// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // Common C++. If you copy code from other releases into a copy of GNU // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // /** * @file serial.h * @short Serial I/O services. **/ #ifndef CCXX_SERIAL_H_ #define CCXX_SERIAL_H_ #ifndef CCXX_MISSING_H_ #include #endif #ifndef CCXX_THREAD_H_ #include #endif #ifndef CCXX_EXCEPTION_H_ #include #endif #ifndef WIN32 typedef int HANDLE; #define INVALID_HANDLE_VALUE (-1) #endif #ifdef CCXX_NAMESPACES namespace ost { #endif /** * The Serial class is used as the base for all serial I/O services * under APE. A serial is a system serial port that is used either * for line or packet based data input. Serial ports may also be * "streamable" in a derived form. * * Common C++ serial I/O classes are used to manage serial devices and * implement serial device protocols. From the point of view of Common C++, * serial devices are supported by the underlying Posix specified "termios" * call interface. * * The serial I/O base class is used to hold a descriptor to a serial device * and to provide an exception handling interface for all serial I/O classes. * The base class is also used to specify serial I/O properties such as * communication speed, flow control, data size, and parity. The "Serial" * base class is not itself directly used in application development, * however. * * Common C++ Serial I/O is itself divided into two conceptual modes; frame * oriented and line oriented I/O. Both frame and line oriented I/O makes * use of the ability of the underlying tty driver to buffer data and return * "ready" status from when select either a specified number of bytes or * newline record has been reached by manipulating termios c_cc fields * appropriately. This provides some advantage in that a given thread * servicing a serial port can block and wait rather than have to continually * poll or read each and every byte as soon as it appears at the serial port. * * @author David Sugar * @short base class for all serial I/O services. */ class __EXPORT Serial { public: enum Error { errSuccess = 0, errOpenNoTty, errOpenFailed, errSpeedInvalid, errFlowInvalid, errParityInvalid, errCharsizeInvalid, errStopbitsInvalid, errOptionInvalid, errResourceFailure, errOutput, errInput, errTimeout, errExtended }; typedef enum Error Error; enum Flow { flowNone, flowSoft, flowHard, flowBoth }; typedef enum Flow Flow; enum Parity { parityNone, parityOdd, parityEven }; typedef enum Parity Parity; enum Pending { pendingInput, pendingOutput, pendingError }; typedef enum Pending Pending; private: Error errid; char *errstr; struct { bool thrown: 1; bool linebuf: 1; } flags; void * original; void * current; /** * Used to properly initialize serial object. */ void initSerial(void); protected: HANDLE dev; int bufsize; /** * Opens the serial device. * * @param fname Pathname of device to open */ void open(const char *fname); /** * Closes the serial device. * */ void close(void); /** * Reads from serial device. * * @param Data Point to character buffer to receive data. Buffers MUST * be at least Length + 1 bytes in size. * @param Length Number of bytes to read. */ virtual int aRead(char * Data, const int Length); /** * Writes to serial device. * * @param Data Point to character buffer containing data to write. Buffers MUST * @param Length Number of bytes to write. */ virtual int aWrite(const char * Data, const int Length); /** * This service is used to throw all serial errors which usually * occur during the serial constructor. * * @param error defined serial error id. * @param errstr string or message to optionally pass. */ Error error(Error error, char *errstr = NULL); /** * This service is used to thow application defined serial * errors where the application specific error code is a string. * * @param err string or message to pass. */ inline void error(char *err) {error(errExtended, err);}; /** * This method is used to turn the error handler on or off for * "throwing" execptions by manipulating the thrown flag. * * @param enable true to enable handler. */ inline void setError(bool enable) {flags.thrown = !enable;}; /** * Set packet read mode and "size" of packet read buffer. * This sets VMIN to x. VTIM is normally set to "0" so that * "isPending()" can wait for an entire packet rather than just * the first byte. * * @return actual buffer size set. * @param size of packet read request. * @param btimer optional inter-byte data packet timeout. */ int setPacketInput(int size, unsigned char btimer = 0); /** * Set "line buffering" read mode and specifies the newline * character to be used in seperating line records. isPending * can then be used to wait for an entire line of input. * * @param newline newline character. * @param nl1 EOL2 control character. * @return size of conical input buffer. */ int setLineInput(char newline = 13, char nl1 = 0); /** * Restore serial device to the original settings at time of open. */ void restore(void); /** * Used to flush the input waiting queue. */ void flushInput(void); /** * Used to flush any pending output data. */ void flushOutput(void); /** * Used to wait until all output has been sent. */ void waitOutput(void); /** * Used as the default destructor for ending serial I/O * services. It will restore the port to it's original state. */ void endSerial(void); /** * Used to initialize a newly opened serial file handle. You * should set serial properties and DTR manually before first * use. */ void initConfig(void); /** * This allows later ttystream class to open and close a serial * device. */ Serial() {initSerial();}; /** * A serial object may be constructed from a named file on the * file system. This named device must be "isatty()". * * @param name of file. */ Serial(const char *name); public: /** * The serial base class may be "thrown" as a result on an error, * and the "catcher" may then choose to destory the object. By * assuring the socket base class is a virtual destructor, we * can assure the full object is properly terminated. */ virtual ~Serial(); /** * Serial ports may also be duplecated by the assignment * operator. */ Serial &operator=(const Serial &from); /** * Set serial port speed for both input and output. * * @return 0 on success. * @param speed to select. 0 signifies modem "hang up". */ Error setSpeed(unsigned long speed); /** * Set character size. * * @return 0 on success. * @param bits character size to use (usually 7 or 8). */ Error setCharBits(int bits); /** * Set parity mode. * * @return 0 on success. * @param parity mode. */ Error setParity(Parity parity); /** * Set number of stop bits. * * @return 0 on success. * @param bits stop bits. */ Error setStopBits(int bits); /** * Set flow control. * * @return 0 on success. * @param flow control mode. */ Error setFlowControl(Flow flow); /** * Set the DTR mode off momentarily. * * @param millisec number of milliseconds. */ void toggleDTR(timeout_t millisec); /** * Send the "break" signal. */ void sendBreak(void); /** * Often used by a "catch" to fetch the last error of a thrown * serial. * * @return error numbr of last Error. */ inline Error getErrorNumber(void) {return errid;}; /** * Often used by a "catch" to fetch the user set error string * of a thrown serial. * * @return string for error message. */ inline char *getErrorString(void) {return errstr;}; /** * Get the "buffer" size for buffered operations. This can * be used when setting packet or line read modes to determine * how many bytes to wait for in a given read call. * * @return number of bytes used for buffering. */ inline int getBufferSize(void) {return bufsize;}; /** * Get the status of pending operations. This can be used to * examine if input or output is waiting, or if an error has * occured on the serial device. * * @return true if ready, false if timeout. * @param pend ready check to perform. * @param timeout in milliseconds. */ virtual bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF); }; /** * TTY streams are used to represent serial connections that are fully * "streamable" objects using C++ stream classes and friends. * * The first application relevant serial I/O class is the TTYStream class. * TTYStream offers a linearly buffered "streaming" I/O session with the * serial device. Furthermore, traditional C++ "stream" operators (<< and * >>) may be used with the serial device. A more "true" to ANSI C++ library * format "ttystream" is also available, and this supports an "open" method * in which one can pass initial serial device parameters immediately * following the device name in a single string, as in * "/dev/tty3a:9600,7,e,1", as an example. * * The TTYSession aggragates a TTYStream and a Common C++ Thread which is * assumed to be the execution context that will be used to perform actual * I/O operations. This class is very anagolous to TCPSession. * * * @author David Sugar * @short streamable tty serial I/O class. */ class __EXPORT TTYStream : protected std::streambuf, public Serial, public std::iostream { private: int doallocate(); friend TTYStream& crlf(TTYStream&); friend TTYStream& lfcr(TTYStream&); protected: char *gbuf, *pbuf; timeout_t timeout; /** * This constructor is used to derive "ttystream", a more * C++ style version of the TTYStream class. */ TTYStream(); /** * Used to allocate the buffer space needed for iostream * operations. This is based on MAX_INPUT. */ void allocate(void); /** * Used to terminate the buffer space and clean up the tty * connection. This function is called by the destructor. */ void endStream(void); /** * This streambuf method is used to load the input buffer * through the established tty serial port. * * @return char from get buffer, EOF also possible. */ int underflow(void); /** * This streambuf method is used for doing unbuffered reads * through the establish tty serial port when in interactive mode. * Also this method will handle proper use of buffers if not in * interative mode. * * @return char from tty serial port, EOF also possible. */ int uflow(void); /** * This streambuf method is used to write the output * buffer through the established tty port. * * @param ch char to push through. * @return char pushed through. */ int overflow(int ch); public: /** * Create and open a tty serial port. * * @param filename char name of device to open. * @param to default timeout. */ TTYStream(const char *filename, timeout_t to = 0); /** * End the tty stream and cleanup. */ virtual ~TTYStream(); /** * Set the timeout control. * * @param to timeout to use. */ inline void setTimeout(timeout_t to) {timeout = to;}; /** * Set tty mode to buffered or "interactive". When interactive, * all streamed I/O is directly sent to the serial port * immediately. * * @param flag bool set to true to make interactive. */ void interactive(bool flag); /** * Flushes the stream input and out buffers, writes * pending output. * * @return 0 on success. */ int sync(void); /** * Get the status of pending operations. This can be used to * examine if input or output is waiting, or if an error has * occured on the serial device. If read buffer contains data * then input is ready and if write buffer contains data it is * first flushed then checked. * * @return true if ready, false if timeout. * @param pend ready check to perform. * @param timeout in milliseconds. */ bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF); }; /** * A more natural C++ "ttystream" class for use by non-threaded * applications. This class behaves a lot more like fstream and * similar classes. * * @author David Sugar * @short C++ "fstream" style ttystream class. */ class __EXPORT ttystream : public TTYStream { public: /** * Construct an unopened "ttystream" object. */ ttystream(); /** * Construct and "open" a tty stream object. A filename in * the form "device:options[,options]" may be used to pass * device options as part of the open. * * @param name of file and serial options. */ ttystream(const char *name); /** * Open method for a tty stream. * * @param name filename to open. */ void open(const char *name); /** * Close method for a tty stream. */ void close(void); /** * Test to see if stream is opened. */ inline bool operator!() {return (dev < 0);}; }; /** * * The TTYSession aggragates a TTYStream and a Common C++ Thread which is * assumed to be the execution context that will be used to perform actual * I/O operations. This class is very anagolous to TCPSession. * * @author David Sugar * @short This class is very anagolous to TCPSession. */ class __EXPORT TTYSession : public Thread, public TTYStream { public: /** * Create TTY stream that will be managed by it's own thread. * * @param name of tty device to open. * @param pri execution priority. * @param stack allocation needed on some platforms. */ TTYSession(const char *name, int pri = 0, int stack = 0); virtual ~TTYSession(); }; #ifndef WIN32 // Not support this right now....... // class __EXPORT SerialPort; class __EXPORT SerialService; /** * The serial port is an internal class which is attached to and then * serviced by a specified SerialService thread. Derived versions of * this class offer specific functionality such as serial integration * protocols. * * The TTYPort and TTYService classes are used to form thread-pool serviced * serial I/O protocol sets. These can be used when one has a large number * of serial devices to manage, and a single (or limited number of) thread(s) * can then be used to service the tty port objects present. Each tty port * supports a timer control and several virtual methods that the service * thread can call when events occur. This model provides for "callback" * event management, whereby the service thread performs a "callback" into * the port object when events occur. Specific events supported include the * expiration of a TTYPort timer, pending input data waiting to be read, and * "sighup" connection breaks. * * * @author David Sugar * @short base class for thread pool serviced serial I/O. */ class __EXPORT SerialPort: public Serial, public TimerPort { private: SerialPort *next, *prev; SerialService *service; #ifdef USE_POLL struct pollfd *ufd; #endif bool detect_pending; bool detect_output; bool detect_disconnect; friend class SerialService; protected: /** * Construct a tty serial port for a named serial device. * * @param svc pool thread object. * @param name of tty port. */ SerialPort(SerialService *svc, const char *name); /** * Disconnect the Serial Port from the service pool thread * and shutdown the port. */ virtual ~SerialPort(); /** * Used to indicate if the service thread should monitor pending * data for us. */ void setDetectPending( bool ); /** * Get the current state of the DetectPending flag. */ inline bool getDetectPending( void ) const { return detect_pending; } /** * Used to indicate if output ready monitoring should be performed * by the service thread. */ void setDetectOutput( bool ); /** * Get the current state of the DetectOutput flag. */ inline bool getDetectOutput( void ) const { return detect_output; } /** * Called by the service thread when the objects timer * has expired. */ virtual void expired(void); /** * Called by the service thread when input data is pending * for this tty port. Effected by setPacketInput and by * setLineInput. */ virtual void pending(void); /** * Called by the service thread when an exception has occured * such as a hangup. */ virtual void disconnect(void); /** * Transmit "send" data to the serial port. This is not public * since it's meant to support internal protocols rather than * direct public access to the device. * * @return number of bytes send. * @param buf address of buffer to send. * @param len of bytes to send. */ inline int output(void *buf, int len) {return aWrite((char *)buf, len);}; /** * Perform when output is available for sending data. */ virtual void output(void); /** * Receive "input" for pending data from the serial port. This * is not a public member since it's meant to support internal * protocols rather than direct external access to the device. * * @return number of bytes received. * @param buf address of buffer to input. * @param len of input buffer used. */ inline int input(void *buf, int len) {return aRead((char *)buf, len);}; public: /** * Derived setTimer to notify the service thread pool of changes * in expected timeout. This allows SerialService to * reschedule all timers. * * @param timeout in milliseconds. */ void setTimer(timeout_t timeout = 0); /** * Derived incTimer to notify the service thread pool of a * change in expected timeout. This allows SerialService to * reschedule all timers. */ void incTimer(timeout_t timeout); }; /** * The SerialService is a thead service object that is meant to service * attached serial ports. Multiple pool objects may be created and * multiple serial ports may be attached to the same thread of * of execution. This allows one to balance threads and the serial ports * they service. * * The TTYPort and TTYService classes are used to form thread-pool serviced * serial I/O protocol sets. These can be used when one has a large number * of serial devices to manage, and a single (or limited number of) thread(s) * can then be used to service the tty port objects present. Each tty port * supports a timer control and several virtual methods that the service * thread can call when events occur. This model provides for "callback" * event management, whereby the service thread performs a "callback" into * the port object when events occur. Specific events supported include the * expiration of a TTYPort timer, pending input data waiting to be read, and * "sighup" connection breaks. * * * @author David Sugar * @short Thread pool service for serial ports. */ class __EXPORT SerialService : public Thread, private Mutex { private: fd_set connect; int iosync[2]; int hiwater; int count; SerialPort *first, *last; /** * Attach a new serial port to this service thread. * * @param port of SerialPort derived object to attach. */ void attach(SerialPort *port); /** * Detach a serial port from this service thread. * * @param port of SerialPort derived object to remove. */ void detach(SerialPort *port); /** * The service thread itself. */ void run(void); friend class SerialPort; protected: /** * A virtual handler for processing user defined update * requests (1-254) which have been posted through Update. * * @param flag of update request. */ virtual void onUpdate(unsigned char flag); /** * A virtual handler for event loop calls. This can be * used to extend event loop processing. */ virtual void onEvent(void); /** * A virtual handler for adding support for additional * callback events into SerialPort. * * @param port serial port currently being evaluated. */ virtual void onCallback(SerialPort *port); public: /** * Notify service thread that a port has been added or * removed, or a timer changed, so that a new schedule * can be computed for expiring attached ports. This * can also be used to pass requests to the OnUpdate() * event handler. * * @param flag event for OnUpdate, termination, or reschedule. */ void update(unsigned char flag = 0xff); /** * Create a service thread for attaching serial ports. The * thread begins execution with the first attached port. * * @param pri of this thread to run under. * @param stack stack size. * @param id stack ID. */ SerialService(int pri = 0, size_t stack = 0, const char *id = NULL); /** * Terminate the service thread and update attached objects. */ virtual ~SerialService(); /** * Get current reference count. This can be used when selecting * the lead used service handler from a pool. * * @return count of active ports. */ inline int getCount(void) {return count;}; }; #endif #ifdef COMMON_STD_EXCEPTION class __EXPORT SerException : public IOException { public: SerException(const String &str) : IOException(str) {}; }; #endif #ifdef CCXX_NAMESPACES } #endif #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */