From 8022c1b1ea2d72ec6dd2fd44adbec3b3d833d4f4 Mon Sep 17 00:00:00 2001 From: William Woodall Date: Wed, 2 May 2012 00:45:23 -0500 Subject: [PATCH] Updating the API to fix some inconsistencies --- doc/Doxyfile | 2 +- include/serial/impl/unix.h | 42 +-- include/serial/serial.h | 386 +++++++++++++++-------- serial.sublime-project | 18 ++ serial.sublime-workspace | 631 +++++++++++++++++++++++++++++++++++++ src/impl/unix.cc | 364 +++++++++++---------- src/serial.cc | 13 +- 7 files changed, 1119 insertions(+), 337 deletions(-) create mode 100644 serial.sublime-project create mode 100644 serial.sublime-workspace diff --git a/doc/Doxyfile b/doc/Doxyfile index f64a659..6b4472f 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -37,7 +37,7 @@ PROJECT_NUMBER = 1.0 # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = Cross-platform serial port library for C++ +PROJECT_BRIEF = "Cross-platform serial port library for C++" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not diff --git a/include/serial/impl/unix.h b/include/serial/impl/unix.h index 98f0fec..2e134df 100644 --- a/include/serial/impl/unix.h +++ b/include/serial/impl/unix.h @@ -10,7 +10,7 @@ * * Copyright (c) 2011 William Woodall, John Harrison * - * Permission is hereby granted, free of charge, to any person obtaining a + * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, @@ -24,8 +24,8 @@ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * \section DESCRIPTION @@ -54,7 +54,6 @@ class serial::Serial::SerialImpl { public: SerialImpl (const string &port, unsigned long baudrate, - long timeout, bytesize_t bytesize, parity_t parity, stopbits_t stopbits, @@ -75,7 +74,7 @@ public: available (); size_t - read (unsigned char* buf, size_t size = 1); + read (unsigned char *buf, size_t size = 1); size_t write (const string &data); @@ -90,28 +89,31 @@ public: flushOutput (); void - sendBreak(int duration); + sendBreak (int duration); void - setBreak(bool level); + setBreak (bool level); void - setRTS(bool level); + setRTS (bool level); void - setDTR(bool level); + setDTR (bool level); bool - getCTS(); + waitForChange (); bool - getDSR(); + getCTS (); bool - getRI(); + getDSR (); bool - getCD(); + getRI (); + + bool + getCD (); void setPort (const string &port); @@ -120,9 +122,9 @@ public: getPort () const; void - setTimeout (long timeout); + setTimeout (timeout_t &timeout); - long + timeout_t getTimeout () const; void @@ -156,16 +158,16 @@ public: getFlowcontrol () const; void - readLock(); + readLock (); void - readUnlock(); + readUnlock (); void - writeLock(); + writeLock (); void - writeUnlock(); + writeUnlock (); protected: void reconfigurePort (); @@ -178,7 +180,7 @@ private: bool xonxoff_; bool rtscts_; - long timeout_; // Timeout for read operations + timeout_t timeout_; // Timeout for read operations unsigned long baudrate_; // Baudrate parity_t parity_; // Parity diff --git a/include/serial/serial.h b/include/serial/serial.h index c1a9269..ad29bab 100644 --- a/include/serial/serial.h +++ b/include/serial/serial.h @@ -43,7 +43,8 @@ #include #include -#define THROW(exceptionClass, message) throw exceptionClass(__FILE__, __LINE__, (message) ) +#define THROW(exceptionClass, message) throw exceptionClass(__FILE__, \ +__LINE__, (message) ) namespace serial { @@ -83,27 +84,50 @@ typedef enum { flowcontrol_software } flowcontrol_t; +/*! + * Structure for setting the timeout of the serial port, times are + * in milliseconds. + */ +struct timeout_t { + timeout_t (long inter_byte_timeout_=0, long read_timeout_constant_=0, + long read_timeout_multiplier_=0, long write_timeout_constant_=0, + long write_timeout_multiplier_=0) + : inter_byte_timeout(inter_byte_timeout_), + read_timeout_constant(read_timeout_constant_), + read_timeout_multiplier(read_timeout_multiplier_), + write_timeout_constant(write_timeout_constant_), + write_timeout_multiplier(write_timeout_multiplier_) + {} + /*! Number of milliseconds between bytes received to timeout on. */ + long inter_byte_timeout; + /*! A constant number of milliseconds to wait after calling read. */ + long read_timeout_constant; + /*! A multiplier against the number of requested bytes to wait after + * calling read. + */ + long read_timeout_multiplier; + /*! A constant number of milliseconds to wait after calling write. */ + long write_timeout_constant; + /*! A multiplier against the number of requested bytes to wait after + * calling write. + */ + long write_timeout_multiplier; +}; + /*! * Class that provides a portable serial port interface. */ class Serial { public: /*! - * Constructor, creates a SerialPortBoost object and opens the port. + * Creates a Serial object and opens the port if a port is specified, + * otherwise it remains closed until serial::Serial::open is called. * * \param port A std::string containing the address of the serial port, * which would be something like 'COM1' on Windows and '/dev/ttyS0' * on Linux. * - * \param baudrate An integer that represents the buadrate - * - * \param timeout A long that represents the time (in milliseconds) until a - * timeout on reads occur. Setting this to zero (0) will cause reading to - * be non-blocking, i.e. the available data will be returned immediately, - * but it will not block to wait for more. Setting this to a number less - * than zero (-1) will result in infinite blocking behaviour, i.e. the - * serial port will block until either size bytes have been read or an - * exception has occured. + * \param baudrate An integer that represents the baudrate * * \param bytesize Size of each byte in the serial transmission of data, * default is eightbits, possible values are: fivebits, sixbits, sevenbits, @@ -119,14 +143,10 @@ public: * flowcontrol_none, possible values are: flowcontrol_none, * flowcontrol_software, flowcontrol_hardware * - * \param buffer_size The maximum size of the internal buffer, defaults - * to 256 bytes (2^8). - * * \throw PortNotOpenedException */ Serial (const std::string &port = "", unsigned long baudrate = 9600, - long timeout = 0, bytesize_t bytesize = eightbits, parity_t parity = parity_none, stopbits_t stopbits = stopbits_one, @@ -136,8 +156,8 @@ public: virtual ~Serial (); /*! - * Opens the serial port as long as the portname is set and the port isn't - * alreay open. + * Opens the serial port as long as the port is set and the port isn't + * already open. * * If the port is provided to the constructor then an explicit call to open * is not needed. @@ -164,28 +184,82 @@ public: /*! Return the number of characters in the buffer. */ size_t - available(); + available (); - /*! Read a given amount of bytes from the serial port. - * - * If a timeout is set it may return less characters than requested. With - * no timeout it will block until the requested number of bytes have been - * read or until an exception occurs. + /*! Read a given amount of bytes from the serial port into a given buffer. * + * The read function will return in one of three cases: + * * The number of requested bytes was read. + * * In this case the number of bytes requested will match the size_t + * returned by read. + * * A timeout occurred, in this case the number of bytes read will not + * match the amount requested, but no exception will be thrown. One of + * two possible timeouts occurred: + * * The inter byte timeout expired, this means that number of + * milliseconds elapsed between receiving bytes from the serial port + * exceeded the inter byte timeout. + * * The total timeout expired, which is calculated by multiplying the + * read timeout multiplier by the number of requested bytes and then + * added to the read timeout constant. If that total number of + * milliseconds elapses after the initial call to read a timeout will + * occur. + * * An exception occurred, in this case an actual exception will be thrown. + * + * \param buffer An unsigned char array of at least the requested size. * \param size A size_t defining how many bytes to be read. * - * \return A std::string containing the data read. + * \return A size_t representing the number of bytes read as a result of the + * call to read. */ size_t read (unsigned char *buffer, size_t size); + + /*! Read a given amount of bytes from the serial port into a give buffer. + * + * \param buffer A reference to a std::vector of unsigned char. + * \param size A size_t defining how many bytes to be read. + * + * \return A size_t representing the number of bytes read as a result of the + * call to read. + */ size_t read (std::vector &buffer, size_t size = 1); + + /*! Read a given amount of bytes from the serial port into a give buffer. + * + * \param buffer A reference to a std::string. + * \param size A size_t defining how many bytes to be read. + * + * \return A size_t representing the number of bytes read as a result of the + * call to read. + */ size_t read (std::string &buffer, size_t size = 1); + + /*! Read a given amount of bytes from the serial port and return a string + * containing the data. + * + * \param size A size_t defining how many bytes to be read. + * + * \return A std::string containing the data read from the port. + */ std::string read (size_t size = 1); - /*! Reads in a line or until a given delimiter has been processed + /*! Reads in a line or until a given delimiter has been processed. + * + * Reads from the serial port until a single line has been read. + * + * \param buffer A std::string reference used to store the data. + * \param size A maximum length of a line, defaults to 65536 (2^16) + * \param eol A string to match against for the EOL. + * + * \return A size_t representing the number of bytes read. + */ + size_t + readline (std::string &buffer, size_t size = 65536, std::string eol = "\n"); + + /*! Reads in a line or until a given delimiter has been processed. * * Reads from the serial port until a single line has been read. * @@ -194,15 +268,10 @@ public: * * \return A std::string containing the line. */ - size_t - readline (std::string &buffer, - size_t size = 65536, - std::string eol = "\n"); std::string - readline (size_t size = 65536, - std::string eol = "\n"); + readline (size_t size = 65536, std::string eol = "\n"); - /*! Reads in multiple lines until the serail port times out. + /*! Reads in multiple lines until the serial port times out. * * This requires a timeout > 0 before it can be run. It will read until a * timeout occurs and return a list of strings. @@ -218,160 +287,207 @@ public: /*! Write a string to the serial port. * - * \param data A const reference containg the data to be written + * \param data A const reference containing the data to be written * to the serial port. * + * \param size A size_t that indicates how many bytes should be written from + * the given data buffer. + * * \return A size_t representing the number of bytes actually written to * the serial port. */ size_t write (const unsigned char *data, size_t size); + + /*! Write a string to the serial port. + * + * \param data A const reference containing the data to be written + * to the serial port. + * + * \return A size_t representing the number of bytes actually written to + * the serial port. + */ size_t write (const std::vector &data); + + /*! Write a string to the serial port. + * + * \param data A const reference containing the data to be written + * to the serial port. + * + * \return A size_t representing the number of bytes actually written to + * the serial port. + */ size_t write (const std::string &data); /*! Sets the serial port identifier. - * - * \param port A const std::string reference containing the address of the - * serial port, which would be something like 'COM1' on Windows and - * '/dev/ttyS0' on Linux. - * - * \throw InvalidConfigurationException - */ + * + * \param port A const std::string reference containing the address of the + * serial port, which would be something like 'COM1' on Windows and + * '/dev/ttyS0' on Linux. + * + * \throw InvalidConfigurationException + */ void setPort (const std::string &port); /*! Gets the serial port identifier. - * - * \see Serial::setPort - * - * \throw InvalidConfigurationException - */ + * + * \see Serial::setPort + * + * \throw InvalidConfigurationException + */ std::string getPort () const; - /*! Sets the timeout for reads in milliseconds. - * - * \param timeout A long that represents the time (in milliseconds) until a - * timeout on reads occur. Setting this to zero (0) will cause reading to be - * non-blocking, i.e. the available data will be returned immediately, but it - * will not block to wait for more. Setting this to a number less than - * zero (-1) will result in infinite blocking behaviour, i.e. the serial port - * will block until either size bytes have been read or an exception has - * occured. - */ + /*! Sets the timeout for reads and writes using the timeout_t struct. + * + * There are two basic conditions for timeout described here, the inter byte + * timeout is the maximum amount of time in milliseconds allowed between + * receiving bytes from the serial port. The second condition is where the + * total timeout expires during a read or write. The total timeout can be + * calculated as the multiplier times the number of requested bytes plus the + * constant. In this way a single constant time timeout can be specified + * with zero for the inter byte timeout and zero for the multiplier. + * Alternatively, you could have only an inter byte timeout and zero for + * both the constant and multiplier to prevent a total time timeout from + * occurring.You can use the multiplier to increase the total time timeout + * based on the number of bytes requested. The user can combine any of + * these timeout metrics in order to achieve the desired trade-off between + * efficiency and responsiveness. + * + * \param timeout A timeout_t struct containing the inter byte timeout, and + * the read and write timeout constants and multipliers. + * + * \see serial::timeout_t + */ void - setTimeout (long timeout); + setTimeout (timeout_t &timeout); + + /*! Sets the timeout for reads and writes. */ + void + setTimeout (long inter_byte_timeout, long read_timeout_constant, + long read_timeout_multiplier, long write_timeout_constant, + long write_timeout_multiplier) + { + timeout_t timeout(inter_byte_timeout, read_timeout_constant, + read_timeout_multiplier, write_timeout_constant, + write_timeout_multiplier); + return setTimeout(timeout); + } /*! Gets the timeout for reads in seconds. - * - * \see Serial::setTimeout - */ - long + * + * \return A timeout_t struct containing the inter_byte_timeout, and read + * and write timeout constants and multipliers. + * + * \see Serial::setTimeout + */ + timeout_t getTimeout () const; /*! Sets the baudrate for the serial port. - * - * Possible baudrates depends on the system but some safe baudrates include: - * 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000, - * 57600, 115200 - * Some other baudrates that are supported by some comports: - * 128000, 153600, 230400, 256000, 460800, 921600 - * - * \param baudrate An integer that sets the baud rate for the serial port. - * - * \throw InvalidConfigurationException - */ + * + * Possible baudrates depends on the system but some safe baudrates include: + * 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000, + * 57600, 115200 + * Some other baudrates that are supported by some comports: + * 128000, 153600, 230400, 256000, 460800, 921600 + * + * \param baudrate An integer that sets the baud rate for the serial port. + * + * \throw InvalidConfigurationException + */ void setBaudrate (unsigned long baudrate); /*! Gets the baudrate for the serial port. - * - * \return An integer that sets the baud rate for the serial port. - * - * \see Serial::setBaudrate - * - * \throw InvalidConfigurationException - */ + * + * \return An integer that sets the baud rate for the serial port. + * + * \see Serial::setBaudrate + * + * \throw InvalidConfigurationException + */ unsigned long getBaudrate () const; /*! Sets the bytesize for the serial port. - * - * \param bytesize Size of each byte in the serial transmission of data, - * default is eightbits, possible values are: fivebits, sixbits, sevenbits, - * eightbits - * - * \throw InvalidConfigurationException - */ + * + * \param bytesize Size of each byte in the serial transmission of data, + * default is eightbits, possible values are: fivebits, sixbits, sevenbits, + * eightbits + * + * \throw InvalidConfigurationException + */ void setBytesize (bytesize_t bytesize); /*! Gets the bytesize for the serial port. - * - * \see Serial::setBytesize - * - * \throw InvalidConfigurationException - */ + * + * \see Serial::setBytesize + * + * \throw InvalidConfigurationException + */ bytesize_t getBytesize () const; /*! Sets the parity for the serial port. - * - * \param parity Method of parity, default is parity_none, possible values - * are: parity_none, parity_odd, parity_even - * - * \throw InvalidConfigurationException - */ + * + * \param parity Method of parity, default is parity_none, possible values + * are: parity_none, parity_odd, parity_even + * + * \throw InvalidConfigurationException + */ void setParity (parity_t parity); /*! Gets the parity for the serial port. - * - * \see Serial::setParity - * - * \throw InvalidConfigurationException - */ + * + * \see Serial::setParity + * + * \throw InvalidConfigurationException + */ parity_t getParity () const; /*! Sets the stopbits for the serial port. - * - * \param stopbits Number of stop bits used, default is stopbits_one, - * possible values are: stopbits_one, stopbits_one_point_five, stopbits_two - * - * \throw InvalidConfigurationException - */ + * + * \param stopbits Number of stop bits used, default is stopbits_one, + * possible values are: stopbits_one, stopbits_one_point_five, stopbits_two + * + * \throw InvalidConfigurationException + */ void setStopbits (stopbits_t stopbits); /*! Gets the stopbits for the serial port. - * - * \see Serial::setStopbits - * - * \throw InvalidConfigurationException - */ + * + * \see Serial::setStopbits + * + * \throw InvalidConfigurationException + */ stopbits_t getStopbits () const; /*! Sets the flow control for the serial port. - * - * \param flowcontrol Type of flowcontrol used, default is flowcontrol_none, - * possible values are: flowcontrol_none, flowcontrol_software, - * flowcontrol_hardware - * - * \throw InvalidConfigurationException - */ + * + * \param flowcontrol Type of flowcontrol used, default is flowcontrol_none, + * possible values are: flowcontrol_none, flowcontrol_software, + * flowcontrol_hardware + * + * \throw InvalidConfigurationException + */ void setFlowcontrol (flowcontrol_t flowcontrol); /*! Gets the flow control for the serial port. - * - * \see Serial::setFlowcontrol - * - * \throw InvalidConfigurationException - */ + * + * \see Serial::setFlowcontrol + * + * \throw InvalidConfigurationException + */ flowcontrol_t getFlowcontrol () const; @@ -387,27 +503,49 @@ public: void flushOutput (); + /*! Sends the RS-232 break signal. See tcsendbreak(3). */ void sendBreak (int duration); + /*! Set the break condition to a given level. Defaults to true. */ void setBreak (bool level = true); + /*! Set the RTS handshaking line to the given level. Defaults to true. */ void setRTS (bool level = true); + /*! Set the DTR handshaking line to the given level. Defaults to true. */ void setDTR (bool level = true); + /*! + * Returns true on CTS, DSR, RI, or CD changing. + * + * Can throw an exception if an error occurs while waiting. + * You can check the status of CTS, DSR, RI, and CD once this returns. + * Uses TIOCMIWAIT via ioctl if available (mostly only on Linux) with a + * resolution of less than +-1ms and as good as +-0.2ms. Otherwise a + * polling method is used which can give +-2ms. + * + * \throw SerialException + */ + bool + waitForChange (); + + /*! Returns the current status of the CTS line. */ bool getCTS (); + /*! Returns the current status of the DSR line. */ bool getDSR (); + /*! Returns the current status of the RI line. */ bool getRI (); + /*! Returns the current status of the CD line. */ bool getCD (); diff --git a/serial.sublime-project b/serial.sublime-project new file mode 100644 index 0000000..1746fa9 --- /dev/null +++ b/serial.sublime-project @@ -0,0 +1,18 @@ +{ + "folders": + [ + { + "path": "/Users/william/devel/serial" + } + ], + "settings": + { + "sublimeclang_options": + [ + "-I/usr/include", + "-I/usr/local/include", + "-I/usr/lib/clang/3.1/include/", + "-I${folder:${project_path:serial.sublime-project}}/include" + ] + } +} diff --git a/serial.sublime-workspace b/serial.sublime-workspace new file mode 100644 index 0000000..486d099 --- /dev/null +++ b/serial.sublime-workspace @@ -0,0 +1,631 @@ +{ + "auto_complete": + { + "selected_items": + [ + [ + "tour", + "toupper(int _c) int" + ], + [ + "rotat", + "SceneObject::rotateTo(GLfloat roll, GLfloat pitch, GLfloat yaw) void" + ], + [ + "tou", + "touring_index size_t" + ], + [ + "person", + "person_mbb Model::CollisionBox" + ], + [ + "SE", + "SE Model::CollisionBox" + ], + [ + "m", + "mbb Model::CollisionBox" + ], + [ + "glVer", + "glVertex2fv(const GLfloat *v) void" + ], + [ + "di", + "distance GLfloat" + ], + [ + "the", + "their_position GLfloat *" + ], + [ + "their", + "their_obj_it vector::iterator" + ], + [ + "my", + "my_obj_it vector::iterator" + ], + [ + "my_mod", + "my_model_it vector::iterator" + ], + [ + "thei", + "their_model_it vector::iterator" + ], + [ + "iterator", + "assign(_InputIterator __first, _InputIterator __last) void" + ], + [ + "get", + "getPosition() GLfloat *" + ], + [ + "lh", + "lhs_mbb Model::CollisionBox" + ], + [ + "cal", + "calculateMBB(Model::Object &obj) Model::CollisionBox" + ], + [ + "Col", + "CollisionBox " + ], + [ + "spo", + "spotlight LightingStyle" + ], + [ + "main", + "main_camera Camera" + ], + [ + "pers", + "person Person *" + ], + [ + "glro", + "glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) void" + ], + [ + "glTran", + "glTranslatef(GLfloat x, GLfloat y, GLfloat z) void" + ], + [ + "she", + "shelby_model string" + ], + [ + "loa", + "loaded_ bool" + ], + [ + "ena", + "enabled_ bool" + ], + [ + "sp", + "specular(GLfloat r, GLfloat g, GLfloat b, GLfloat a) void" + ], + [ + "en", + "direction(GLfloat x, GLfloat y, GLfloat z) void" + ], + [ + "spot", + "spot_light Light" + ], + [ + "GL_NOR", + "GL_NORMALIZE " + ], + [ + "att", + "attenuation_q_ GLfloat" + ], + [ + "atte", + "attenuation_c_ GLfloat" + ], + [ + "glPop", + "glPopMatrix() void" + ], + [ + "appl", + "apply_() void" + ], + [ + "no_l", + "no_lights_left const size_t" + ], + [ + "ligh", + "lights_left size_t" + ], + [ + "do", + "do_normals bool" + ], + [ + "back_in", + "back_inserter(_Container &__x) back_insert_iterator<_Container>" + ], + [ + "istr", + "istream_iterator " + ], + [ + "is", + "istringstream " + ], + [ + "math", + "matches size_t" + ], + [ + "curr", + "current_object Model::Object" + ], + [ + "matc", + "matches2 size_t" + ], + [ + "QwtPlot", + "QwtPlotZoomer" + ], + [ + "__init", + "__initZooming" + ], + [ + "plot_coi", + "plot_coil2" + ], + [ + "plo", + "plot_coil1" + ], + [ + "plot_co", + "plot_coil2" + ], + [ + "QwtPl", + "QwtPlotCurve" + ], + [ + "trail", + "trailer_plotcurve" + ], + [ + "pl", + "plot_coil1" + ], + [ + "plot", + "plot_coil1" + ], + [ + "open", + "open_button" + ], + [ + "plotcoi", + "plot_coil1" + ], + [ + "EM", + "EM61MK2Log" + ], + [ + "pa", + "path_file_name" + ], + [ + "head", + "headings" + ], + [ + "eas", + "eastings" + ], + [ + "north", + "northings" + ], + [ + "las", + "last_east" + ], + [ + "odom", + "odom" + ], + [ + "logs", + "logs_data" + ], + [ + "plot_", + "plot_em61mk2logs" + ], + [ + "Em61", + "EM61MK2Log" + ], + [ + "sib", + "sibling_file_name" + ], + [ + "si", + "sibling_file_name" + ], + [ + "fil", + "file_name" + ] + ] + }, + "buffers": + [ + { + "file": "include/serial/serial.h", + "settings": + { + "buffer_size": 17876, + "line_ending": "Unix" + } + }, + { + "file": "src/serial.cc", + "settings": + { + "buffer_size": 7015, + "line_ending": "Unix" + } + }, + { + "file": "src/impl/unix.cc", + "settings": + { + "buffer_size": 16696, + "line_ending": "Unix" + } + } + ], + "build_system": "Packages/Python/Python.sublime-build", + "command_palette": + { + "height": 47.0, + "selected_items": + [ + [ + "install", + "Package Control: Install Package" + ], + [ + "late", + "LaTeXTools: View PDF" + ] + ], + "width": 449.0 + }, + "console": + { + "height": 0.0 + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "file_history": + [ + "/Users/william/devel/automow_ws/au_automow_common/automow_planning/tests/test_path_planner.py", + "/Users/william/devel/automow_ws/au_automow_common/automow_planning/tests/test_coverage_planner.py", + "/Users/william/devel/automow_ws/au_automow_common/automow_planning/tests/test_costmap.py", + "/Users/william/devel/automow_ws/au_automow_common/automow_planning/tests/survey.csv", + "/Users/william/devel/automow_ws/au_automow_common/automow_planning/tests/image_generator.py", + "/Users/william/.ros/rosdep.yaml", + "/Users/william/.bashrc", + "/Users/william/devel/xbow400/include/xbow_400.h", + "/Users/william/devel/xbow400/src/xbow_400.cpp", + "/Users/william/devel/xbow400/README", + "/Users/william/devel/xbow400/xbow400.sublime-project", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/SublimeClang/SublimeClang.sublime-settings", + "/Users/william/devel/comp6400/homework6/homework6.sublime-project", + "/Users/william/devel/comp6400/homework6/src/main.cc", + "/Users/william/devel/comp6400/homework6/models/student.obj", + "/Users/william/devel/comp6400/homework6/models/ground.obj", + "/Users/william/devel/comp6400/homework6/models/shelby.obj", + "/Users/william/devel/comp6400/homework6/models/ground.mtl", + "/Users/william/devel/comp6400/homework6/models/shelby.mtl", + "/Users/william/devel/comp6400/homework6/CMakeLists.txt", + "/Users/william/devel/comp6400/homework6/models/shelby.blend", + "/Users/william/devel/comp6400/homework6/Makefile", + "/usr/include/c++/4.2.1/tr1/cstdio", + "/Users/william/devel/comp6400/homework6/src/michaels.cc", + "/Users/william/devel/auxos_orig/scripts/plot_em.py", + "/Users/william/devel/auxos_orig/scripts/logtool.py", + "/Users/william/devel/auxos_orig/scripts/em61mk2.py", + "/Users/william/devel/auxos_orig/scripts/lib/__init__.py", + "/usr/local/Library/Formula/pyqt.rb", + "/usr/local/Library/Formula/pyqwt.rb", + "/Users/william/devel/3dteleop_ws/3d_teleop/redo_slam_offline/launch/play_and_remap_tf.launch", + "/Users/william/devel/3dteleop_ws/3d_teleop/misc_scripts/launch/automow_stuff.launch", + "/Users/william/devel/auxos_orig/scripts/coords2path.py", + "/Users/william/Downloads/sup1_waypts_utm_path.txt", + "/Users/william/Downloads/example.txt", + "/Users/william/devel/auxos_orig/scripts/sup1_waypts_utm_path.txt", + "/Users/william/devel/ion_plans_paper/citations.bib", + "/Users/william/devel/ion_plans_paper/ion_plans.tex", + "/Users/william/Desktop/em61mk2.py", + "/Users/william/devel/ion_plans_paper/ion_plans.log", + "/Users/william/devel/ion_plans_paper/ion_plans.pdf", + "/Users/william/devel/3dteleop_ws/octomap/octomap/include/octomap/OcTree.h", + "/Users/william/devel/3dteleop_ws/octomap/octomap/include/octomap/OccupancyOcTreeBase.h", + "/Users/william/devel/3dteleop_ws/octomap/octomap/include/octomap/OccupancyOcTreeBase.hxx", + "/Users/william/devel/3dteleop_ws/octomap/octomap/src/OcTree.cpp", + "/Users/william/devel/3dteleop_ws/octomap/octomap/include/octomap/octomap_deprecated.h", + "/Users/william/devel/3dteleop_ws/octomap/CMakeLists.txt", + "/Users/william/devel/comp6400/homework3/src/main.cc", + "/Users/william/Desktop/untitled.obj", + "/Users/william/devel/cs373-tests/util.py", + "/Users/william/devel/cs373-tests/2.6/code.py", + "/Users/william/devel/cs373-tests/2.6/template.py", + "/Users/william/devel/3dteleop_ws/3d_teleop/misc_scripts/manifest.xml", + "/Users/william/devel/3dteleop_ws/3d_teleop/misc_scripts/nodes/odom2tf.py", + "/Users/william/devel/3dteleop_ws/3d_teleop/misc_scripts/nodes/automow_laser_filter.py", + "/Users/william/devel/3dteleop_ws/3d_teleop/misc_scripts/nodes/rename_tf_frame.py", + "/Users/william/devel/3dteleop_ws/3d_teleop/misc_scripts/nodes/remap_tf.py", + "/Users/william/Downloads/orocos_kinematics_dynamics-ffdeaad-install_name_tool.patch", + "/Users/william/devel/automow_ws/au_automow_common/automow_bringup/launch/minimal.launch", + "/Users/william/devel/vis_ws/visualization/rviz/manifest.xml", + "/Library/Python/2.7/site-packages/pkg_resources.py", + "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", + "/Volumes/Storage/Data/Camp Sibert/Feb 15 - Feb 20/plot_em61mk2.py", + "/Volumes/Storage/Data/Camp Sibert/Feb 15 - Feb 20/em61mk2.py", + "/Volumes/Storage/Data/Camp Sibert 2-15to2-20/em61mk2.py", + "/Volumes/Storage/Data/Camp Sibert 2-15to2-20/plot_em61mk2.py" + ], + "find": + { + "height": 35.0 + }, + "find_in_files": + { + "height": 0.0, + "where_history": + [ + "" + ] + }, + "find_state": + { + "case_sensitive": false, + "find_history": + [ + "cts", + " ", + "o ", + "Cube_Cube.001", + "min[2]", + "min[1]", + "max[2]", + "max[1]", + "max[0]", + "min[0]", + "window_width", + "800", + "•", + "Cube", + "expected 1.", + "counter", + "go", + "setZoomerMousePattern", + "updateNode", + "compute", + "insertS" + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + ", ", + "min.z", + "min.y", + "max.z", + "max.y", + "max.x", + "min.x", + "*" + ], + "reverse": false, + "show_context": true, + "use_buffer2": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "selected": 2, + "sheets": + [ + { + "buffer": 0, + "file": "include/serial/serial.h", + "settings": + { + "buffer_size": 17876, + "regions": + { + }, + "selection": + [ + [ + 11407, + 11407 + ] + ], + "settings": + { + "syntax": "Packages/C++/C++.tmLanguage", + "tab_size": 4, + "translate_tabs_to_spaces": true, + "word_wrap": true, + "wrap_width": 80 + }, + "translation.x": 0.0, + "translation.y": 6934.0, + "zoom_level": 1.0 + }, + "type": "text" + }, + { + "buffer": 1, + "file": "src/serial.cc", + "settings": + { + "buffer_size": 7015, + "regions": + { + }, + "selection": + [ + [ + 0, + 0 + ] + ], + "settings": + { + "syntax": "Packages/C++/C++.tmLanguage", + "tab_size": 2, + "translate_tabs_to_spaces": true + }, + "translation.x": 0.0, + "translation.y": 479.0, + "zoom_level": 1.0 + }, + "type": "text" + }, + { + "buffer": 2, + "file": "src/impl/unix.cc", + "settings": + { + "buffer_size": 16696, + "regions": + { + }, + "selection": + [ + [ + 15521, + 15521 + ] + ], + "settings": + { + "syntax": "Packages/C++/C++.tmLanguage", + "tab_size": 2, + "translate_tabs_to_spaces": true + }, + "translation.x": 0.0, + "translation.y": 10013.0, + "zoom_level": 1.0 + }, + "type": "text" + } + ] + }, + { + "sheets": + [ + ] + } + ], + "incremental_find": + { + "height": 0.0 + }, + "input": + { + "height": 31.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ], + [ + 1, + 0, + 2, + 1 + ] + ], + "cols": + [ + 0.0, + 0.61784814072, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "output.clang": + { + "height": 100.0 + }, + "replace": + { + "height": 64.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "select_project": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "show_minimap": false, + "show_open_files": false, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 283.0, + "status_bar_visible": true +} diff --git a/src/impl/unix.cc b/src/impl/unix.cc index e87125d..e8d0f4c 100644 --- a/src/impl/unix.cc +++ b/src/impl/unix.cc @@ -2,9 +2,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -35,6 +37,7 @@ #endif using std::string; +using std::stringstream; using std::invalid_argument; using serial::Serial; using serial::SerialExecption; @@ -43,12 +46,12 @@ using serial::IOException; Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate, - long timeout, bytesize_t bytesize, + bytesize_t bytesize, parity_t parity, stopbits_t stopbits, flowcontrol_t flowcontrol) -: port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (true), rtscts_ (false), - timeout_ (timeout), baudrate_ (baudrate), parity_ (parity), - bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol) + : port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (true), rtscts_ (false), + baudrate_ (baudrate), parity_ (parity), + bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol) { pthread_mutex_init(&this->read_mutex, NULL); pthread_mutex_init(&this->write_mutex, NULL); @@ -66,30 +69,26 @@ Serial::SerialImpl::~SerialImpl () void Serial::SerialImpl::open () { - if (port_.empty ()) - { + if (port_.empty ()) { throw invalid_argument ("Empty port is invalid."); } - if (is_open_ == true) - { + if (is_open_ == true) { throw SerialExecption ("Serial port already open."); } fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); - if (fd_ == -1) - { - switch (errno) - { - case EINTR: - // Recurse because this is a recoverable error. - open (); - return; - case ENFILE: - case EMFILE: - THROW (IOException, "Too many file handles open."); - default: - THROW (IOException, errno); + if (fd_ == -1) { + switch (errno) { + case EINTR: + // Recurse because this is a recoverable error. + open (); + return; + case ENFILE: + case EMFILE: + THROW (IOException, "Too many file handles open."); + default: + THROW (IOException, errno); } } @@ -100,26 +99,24 @@ Serial::SerialImpl::open () void Serial::SerialImpl::reconfigurePort () { - if (fd_ == -1) - { + if (fd_ == -1) { // Can only operate on a valid file descriptor THROW (IOException, "Invalid file descriptor, is the serial port open?"); } struct termios options; // The options for the file descriptor - if (tcgetattr(fd_, &options) == -1) - { + if (tcgetattr(fd_, &options) == -1) { THROW (IOException, "::tcgetattr"); } // set up raw mode / no echo / binary - options.c_cflag |= (unsigned long) (CLOCAL|CREAD); - options.c_lflag &= (unsigned long) ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL| - ISIG|IEXTEN); //|ECHOPRT + options.c_cflag |= (unsigned long) (CLOCAL | CREAD); + options.c_lflag &= (unsigned long) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | + ISIG | IEXTEN); //|ECHOPRT options.c_oflag &= (unsigned long) ~(OPOST); - options.c_iflag &= (unsigned long) ~(INLCR|IGNCR|ICRNL|IGNBRK); + options.c_iflag &= (unsigned long) ~(INLCR | IGNCR | ICRNL | IGNBRK); #ifdef IUCLC options.c_iflag &= (unsigned long) ~IUCLC; #endif @@ -130,122 +127,118 @@ Serial::SerialImpl::reconfigurePort () // setup baud rate bool custom_baud = false; speed_t baud; - switch (baudrate_) - { + switch (baudrate_) { #ifdef B0 - case 0: baud = B0; break; + case 0: baud = B0; break; #endif #ifdef B50 - case 50: baud = B50; break; + case 50: baud = B50; break; #endif #ifdef B75 - case 75: baud = B75; break; + case 75: baud = B75; break; #endif #ifdef B110 - case 110: baud = B110; break; + case 110: baud = B110; break; #endif #ifdef B134 - case 134: baud = B134; break; + case 134: baud = B134; break; #endif #ifdef B150 - case 150: baud = B150; break; + case 150: baud = B150; break; #endif #ifdef B200 - case 200: baud = B200; break; + case 200: baud = B200; break; #endif #ifdef B300 - case 300: baud = B300; break; + case 300: baud = B300; break; #endif #ifdef B600 - case 600: baud = B600; break; + case 600: baud = B600; break; #endif #ifdef B1200 - case 1200: baud = B1200; break; + case 1200: baud = B1200; break; #endif #ifdef B1800 - case 1800: baud = B1800; break; + case 1800: baud = B1800; break; #endif #ifdef B2400 - case 2400: baud = B2400; break; + case 2400: baud = B2400; break; #endif #ifdef B4800 - case 4800: baud = B4800; break; + case 4800: baud = B4800; break; #endif #ifdef B7200 - case 7200: baud = B7200; break; + case 7200: baud = B7200; break; #endif #ifdef B9600 - case 9600: baud = B9600; break; + case 9600: baud = B9600; break; #endif #ifdef B14400 - case 14400: baud = B14400; break; + case 14400: baud = B14400; break; #endif #ifdef B19200 - case 19200: baud = B19200; break; + case 19200: baud = B19200; break; #endif #ifdef B28800 - case 28800: baud = B28800; break; + case 28800: baud = B28800; break; #endif #ifdef B57600 - case 57600: baud = B57600; break; + case 57600: baud = B57600; break; #endif #ifdef B76800 - case 76800: baud = B76800; break; + case 76800: baud = B76800; break; #endif #ifdef B38400 - case 38400: baud = B38400; break; + case 38400: baud = B38400; break; #endif #ifdef B115200 - case 115200: baud = B115200; break; + case 115200: baud = B115200; break; #endif #ifdef B128000 - case 128000: baud = B128000; break; + case 128000: baud = B128000; break; #endif #ifdef B153600 - case 153600: baud = B153600; break; + case 153600: baud = B153600; break; #endif #ifdef B230400 - case 230400: baud = B230400; break; + case 230400: baud = B230400; break; #endif #ifdef B256000 - case 256000: baud = B256000; break; + case 256000: baud = B256000; break; #endif #ifdef B460800 - case 460800: baud = B460800; break; + case 460800: baud = B460800; break; #endif #ifdef B921600 - case 921600: baud = B921600; break; + case 921600: baud = B921600; break; #endif - default: - custom_baud = true; -// Mac OS X 10.x Support + default: + custom_baud = true; + // Mac OS X 10.x Support #if defined(__APPLE__) && defined(__MACH__) #define IOSSIOSPEED _IOW('T', 2, speed_t) - int new_baud = static_cast (baudrate_); - if (ioctl (fd_, IOSSIOSPEED, &new_baud, 1) < 0) - { - THROW (IOException, errno); - } -// Linux Support + int new_baud = static_cast (baudrate_); + if (ioctl (fd_, IOSSIOSPEED, &new_baud, 1) < 0) { + THROW (IOException, errno); + } + // Linux Support #elif defined(__linux__) - struct serial_struct ser; - ioctl (fd_, TIOCGSERIAL, &ser); - // set custom divisor - ser.custom_divisor = ser.baud_base / baudrate_; - // update flags - ser.flags &= ~ASYNC_SPD_MASK; - ser.flags |= ASYNC_SPD_CUST; + struct serial_struct ser; + ioctl (fd_, TIOCGSERIAL, &ser); + // set custom divisor + ser.custom_divisor = ser.baud_base / baudrate_; + // update flags + ser.flags &= ~ASYNC_SPD_MASK; + ser.flags |= ASYNC_SPD_CUST; - if (ioctl (fd_, TIOCSSERIAL, ser) < 0) - { - THROW (IOException, errno); - } + if (ioctl (fd_, TIOCSSERIAL, ser) < 0) { + THROW (IOException, errno); + } #else - throw invalid_argument ("OS does not currently support custom bauds"); + throw invalid_argument ("OS does not currently support custom bauds"); #endif } - if (custom_baud == false) - { + if (custom_baud == false) { #ifdef _BSD_SOURCE ::cfsetspeed(&options, baud); #else @@ -257,56 +250,49 @@ Serial::SerialImpl::reconfigurePort () // setup char len options.c_cflag &= (unsigned long) ~CSIZE; if (bytesize_ == eightbits) - options.c_cflag |= CS8; + options.c_cflag |= CS8; else if (bytesize_ == sevenbits) - options.c_cflag |= CS7; + options.c_cflag |= CS7; else if (bytesize_ == sixbits) - options.c_cflag |= CS6; + options.c_cflag |= CS6; else if (bytesize_ == fivebits) - options.c_cflag |= CS5; + options.c_cflag |= CS5; else - throw invalid_argument ("invalid char len"); + throw invalid_argument ("invalid char len"); // setup stopbits if (stopbits_ == stopbits_one) - options.c_cflag &= (unsigned long) ~(CSTOPB); + options.c_cflag &= (unsigned long) ~(CSTOPB); else if (stopbits_ == stopbits_one_point_five) - // ONE POINT FIVE same as TWO.. there is no POSIX support for 1.5 - options.c_cflag |= (CSTOPB); + // ONE POINT FIVE same as TWO.. there is no POSIX support for 1.5 + options.c_cflag |= (CSTOPB); else if (stopbits_ == stopbits_two) - options.c_cflag |= (CSTOPB); + options.c_cflag |= (CSTOPB); else - throw invalid_argument ("invalid stop bit"); + throw invalid_argument ("invalid stop bit"); // setup parity - options.c_iflag &= (unsigned long) ~(INPCK|ISTRIP); - if (parity_ == parity_none) - { - options.c_cflag &= (unsigned long) ~(PARENB|PARODD); - } - else if (parity_ == parity_even) - { + options.c_iflag &= (unsigned long) ~(INPCK | ISTRIP); + if (parity_ == parity_none) { + options.c_cflag &= (unsigned long) ~(PARENB | PARODD); + } else if (parity_ == parity_even) { options.c_cflag &= (unsigned long) ~(PARODD); options.c_cflag |= (PARENB); - } - else if (parity_ == parity_odd) - { - options.c_cflag |= (PARENB|PARODD); - } - else - { + } else if (parity_ == parity_odd) { + options.c_cflag |= (PARENB | PARODD); + } else { throw invalid_argument ("invalid parity"); } // setup flow control // xonxoff #ifdef IXANY if (xonxoff_) - options.c_iflag |= (IXON|IXOFF); //|IXANY) + options.c_iflag |= (IXON | IXOFF); //|IXANY) else - options.c_iflag &= (unsigned long) ~(IXON|IXOFF|IXANY); + options.c_iflag &= (unsigned long) ~(IXON | IXOFF | IXANY); #else if (xonxoff_) - options.c_iflag |= (IXON|IXOFF); + options.c_iflag |= (IXON | IXOFF); else - options.c_iflag &= (unsigned long) ~(IXON|IXOFF); + options.c_iflag &= (unsigned long) ~(IXON | IXOFF); #endif // rtscts #ifdef CRTSCTS @@ -324,8 +310,8 @@ Serial::SerialImpl::reconfigurePort () #endif // http://www.unixwiz.net/techtips/termios-vmin-vtime.html - // this basically sets the read call up to be a polling read, - // but we are using select to ensure there is data available + // this basically sets the read call up to be a polling read, + // but we are using select to ensure there is data available // to read before each call, so we should never needlessly poll options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 0; @@ -337,10 +323,8 @@ Serial::SerialImpl::reconfigurePort () void Serial::SerialImpl::close () { - if (is_open_ == true) - { - if (fd_ != -1) - { + if (is_open_ == true) { + if (fd_ != -1) { ::close (fd_); // Ignoring the outcome fd_ = -1; } @@ -357,23 +341,20 @@ Serial::SerialImpl::isOpen () const size_t Serial::SerialImpl::available () { - if (!is_open_) - { + if (!is_open_) { return 0; } int count = 0; int result = ioctl (fd_, TIOCINQ, &count); - if (result == 0) - { + if (result == 0) { return static_cast (count); - } - else - { + } else { THROW (IOException, errno); } } -inline void get_time_now(struct timespec &time) { +inline void get_time_now(struct timespec &time) +{ # ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time clock_serv_t cclock; mach_timespec_t mts; @@ -388,23 +369,22 @@ inline void get_time_now(struct timespec &time) { } size_t -Serial::SerialImpl::read (unsigned char* buf, size_t size) +Serial::SerialImpl::read (unsigned char *buf, size_t size) { - if (!is_open_) - { + if (!is_open_) { throw PortNotOpenedException ("Serial::read"); } fd_set readfds; size_t bytes_read = 0; struct timeval timeout; - timeout.tv_sec = timeout_ / 1000; - timeout.tv_usec = static_cast (timeout_ % 1000) * 1000; - while (bytes_read < size) - { + timeout.tv_sec = timeout_.read_timeout_constant / 1000; + timeout.tv_usec = static_cast (timeout_.read_timeout_constant % 1000); + timeout.tv_usec *= 1000; // To convert to micro seconds + while (bytes_read < size) { FD_ZERO (&readfds); FD_SET (fd_, &readfds); - // On Linux the timeout struct is updated by select to contain the time - // left on the timeout to make looping easier, but on other platforms this + // On Linux the timeout struct is updated by select to contain the time + // left on the timeout to make looping easier, but on other platforms this // does not occur. #if !defined(__linux__) // Begin timing select @@ -418,8 +398,8 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size) get_time_now(end); // Calculate the time select took struct timeval diff; - diff.tv_sec = end.tv_sec-start.tv_sec; - diff.tv_usec = static_cast ((end.tv_nsec-start.tv_nsec)/1000); + diff.tv_sec = end.tv_sec - start.tv_sec; + diff.tv_usec = static_cast ((end.tv_nsec - start.tv_nsec) / 1000); // Update the timeout if (timeout.tv_sec <= diff.tv_sec) { timeout.tv_sec = 0; @@ -434,7 +414,7 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size) #endif // Figure out what happened by looking at select's response 'r' -/** Error **/ + /** Error **/ if (r < 0) { // Select was interrupted, try again if (errno == EINTR) { @@ -443,22 +423,21 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size) // Otherwise there was some error THROW (IOException, errno); } -/** Timeout **/ + /** Timeout **/ if (r == 0) { break; } -/** Something ready to read **/ + /** Something ready to read **/ if (r > 0) { // Make sure our file descriptor is in the ready to read list if (FD_ISSET (fd_, &readfds)) { // This should be non-blocking returning only what is avaialble now // Then returning so that select can block again. ssize_t bytes_read_now = - ::read (fd_, buf+bytes_read, size-bytes_read); + ::read (fd_, buf + bytes_read, size - bytes_read); // read should always return some data as select reported it was // ready to read when we get to this point. - if (bytes_read_now < 1) - { + if (bytes_read_now < 1) { // Disconnected devices, at least on Linux, show the // behavior that they are always ready to read immediately // but reading returns nothing. @@ -484,7 +463,7 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size) } // This shouldn't happen, if r > 0 our fd has to be in the list! THROW (IOException, "select reports ready to read, but our fd isn't" - " in the list, this shouldn't happen!"); + " in the list, this shouldn't happen!"); } } return bytes_read; @@ -493,11 +472,9 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size) size_t Serial::SerialImpl::write (const string &data) { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::write"); } - return static_cast (::write (fd_, data.c_str (), data.length ())); } @@ -514,12 +491,12 @@ Serial::SerialImpl::getPort () const } void -Serial::SerialImpl::setTimeout (long timeout) +Serial::SerialImpl::setTimeout (serial::timeout_t &timeout) { timeout_ = timeout; } -long +serial::timeout_t Serial::SerialImpl::getTimeout () const { return timeout_; @@ -598,8 +575,7 @@ Serial::SerialImpl::getFlowcontrol () const void Serial::SerialImpl::flush () { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::flush"); } tcdrain (fd_); @@ -608,8 +584,7 @@ Serial::SerialImpl::flush () void Serial::SerialImpl::flushInput () { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::flushInput"); } tcflush (fd_, TCIFLUSH); @@ -618,8 +593,7 @@ Serial::SerialImpl::flushInput () void Serial::SerialImpl::flushOutput () { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::flushOutput"); } tcflush (fd_, TCOFLUSH); @@ -628,25 +602,21 @@ Serial::SerialImpl::flushOutput () void Serial::SerialImpl::sendBreak (int duration) { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::sendBreak"); } - tcsendbreak (fd_, static_cast (duration/4)); + tcsendbreak (fd_, static_cast (duration / 4)); } void Serial::SerialImpl::setBreak (bool level) { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::setBreak"); } - if (level) - { + if (level) { ioctl (fd_, TIOCSBRK); - } - else { + } else { ioctl (fd_, TIOCCBRK); } } @@ -654,15 +624,12 @@ Serial::SerialImpl::setBreak (bool level) void Serial::SerialImpl::setRTS (bool level) { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::setRTS"); } - if (level) - { + if (level) { ioctl (fd_, TIOCMBIS, TIOCM_RTS); - } - else { + } else { ioctl (fd_, TIOCMBIC, TIOCM_RTS); } } @@ -670,25 +637,45 @@ Serial::SerialImpl::setRTS (bool level) void Serial::SerialImpl::setDTR (bool level) { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::setDTR"); } - if (level) - { + if (level) { ioctl (fd_, TIOCMBIS, TIOCM_DTR); - } - else - { + } else { ioctl (fd_, TIOCMBIC, TIOCM_DTR); } } +bool +Serial::SerialImpl::waitForChange () +{ +#ifndef TIOCMIWAIT + while (is_open_ == true) { + int s = ioctl (fd_, TIOCMGET, 0); + if ((s & TIOCM_CTS) != 0) return true; + if ((s & TIOCM_DSR) != 0) return true; + if ((s & TIOCM_RI) != 0) return true; + if ((s & TIOCM_CD) != 0) return true; + usleep(1000); + } +#else + if (ioctl(fd_, TIOCMIWAIT, (TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS)) != 0) { + stringstream ss; + ss << "waitForDSR failed on a call to ioctl(TIOCMIWAIT): " + << errno << " " << strerror(errno); + throw(SerialExecption(ss.str().c_str())); + return false; + } + return true; +#endif + return false; +} + bool Serial::SerialImpl::getCTS () { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::getCTS"); } int s = ioctl (fd_, TIOCMGET, 0); @@ -696,10 +683,9 @@ Serial::SerialImpl::getCTS () } bool -Serial::SerialImpl::getDSR() +Serial::SerialImpl::getDSR () { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::getDSR"); } int s = ioctl (fd_, TIOCMGET, 0); @@ -709,8 +695,7 @@ Serial::SerialImpl::getDSR() bool Serial::SerialImpl::getRI() { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::getRI"); } int s = ioctl (fd_, TIOCMGET, 0); @@ -720,8 +705,7 @@ Serial::SerialImpl::getRI() bool Serial::SerialImpl::getCD() { - if (is_open_ == false) - { + if (is_open_ == false) { throw PortNotOpenedException ("Serial::getCD"); } int s = ioctl (fd_, TIOCMGET, 0); @@ -729,7 +713,8 @@ Serial::SerialImpl::getCD() } void -Serial::SerialImpl::readLock() { +Serial::SerialImpl::readLock() +{ int result = pthread_mutex_lock(&this->read_mutex); if (result) { THROW (IOException, result); @@ -737,7 +722,8 @@ Serial::SerialImpl::readLock() { } void -Serial::SerialImpl::readUnlock() { +Serial::SerialImpl::readUnlock() +{ int result = pthread_mutex_unlock(&this->read_mutex); if (result) { THROW (IOException, result); @@ -745,7 +731,8 @@ Serial::SerialImpl::readUnlock() { } void -Serial::SerialImpl::writeLock() { +Serial::SerialImpl::writeLock() +{ int result = pthread_mutex_lock(&this->write_mutex); if (result) { THROW (IOException, result); @@ -753,7 +740,8 @@ Serial::SerialImpl::writeLock() { } void -Serial::SerialImpl::writeUnlock() { +Serial::SerialImpl::writeUnlock() +{ int result = pthread_mutex_unlock(&this->write_mutex); if (result) { THROW (IOException, result); diff --git a/src/serial.cc b/src/serial.cc index 2133b06..c2e1eaa 100644 --- a/src/serial.cc +++ b/src/serial.cc @@ -48,12 +48,12 @@ private: SerialImpl *pimpl_; }; -Serial::Serial (const string &port, unsigned long baudrate, long timeout, +Serial::Serial (const string &port, unsigned long baudrate, bytesize_t bytesize, parity_t parity, stopbits_t stopbits, flowcontrol_t flowcontrol) : read_cache_("") { - pimpl_ = new SerialImpl (port, baudrate, timeout, bytesize, parity, + pimpl_ = new SerialImpl (port, baudrate, bytesize, parity, stopbits, flowcontrol); } @@ -230,12 +230,12 @@ Serial::getPort () const } void -Serial::setTimeout (long timeout) +Serial::setTimeout (serial::timeout_t &timeout) { pimpl_->setTimeout (timeout); } -long +serial::timeout_t Serial::getTimeout () const { return pimpl_->getTimeout (); } @@ -341,6 +341,11 @@ void Serial::setDTR (bool level) pimpl_->setDTR (level); } +bool Serial::waitForChange() +{ + return pimpl_->waitForChange(); +} + bool Serial::getCTS () { return pimpl_->getCTS ();