blob: 213afaca48036b5b5226397d375e73769fbef955 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39/**
40 * @file serial.h
41 * @short Serial I/O services.
42 **/
43
44#ifndef CCXX_SERIAL_H_
45#define CCXX_SERIAL_H_
46
47#ifndef CCXX_MISSING_H_
48#include <cc++/missing.h>
49#endif
50
51#ifndef CCXX_THREAD_H_
52#include <cc++/thread.h>
53#endif
54
55#ifndef CCXX_EXCEPTION_H_
56#include <cc++/exception.h>
57#endif
58
59#ifndef WIN32
60typedef int HANDLE;
61#define INVALID_HANDLE_VALUE (-1)
62#endif
63
64#ifdef CCXX_NAMESPACES
65namespace ost {
66#endif
67
68/**
69 * The Serial class is used as the base for all serial I/O services
70 * under APE. A serial is a system serial port that is used either
71 * for line or packet based data input. Serial ports may also be
72 * "streamable" in a derived form.
73 *
74 * Common C++ serial I/O classes are used to manage serial devices and
75 * implement serial device protocols. From the point of view of Common C++,
76 * serial devices are supported by the underlying Posix specified "termios"
77 * call interface.
78 *
79 * The serial I/O base class is used to hold a descriptor to a serial device
80 * and to provide an exception handling interface for all serial I/O classes.
81 * The base class is also used to specify serial I/O properties such as
82 * communication speed, flow control, data size, and parity. The "Serial"
83 * base class is not itself directly used in application development,
84 * however.
85 *
86 * Common C++ Serial I/O is itself divided into two conceptual modes; frame
87 * oriented and line oriented I/O. Both frame and line oriented I/O makes
88 * use of the ability of the underlying tty driver to buffer data and return
89 * "ready" status from when select either a specified number of bytes or
90 * newline record has been reached by manipulating termios c_cc fields
91 * appropriately. This provides some advantage in that a given thread
92 * servicing a serial port can block and wait rather than have to continually
93 * poll or read each and every byte as soon as it appears at the serial port.
94 *
95 * @author David Sugar <dyfet@ostel.com>
96 * @short base class for all serial I/O services.
97 */
98class __EXPORT Serial
99{
100public:
101 enum Error {
102 errSuccess = 0,
103 errOpenNoTty,
104 errOpenFailed,
105 errSpeedInvalid,
106 errFlowInvalid,
107 errParityInvalid,
108 errCharsizeInvalid,
109 errStopbitsInvalid,
110 errOptionInvalid,
111 errResourceFailure,
112 errOutput,
113 errInput,
114 errTimeout,
115 errExtended
116 };
117 typedef enum Error Error;
118
119 enum Flow {
120 flowNone,
121 flowSoft,
122 flowHard,
123 flowBoth
124 };
125 typedef enum Flow Flow;
126
127 enum Parity {
128 parityNone,
129 parityOdd,
130 parityEven
131 };
132 typedef enum Parity Parity;
133
134 enum Pending {
135 pendingInput,
136 pendingOutput,
137 pendingError
138 };
139 typedef enum Pending Pending;
140
141private:
142 Error errid;
143 char *errstr;
144
145 struct {
146 bool thrown: 1;
147 bool linebuf: 1;
148 } flags;
149
150 void * original;
151 void * current;
152
153 /**
154 * Used to properly initialize serial object.
155 */
156 void initSerial(void);
157
158protected:
159
160 HANDLE dev;
161
162 int bufsize;
163
164 /**
165 * Opens the serial device.
166 *
167 * @param fname Pathname of device to open
168 */
169 void open(const char *fname);
170
171 /**
172 * Closes the serial device.
173 *
174 */
175 void close(void);
176
177 /**
178 * Reads from serial device.
179 *
180 * @param Data Point to character buffer to receive data. Buffers MUST
181 * be at least Length + 1 bytes in size.
182 * @param Length Number of bytes to read.
183 */
184 virtual int aRead(char * Data, const int Length);
185
186 /**
187 * Writes to serial device.
188 *
189 * @param Data Point to character buffer containing data to write. Buffers MUST
190 * @param Length Number of bytes to write.
191 */
192 virtual int aWrite(const char * Data, const int Length);
193
194 /**
195 * This service is used to throw all serial errors which usually
196 * occur during the serial constructor.
197 *
198 * @param error defined serial error id.
199 * @param errstr string or message to optionally pass.
200 */
201 Error error(Error error, char *errstr = NULL);
202
203 /**
204 * This service is used to thow application defined serial
205 * errors where the application specific error code is a string.
206 *
207 * @param err string or message to pass.
208 */
209 inline void error(char *err)
210 {error(errExtended, err);};
211
212
213 /**
214 * This method is used to turn the error handler on or off for
215 * "throwing" execptions by manipulating the thrown flag.
216 *
217 * @param enable true to enable handler.
218 */
219 inline void setError(bool enable)
220 {flags.thrown = !enable;};
221
222 /**
223 * Set packet read mode and "size" of packet read buffer.
224 * This sets VMIN to x. VTIM is normally set to "0" so that
225 * "isPending()" can wait for an entire packet rather than just
226 * the first byte.
227 *
228 * @return actual buffer size set.
229 * @param size of packet read request.
230 * @param btimer optional inter-byte data packet timeout.
231 */
232 int setPacketInput(int size, unsigned char btimer = 0);
233
234 /**
235 * Set "line buffering" read mode and specifies the newline
236 * character to be used in seperating line records. isPending
237 * can then be used to wait for an entire line of input.
238 *
239 * @param newline newline character.
240 * @param nl1 EOL2 control character.
241 * @return size of conical input buffer.
242 */
243 int setLineInput(char newline = 13, char nl1 = 0);
244
245 /**
246 * Restore serial device to the original settings at time of open.
247 */
248 void restore(void);
249
250 /**
251 * Used to flush the input waiting queue.
252 */
253 void flushInput(void);
254
255 /**
256 * Used to flush any pending output data.
257 */
258 void flushOutput(void);
259
260 /**
261 * Used to wait until all output has been sent.
262 */
263 void waitOutput(void);
264
265 /**
266 * Used as the default destructor for ending serial I/O
267 * services. It will restore the port to it's original state.
268 */
269 void endSerial(void);
270
271 /**
272 * Used to initialize a newly opened serial file handle. You
273 * should set serial properties and DTR manually before first
274 * use.
275 */
276 void initConfig(void);
277
278 /**
279 * This allows later ttystream class to open and close a serial
280 * device.
281 */
282 Serial()
283 {initSerial();};
284
285 /**
286 * A serial object may be constructed from a named file on the
287 * file system. This named device must be "isatty()".
288 *
289 * @param name of file.
290 */
291 Serial(const char *name);
292
293
294public:
295
296 /**
297 * The serial base class may be "thrown" as a result on an error,
298 * and the "catcher" may then choose to destory the object. By
299 * assuring the socket base class is a virtual destructor, we
300 * can assure the full object is properly terminated.
301 */
302 virtual ~Serial();
303
304 /**
305 * Serial ports may also be duplecated by the assignment
306 * operator.
307 */
308 Serial &operator=(const Serial &from);
309
310 /**
311 * Set serial port speed for both input and output.
312 *
313 * @return 0 on success.
314 * @param speed to select. 0 signifies modem "hang up".
315 */
316 Error setSpeed(unsigned long speed);
317
318 /**
319 * Set character size.
320 *
321 * @return 0 on success.
322 * @param bits character size to use (usually 7 or 8).
323 */
324 Error setCharBits(int bits);
325
326 /**
327 * Set parity mode.
328 *
329 * @return 0 on success.
330 * @param parity mode.
331 */
332 Error setParity(Parity parity);
333
334 /**
335 * Set number of stop bits.
336 *
337 * @return 0 on success.
338 * @param bits stop bits.
339 */
340 Error setStopBits(int bits);
341
342 /**
343 * Set flow control.
344 *
345 * @return 0 on success.
346 * @param flow control mode.
347 */
348 Error setFlowControl(Flow flow);
349
350 /**
351 * Set the DTR mode off momentarily.
352 *
353 * @param millisec number of milliseconds.
354 */
355 void toggleDTR(timeout_t millisec);
356
357 /**
358 * Send the "break" signal.
359 */
360 void sendBreak(void);
361
362 /**
363 * Often used by a "catch" to fetch the last error of a thrown
364 * serial.
365 *
366 * @return error numbr of last Error.
367 */
368 inline Error getErrorNumber(void)
369 {return errid;};
370
371 /**
372 * Often used by a "catch" to fetch the user set error string
373 * of a thrown serial.
374 *
375 * @return string for error message.
376 */
377 inline char *getErrorString(void)
378 {return errstr;};
379
380 /**
381 * Get the "buffer" size for buffered operations. This can
382 * be used when setting packet or line read modes to determine
383 * how many bytes to wait for in a given read call.
384 *
385 * @return number of bytes used for buffering.
386 */
387 inline int getBufferSize(void)
388 {return bufsize;};
389
390 /**
391 * Get the status of pending operations. This can be used to
392 * examine if input or output is waiting, or if an error has
393 * occured on the serial device.
394 *
395 * @return true if ready, false if timeout.
396 * @param pend ready check to perform.
397 * @param timeout in milliseconds.
398 */
399 virtual bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF);
400};
401
402/**
403 * TTY streams are used to represent serial connections that are fully
404 * "streamable" objects using C++ stream classes and friends.
405 *
406 * The first application relevant serial I/O class is the TTYStream class.
407 * TTYStream offers a linearly buffered "streaming" I/O session with the
408 * serial device. Furthermore, traditional C++ "stream" operators (<< and
409 * >>) may be used with the serial device. A more "true" to ANSI C++ library
410 * format "ttystream" is also available, and this supports an "open" method
411 * in which one can pass initial serial device parameters immediately
412 * following the device name in a single string, as in
413 * "/dev/tty3a:9600,7,e,1", as an example.
414 *
415 * The TTYSession aggragates a TTYStream and a Common C++ Thread which is
416 * assumed to be the execution context that will be used to perform actual
417 * I/O operations. This class is very anagolous to TCPSession.
418 *
419 *
420 * @author David Sugar <dyfet@ostel.com>
421 * @short streamable tty serial I/O class.
422 */
423class __EXPORT TTYStream : protected std::streambuf, public Serial, public std::iostream
424{
425private:
426 int doallocate();
427
428 friend TTYStream& crlf(TTYStream&);
429 friend TTYStream& lfcr(TTYStream&);
430
431protected:
432 char *gbuf, *pbuf;
433 timeout_t timeout;
434
435 /**
436 * This constructor is used to derive "ttystream", a more
437 * C++ style version of the TTYStream class.
438 */
439 TTYStream();
440
441 /**
442 * Used to allocate the buffer space needed for iostream
443 * operations. This is based on MAX_INPUT.
444 */
445 void allocate(void);
446
447 /**
448 * Used to terminate the buffer space and clean up the tty
449 * connection. This function is called by the destructor.
450 */
451 void endStream(void);
452
453 /**
454 * This streambuf method is used to load the input buffer
455 * through the established tty serial port.
456 *
457 * @return char from get buffer, EOF also possible.
458 */
459 int underflow(void);
460
461 /**
462 * This streambuf method is used for doing unbuffered reads
463 * through the establish tty serial port when in interactive mode.
464 * Also this method will handle proper use of buffers if not in
465 * interative mode.
466 *
467 * @return char from tty serial port, EOF also possible.
468 */
469 int uflow(void);
470
471 /**
472 * This streambuf method is used to write the output
473 * buffer through the established tty port.
474 *
475 * @param ch char to push through.
476 * @return char pushed through.
477 */
478 int overflow(int ch);
479
480public:
481 /**
482 * Create and open a tty serial port.
483 *
484 * @param filename char name of device to open.
485 * @param to default timeout.
486 */
487 TTYStream(const char *filename, timeout_t to = 0);
488
489 /**
490 * End the tty stream and cleanup.
491 */
492 virtual ~TTYStream();
493
494 /**
495 * Set the timeout control.
496 *
497 * @param to timeout to use.
498 */
499 inline void setTimeout(timeout_t to)
500 {timeout = to;};
501
502 /**
503 * Set tty mode to buffered or "interactive". When interactive,
504 * all streamed I/O is directly sent to the serial port
505 * immediately.
506 *
507 * @param flag bool set to true to make interactive.
508 */
509 void interactive(bool flag);
510
511 /**
512 * Flushes the stream input and out buffers, writes
513 * pending output.
514 *
515 * @return 0 on success.
516 */
517 int sync(void);
518
519 /**
520 * Get the status of pending operations. This can be used to
521 * examine if input or output is waiting, or if an error has
522 * occured on the serial device. If read buffer contains data
523 * then input is ready and if write buffer contains data it is
524 * first flushed then checked.
525 *
526 * @return true if ready, false if timeout.
527 * @param pend ready check to perform.
528 * @param timeout in milliseconds.
529 */
530 bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF);
531};
532
533/**
534 * A more natural C++ "ttystream" class for use by non-threaded
535 * applications. This class behaves a lot more like fstream and
536 * similar classes.
537 *
538 * @author David Sugar <dyfet@ostel.com>
539 * @short C++ "fstream" style ttystream class.
540 */
541
542class __EXPORT ttystream : public TTYStream
543{
544public:
545 /**
546 * Construct an unopened "ttystream" object.
547 */
548 ttystream();
549
550 /**
551 * Construct and "open" a tty stream object. A filename in
552 * the form "device:options[,options]" may be used to pass
553 * device options as part of the open.
554 *
555 * @param name of file and serial options.
556 */
557 ttystream(const char *name);
558
559 /**
560 * Open method for a tty stream.
561 *
562 * @param name filename to open.
563 */
564 void open(const char *name);
565
566 /**
567 * Close method for a tty stream.
568 */
569 void close(void);
570
571 /**
572 * Test to see if stream is opened.
573 */
574 inline bool operator!()
575 {return (dev < 0);};
576};
577
578/**
579 *
580 * The TTYSession aggragates a TTYStream and a Common C++ Thread which is
581 * assumed to be the execution context that will be used to perform actual
582 * I/O operations. This class is very anagolous to TCPSession.
583 *
584 * @author David Sugar <dyfet@ostel.com>
585 * @short This class is very anagolous to TCPSession.
586 */
587
588class __EXPORT TTYSession : public Thread, public TTYStream
589{
590public:
591 /**
592 * Create TTY stream that will be managed by it's own thread.
593 *
594 * @param name of tty device to open.
595 * @param pri execution priority.
596 * @param stack allocation needed on some platforms.
597 */
598 TTYSession(const char *name, int pri = 0, int stack = 0);
599
600 virtual ~TTYSession();
601};
602
603#ifndef WIN32
604
605// Not support this right now.......
606//
607class __EXPORT SerialPort;
608class __EXPORT SerialService;
609
610/**
611 * The serial port is an internal class which is attached to and then
612 * serviced by a specified SerialService thread. Derived versions of
613 * this class offer specific functionality such as serial integration
614 * protocols.
615 *
616 * The TTYPort and TTYService classes are used to form thread-pool serviced
617 * serial I/O protocol sets. These can be used when one has a large number
618 * of serial devices to manage, and a single (or limited number of) thread(s)
619 * can then be used to service the tty port objects present. Each tty port
620 * supports a timer control and several virtual methods that the service
621 * thread can call when events occur. This model provides for "callback"
622 * event management, whereby the service thread performs a "callback" into
623 * the port object when events occur. Specific events supported include the
624 * expiration of a TTYPort timer, pending input data waiting to be read, and
625 * "sighup" connection breaks.
626 *
627 *
628 * @author David Sugar <dyfet@ostel.com>
629 * @short base class for thread pool serviced serial I/O.
630 */
631class __EXPORT SerialPort: public Serial, public TimerPort
632{
633private:
634 SerialPort *next, *prev;
635 SerialService *service;
636#ifdef USE_POLL
637 struct pollfd *ufd;
638#endif
639 bool detect_pending;
640 bool detect_output;
641 bool detect_disconnect;
642
643 friend class SerialService;
644
645protected:
646 /**
647 * Construct a tty serial port for a named serial device.
648 *
649 * @param svc pool thread object.
650 * @param name of tty port.
651 */
652 SerialPort(SerialService *svc, const char *name);
653
654 /**
655 * Disconnect the Serial Port from the service pool thread
656 * and shutdown the port.
657 */
658 virtual ~SerialPort();
659
660 /**
661 * Used to indicate if the service thread should monitor pending
662 * data for us.
663 */
664 void setDetectPending( bool );
665
666 /**
667 * Get the current state of the DetectPending flag.
668 */
669 inline bool getDetectPending( void ) const
670 { return detect_pending; }
671
672 /**
673 * Used to indicate if output ready monitoring should be performed
674 * by the service thread.
675 */
676 void setDetectOutput( bool );
677
678 /**
679 * Get the current state of the DetectOutput flag.
680 */
681 inline bool getDetectOutput( void ) const
682 { return detect_output; }
683
684 /**
685 * Called by the service thread when the objects timer
686 * has expired.
687 */
688 virtual void expired(void);
689
690 /**
691 * Called by the service thread when input data is pending
692 * for this tty port. Effected by setPacketInput and by
693 * setLineInput.
694 */
695 virtual void pending(void);
696
697 /**
698 * Called by the service thread when an exception has occured
699 * such as a hangup.
700 */
701 virtual void disconnect(void);
702
703 /**
704 * Transmit "send" data to the serial port. This is not public
705 * since it's meant to support internal protocols rather than
706 * direct public access to the device.
707 *
708 * @return number of bytes send.
709 * @param buf address of buffer to send.
710 * @param len of bytes to send.
711 */
712 inline int output(void *buf, int len)
713 {return aWrite((char *)buf, len);};
714
715 /**
716 * Perform when output is available for sending data.
717 */
718 virtual void output(void);
719
720 /**
721 * Receive "input" for pending data from the serial port. This
722 * is not a public member since it's meant to support internal
723 * protocols rather than direct external access to the device.
724 *
725 * @return number of bytes received.
726 * @param buf address of buffer to input.
727 * @param len of input buffer used.
728 */
729 inline int input(void *buf, int len)
730 {return aRead((char *)buf, len);};
731public:
732 /**
733 * Derived setTimer to notify the service thread pool of changes
734 * in expected timeout. This allows SerialService to
735 * reschedule all timers.
736 *
737 * @param timeout in milliseconds.
738 */
739 void setTimer(timeout_t timeout = 0);
740
741 /**
742 * Derived incTimer to notify the service thread pool of a
743 * change in expected timeout. This allows SerialService to
744 * reschedule all timers.
745 */
746 void incTimer(timeout_t timeout);
747};
748
749/**
750 * The SerialService is a thead service object that is meant to service
751 * attached serial ports. Multiple pool objects may be created and
752 * multiple serial ports may be attached to the same thread of
753 * of execution. This allows one to balance threads and the serial ports
754 * they service.
755 *
756 * The TTYPort and TTYService classes are used to form thread-pool serviced
757 * serial I/O protocol sets. These can be used when one has a large number
758 * of serial devices to manage, and a single (or limited number of) thread(s)
759 * can then be used to service the tty port objects present. Each tty port
760 * supports a timer control and several virtual methods that the service
761 * thread can call when events occur. This model provides for "callback"
762 * event management, whereby the service thread performs a "callback" into
763 * the port object when events occur. Specific events supported include the
764 * expiration of a TTYPort timer, pending input data waiting to be read, and
765 * "sighup" connection breaks.
766 *
767 *
768 * @author David Sugar <dyfet@ostel.com>
769 * @short Thread pool service for serial ports.
770 */
771class __EXPORT SerialService : public Thread, private Mutex
772{
773private:
774 fd_set connect;
775 int iosync[2];
776 int hiwater;
777 int count;
778 SerialPort *first, *last;
779
780 /**
781 * Attach a new serial port to this service thread.
782 *
783 * @param port of SerialPort derived object to attach.
784 */
785 void attach(SerialPort *port);
786
787 /**
788 * Detach a serial port from this service thread.
789 *
790 * @param port of SerialPort derived object to remove.
791 */
792 void detach(SerialPort *port);
793
794 /**
795 * The service thread itself.
796 */
797 void run(void);
798
799 friend class SerialPort;
800
801protected:
802 /**
803 * A virtual handler for processing user defined update
804 * requests (1-254) which have been posted through Update.
805 *
806 * @param flag of update request.
807 */
808 virtual void onUpdate(unsigned char flag);
809
810 /**
811 * A virtual handler for event loop calls. This can be
812 * used to extend event loop processing.
813 */
814 virtual void onEvent(void);
815
816 /**
817 * A virtual handler for adding support for additional
818 * callback events into SerialPort.
819 *
820 * @param port serial port currently being evaluated.
821 */
822 virtual void onCallback(SerialPort *port);
823
824public:
825 /**
826 * Notify service thread that a port has been added or
827 * removed, or a timer changed, so that a new schedule
828 * can be computed for expiring attached ports. This
829 * can also be used to pass requests to the OnUpdate()
830 * event handler.
831 *
832 * @param flag event for OnUpdate, termination, or reschedule.
833 */
834 void update(unsigned char flag = 0xff);
835
836 /**
837 * Create a service thread for attaching serial ports. The
838 * thread begins execution with the first attached port.
839 *
840 * @param pri of this thread to run under.
841 * @param stack stack size.
842 * @param id stack ID.
843 */
844 SerialService(int pri = 0, size_t stack = 0, const char *id = NULL);
845
846 /**
847 * Terminate the service thread and update attached objects.
848 */
849 virtual ~SerialService();
850
851 /**
852 * Get current reference count. This can be used when selecting
853 * the lead used service handler from a pool.
854 *
855 * @return count of active ports.
856 */
857 inline int getCount(void)
858 {return count;};
859};
860
861#endif
862
863
864
865#ifdef COMMON_STD_EXCEPTION
866class __EXPORT SerException : public IOException
867{
868public:
869 SerException(const String &str) : IOException(str) {};
870};
871#endif
872
873#ifdef CCXX_NAMESPACES
874}
875#endif
876
877#endif
878/** EMACS **
879 * Local variables:
880 * mode: c++
881 * c-basic-offset: 4
882 * End:
883 */