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