From 6fac95d633e3731555f8d228da3140370bab0433 Mon Sep 17 00:00:00 2001 From: William Woodall Date: Wed, 6 Jun 2012 18:56:44 -0500 Subject: [PATCH] Adding initial windows support. --- .gitignore | 1 + Findserial.cmake | 4 +- README.md | 2 +- include/serial/impl/unix.h | 6 +- include/serial/impl/{windows.h => win.h} | 73 ++- include/serial/serial.h | 53 +- serial.sublime-workspace | 204 +++---- src/impl/unix.cc | 98 +++- src/impl/win.cc | 549 +++++++++++++++++++ src/impl/windows.cc | 670 ----------------------- src/serial.cc | 49 +- 11 files changed, 847 insertions(+), 862 deletions(-) rename include/serial/impl/{windows.h => win.h} (81%) create mode 100644 src/impl/win.cc delete mode 100644 src/impl/windows.cc diff --git a/.gitignore b/.gitignore index 00f5a05..b13b41e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ patched wiped msg_gen srv_gen +doc/html diff --git a/Findserial.cmake b/Findserial.cmake index 6d27e7e..20fccd0 100644 --- a/Findserial.cmake +++ b/Findserial.cmake @@ -1,5 +1,5 @@ -find_path(serial_INCLUDE_DIRS serial.h /usr/include/serial - /usr/local/include/serial "$ENV{NAMER_ROOT}") +find_path(serial_INCLUDE_DIRS serial/serial.h /usr/include + /usr/local/include "$ENV{NAMER_ROOT}") find_library(serial_LIBRARIES serial /usr/lib /usr/local/lib "$ENV{NAMER_ROOT}") diff --git a/README.md b/README.md index 31297de..9829480 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Run the example: The BSD License -Copyright (c) 2011 William Woodall +Copyright (c) 2012 William Woodall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/include/serial/impl/unix.h b/include/serial/impl/unix.h index ff8b4d1..6700a24 100644 --- a/include/serial/impl/unix.h +++ b/include/serial/impl/unix.h @@ -8,7 +8,7 @@ * * The MIT License * - * Copyright (c) 2011 William Woodall, John Harrison + * Copyright (c) 2012 William Woodall, John Harrison * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -74,10 +74,10 @@ public: available (); size_t - read (unsigned char *buf, size_t size = 1); + read (uint8_t *buf, size_t size = 1); size_t - write (const string &data); + write (const uint8_t *data, size_t length); void flush (); diff --git a/include/serial/impl/windows.h b/include/serial/impl/win.h similarity index 81% rename from include/serial/impl/windows.h rename to include/serial/impl/win.h index aa06706..902a70a 100644 --- a/include/serial/impl/windows.h +++ b/include/serial/impl/win.h @@ -8,7 +8,7 @@ * * The MIT License * - * Copyright (c) 2011 William Woodall, John Harrison + * Copyright (c) 2012 William Woodall, John Harrison * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -39,6 +39,8 @@ #include "serial/serial.h" +#include "windows.h" + namespace serial { using std::string; @@ -51,7 +53,6 @@ class serial::Serial::SerialImpl { public: SerialImpl (const string &port, unsigned long baudrate, - long timeout, bytesize_t bytesize, parity_t parity, stopbits_t stopbits, @@ -72,10 +73,10 @@ public: available (); size_t - read (char* buf, size_t size = 1); + read (uint8_t *buf, size_t size = 1); size_t - write (const string &data); + write (const uint8_t *data, size_t length); void flush (); @@ -87,50 +88,53 @@ 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); - + string getPort () const; void - setTimeout (long timeout); - - long + setTimeout (Timeout &timeout); + + Timeout getTimeout () const; void setBaudrate (unsigned long baudrate); - + unsigned long getBaudrate () const; void setBytesize (bytesize_t bytesize); - + bytesize_t getBytesize () const; @@ -152,24 +156,39 @@ public: flowcontrol_t getFlowcontrol () const; + void + readLock (); + + void + readUnlock (); + + void + writeLock (); + + void + writeUnlock (); + protected: void reconfigurePort (); private: string port_; // Path to the file descriptor - int fd_; // The current file descriptor + HANDLE fd_; - bool isOpen_; - bool xonxoff_; - bool rtscts_; + bool is_open_; - long timeout_; // Timeout for read operations + Timeout timeout_; // Timeout for read operations unsigned long baudrate_; // Baudrate parity_t parity_; // Parity bytesize_t bytesize_; // Size of the bytes stopbits_t stopbits_; // Stop Bits flowcontrol_t flowcontrol_; // Flow Control + + // Mutex used to lock the read functions + HANDLE read_mutex; + // Mutex used to lock the write functions + HANDLE write_mutex; }; } diff --git a/include/serial/serial.h b/include/serial/serial.h index 3f2c60c..84970d2 100644 --- a/include/serial/serial.h +++ b/include/serial/serial.h @@ -8,7 +8,7 @@ * * The MIT License * - * Copyright (c) 2011 William Woodall + * Copyright (c) 2012 William Woodall * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -42,6 +42,7 @@ #include #include #include +#include #define THROW(exceptionClass, message) throw exceptionClass(__FILE__, \ __LINE__, (message) ) @@ -89,9 +90,9 @@ typedef enum { * in milliseconds. */ struct Timeout { - Timeout (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) + Timeout (int32_t inter_byte_timeout_=0, int32_t read_timeout_constant_=0, + int32_t read_timeout_multiplier_=0, int32_t write_timeout_constant_=0, + int32_t write_timeout_multiplier_=0) : inter_byte_timeout(inter_byte_timeout_), read_timeout_constant(read_timeout_constant_), read_timeout_multiplier(read_timeout_multiplier_), @@ -99,19 +100,19 @@ struct Timeout { write_timeout_multiplier(write_timeout_multiplier_) {} /*! Number of milliseconds between bytes received to timeout on. */ - long inter_byte_timeout; + int32_t inter_byte_timeout; /*! A constant number of milliseconds to wait after calling read. */ - long read_timeout_constant; + int32_t read_timeout_constant; /*! A multiplier against the number of requested bytes to wait after * calling read. */ - long read_timeout_multiplier; + int32_t read_timeout_multiplier; /*! A constant number of milliseconds to wait after calling write. */ - long write_timeout_constant; + int32_t write_timeout_constant; /*! A multiplier against the number of requested bytes to wait after * calling write. */ - long write_timeout_multiplier; + int32_t write_timeout_multiplier; }; /*! @@ -149,7 +150,7 @@ public: * \throw PortNotOpenedException */ Serial (const std::string &port = "", - unsigned long baudrate = 9600, + uint32_t baudrate = 9600, Timeout timeout = Timeout(), bytesize_t bytesize = eightbits, parity_t parity = parity_none, @@ -209,25 +210,25 @@ public: * 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 buffer An uint8_t array of at least the requested size. * \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 (unsigned char *buffer, size_t size); + read (uint8_t *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 buffer A reference to a std::vector of uint8_t. * \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 (std::vector &buffer, size_t size = 1); /*! Read a given amount of bytes from the serial port into a give buffer. * @@ -301,7 +302,7 @@ public: * the serial port. */ size_t - write (const unsigned char *data, size_t size); + write (const uint8_t *data, size_t size); /*! Write a string to the serial port. * @@ -312,7 +313,7 @@ public: * the serial port. */ size_t - write (const std::vector &data); + write (const std::vector &data); /*! Write a string to the serial port. * @@ -384,9 +385,9 @@ public: /*! 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) + setTimeout (int32_t inter_byte_timeout, int32_t read_timeout_constant, + int32_t read_timeout_multiplier, int32_t write_timeout_constant, + int32_t write_timeout_multiplier) { Timeout timeout(inter_byte_timeout, read_timeout_constant, read_timeout_multiplier, write_timeout_constant, @@ -417,7 +418,7 @@ public: * \throw InvalidConfigurationException */ void - setBaudrate (unsigned long baudrate); + setBaudrate (uint32_t baudrate); /*! Gets the baudrate for the serial port. * @@ -427,7 +428,7 @@ public: * * \throw InvalidConfigurationException */ - unsigned long + uint32_t getBaudrate () const; /*! Sets the bytesize for the serial port. @@ -587,7 +588,10 @@ private: // Read common function size_t - read_ (unsigned char *buffer, size_t size); + read_ (uint8_t *buffer, size_t size); + // Write common function + size_t + write_ (const uint8_t *data, size_t length); }; @@ -646,11 +650,6 @@ public: } }; -class SerialExceptionBase : public std::exception -{ - -}; - } // namespace serial #endif diff --git a/serial.sublime-workspace b/serial.sublime-workspace index 486d099..9fa9b00 100644 --- a/serial.sublime-workspace +++ b/serial.sublime-workspace @@ -3,6 +3,46 @@ { "selected_items": [ + [ + "baudr", + "baudrate_" + ], + [ + "dcb", + "dcbSerialParams" + ], + [ + "byte", + "bytes_written size_t" + ], + [ + "write", + "write_timeout_multiplier int32_t" + ], + [ + "read", + "read_timeout_multiplier" + ], + [ + "read_", + "read_timeout_multiplier" + ], + [ + "inter", + "inter_byte_timeout" + ], + [ + "write_", + "write_timeout_constant" + ], + [ + "string", + "stringstream" + ], + [ + "Seri", + "SerialExecption" + ], [ "tour", "toupper(int _c) int" @@ -275,41 +315,25 @@ }, "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, + "height": 87.0, "selected_items": [ + [ + "convert sp", + "Indentation: Convert to Spaces" + ], [ "install", "Package Control: Install Package" ], + [ + "Package Control: remo", + "Package Control: Remove Package" + ], [ "late", "LaTeXTools: View PDF" @@ -332,6 +356,27 @@ }, "file_history": [ + "/Users/william/devel/serial/include/serial/serial.h", + "/Users/william/devel/serial/include/serial/impl/win.h", + "/Users/william/devel/serial/src/impl/win.cc", + "/Users/william/devel/serial/src/impl/unix.cc", + "/Users/william/devel/serial/include/serial/impl/unix.h", + "/Users/william/devel/serial/src/serial.cc", + "/Users/william/devel/serial/Findserial.cmake", + "/Users/william/devel/serial/src/impl/windows.cc", + "/Users/william/devel/serial/serial.sublime-project", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/SublimeClang/SublimeClang.sublime-settings", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/User/SublimeClang.sublime-settings", + "/Users/william/devel/serial/README.md", + "/Users/william/devel/serial/doc/html/serial_8h.html", + "/Users/william/devel/serial/doc/html/unix_8h.html", + "/Users/william/devel/serial/doc/html/windows_8h.html", + "/Users/william/devel/serial/include/serial/impl/windows.h", + "/Users/william/devel/serial/doc/Doxyfile", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/Terminal/Default (OSX).sublime-keymap", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/SublimeAStyleFormatter/SublimeAStyleFormatter.sublime-settings", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/SublimeClang/Default.sublime-keymap", + "/Users/william/Library/Application Support/Sublime Text 2/Packages/SublimeAStyleFormatter/Default (OSX).sublime-keymap", "/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", @@ -343,7 +388,6 @@ "/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", @@ -405,9 +449,10 @@ }, "find_in_files": { - "height": 0.0, + "height": 93.0, "where_history": [ + "", "" ] }, @@ -416,6 +461,18 @@ "case_sensitive": false, "find_history": [ + "flowcon", + "xonxoff_", + "rtscts_", + "#ifdef B", + "baud = B", + "write", + "char", + "unsigned char", + "char", + "long", + "2011", + " *", "cts", " ", "o ", @@ -444,6 +501,10 @@ "regex": false, "replace_history": [ + "#ifdef CBR_", + "dcbSerialParams.BaudRate = CBR_", + "2012", + " *", ", ", "min.z", "min.y", @@ -462,95 +523,8 @@ "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" - } ] }, { @@ -587,7 +561,7 @@ "cols": [ 0.0, - 0.61784814072, + 0.71805886817, 1.0 ], "rows": diff --git a/src/impl/unix.cc b/src/impl/unix.cc index d34d7aa..d39cc01 100644 --- a/src/impl/unix.cc +++ b/src/impl/unix.cc @@ -369,7 +369,7 @@ inline void get_time_now(struct timespec &time) } size_t -Serial::SerialImpl::read (unsigned char *buf, size_t size) +Serial::SerialImpl::read (uint8_t *buf, size_t size) { if (!is_open_) { throw PortNotOpenedException ("Serial::read"); @@ -470,12 +470,104 @@ Serial::SerialImpl::read (unsigned char *buf, size_t size) } size_t -Serial::SerialImpl::write (const string &data) +Serial::SerialImpl::write (const uint8_t *data, size_t length) { if (is_open_ == false) { throw PortNotOpenedException ("Serial::write"); } - return static_cast (::write (fd_, data.c_str (), data.length ())); + fd_set writefds; + size_t bytes_written = 0; + struct timeval timeout; + timeout.tv_sec = timeout_.write_timeout_constant / 1000; + timeout.tv_usec = static_cast (timeout_.write_timeout_multiplier % 1000); + timeout.tv_usec *= 1000; // To convert to micro seconds + while (bytes_written < length) { + FD_ZERO (&writefds); + FD_SET (fd_, &writefds); + // 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 + struct timespec start, end; + get_time_now(start); +#endif + // Do the select + int r = select (fd_ + 1, &writefds, NULL, NULL, &timeout); +#if !defined(__linux__) + // Calculate difference and update the structure + 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); + // Update the timeout + if (timeout.tv_sec <= diff.tv_sec) { + timeout.tv_sec = 0; + } else { + timeout.tv_sec -= diff.tv_sec; + } + if (timeout.tv_usec <= diff.tv_usec) { + timeout.tv_usec = 0; + } else { + timeout.tv_usec -= diff.tv_usec; + } +#endif + + // Figure out what happened by looking at select's response 'r' + /** Error **/ + if (r < 0) { + // Select was interrupted, try again + if (errno == EINTR) { + continue; + } + // Otherwise there was some error + THROW (IOException, errno); + } + /** Timeout **/ + if (r == 0) { + break; + } + /** Something ready to read **/ + if (r > 0) { + // Make sure our file descriptor is in the ready to read list + if (FD_ISSET (fd_, &writefds)) { + // This should be non-blocking returning only what is avaialble now + // Then returning so that select can block again. + ssize_t bytes_written_now = + ::write (fd_, data + bytes_written, length - bytes_written); + // read should always return some data as select reported it was + // ready to read when we get to this point. + if (bytes_written_now < 1) { + // Disconnected devices, at least on Linux, show the + // behavior that they are always ready to read immediately + // but reading returns nothing. + throw SerialExecption ("device reports readiness to write but " + "returned no data (device disconnected?)"); + } + // Update bytes_read + bytes_written += static_cast (bytes_written_now); + // If bytes_read == size then we have read everything we need + if (bytes_written == length) { + break; + } + // If bytes_read < size then we have more to read + if (bytes_written < length) { + continue; + } + // If bytes_read > size then we have over read, which shouldn't happen + if (bytes_written > length) { + throw SerialExecption ("read over read, too many bytes where " + "read, this shouldn't happen, might be " + "a logical error!"); + } + } + // 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!"); + } + } + return bytes_written; } void diff --git a/src/impl/win.cc b/src/impl/win.cc new file mode 100644 index 0000000..9b1f6e5 --- /dev/null +++ b/src/impl/win.cc @@ -0,0 +1,549 @@ +/* Copyright 2012 William Woodall and John Harrison */ + +#include "serial/impl/win.h" + +using std::string; +using std::stringstream; +using std::invalid_argument; +using serial::Serial; +using serial::SerialExecption; +using serial::PortNotOpenedException; +using serial::IOException; + + +Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate, + bytesize_t bytesize, + parity_t parity, stopbits_t stopbits, + flowcontrol_t flowcontrol) + : port_ (port), fd_ (INVALID_HANDLE_VALUE), is_open_ (false), + baudrate_ (baudrate), parity_ (parity), + bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol) +{ + read_mutex = CreateMutex(NULL, false, NULL); + write_mutex = CreateMutex(NULL, false, NULL); + if (port_.empty () == false) + open (); +} + +Serial::SerialImpl::~SerialImpl () +{ + this->close(); + CloseHandle(read_mutex); + CloseHandle(write_mutex); +} + +void +Serial::SerialImpl::open () +{ + if (port_.empty ()) { + throw invalid_argument ("Empty port is invalid."); + } + if (is_open_ == true) { + throw SerialExecption ("Serial port already open."); + } + + fd_ = CreateFile(port_, + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (fd_ == INVALID_HANDLE_VALUE) { + DWORD errno = GetLastError(); + switch (errno) { + case ERROR_FILE_NOT_FOUND: + stringstream ss; + ss << "Specified port, " << port_ << ", does not exist." + THROW (IOException, ss.str().c_str()); + default: + stringstream ss; + ss << "Unknown error opening the serial port: " << errno; + THROW (IOException, ss.str().c_str()); + } + } + + reconfigurePort(); + is_open_ = true; +} + +void +Serial::SerialImpl::reconfigurePort () +{ + if (fd_ == INVALID_HANDLE_VALUE) { + // Can only operate on a valid file descriptor + THROW (IOException, "Invalid file descriptor, is the serial port open?"); + } + + DCB dcbSerialParams = {0}; + + dcbSerial.DCBlength=sizeof(dcbSerialParams); + + if (!GetCommState(fd_, &dcbSerialParams)) { + //error getting state + THROW (IOException, "Error getting the serial port state."); + } + + // setup baud rate + switch (baudrate_) { +#ifdef CBR_0 + case 0: dcbSerialParams.BaudRate = CBR_0; break; +#endif +#ifdef CBR_50 + case 50: dcbSerialParams.BaudRate = CBR_50; break; +#endif +#ifdef CBR_75 + case 75: dcbSerialParams.BaudRate = CBR_75; break; +#endif +#ifdef CBR_110 + case 110: dcbSerialParams.BaudRate = CBR_110; break; +#endif +#ifdef CBR_134 + case 134: dcbSerialParams.BaudRate = CBR_134; break; +#endif +#ifdef CBR_150 + case 150: dcbSerialParams.BaudRate = CBR_150; break; +#endif +#ifdef CBR_200 + case 200: dcbSerialParams.BaudRate = CBR_200; break; +#endif +#ifdef CBR_300 + case 300: dcbSerialParams.BaudRate = CBR_300; break; +#endif +#ifdef CBR_600 + case 600: dcbSerialParams.BaudRate = CBR_600; break; +#endif +#ifdef CBR_1200 + case 1200: dcbSerialParams.BaudRate = CBR_1200; break; +#endif +#ifdef CBR_1800 + case 1800: dcbSerialParams.BaudRate = CBR_1800; break; +#endif +#ifdef CBR_2400 + case 2400: dcbSerialParams.BaudRate = CBR_2400; break; +#endif +#ifdef CBR_4800 + case 4800: dcbSerialParams.BaudRate = CBR_4800; break; +#endif +#ifdef CBR_7200 + case 7200: dcbSerialParams.BaudRate = CBR_7200; break; +#endif +#ifdef CBR_9600 + case 9600: dcbSerialParams.BaudRate = CBR_9600; break; +#endif +#ifdef CBR_14400 + case 14400: dcbSerialParams.BaudRate = CBR_14400; break; +#endif +#ifdef CBR_19200 + case 19200: dcbSerialParams.BaudRate = CBR_19200; break; +#endif +#ifdef CBR_28800 + case 28800: dcbSerialParams.BaudRate = CBR_28800; break; +#endif +#ifdef CBR_57600 + case 57600: dcbSerialParams.BaudRate = CBR_57600; break; +#endif +#ifdef CBR_76800 + case 76800: dcbSerialParams.BaudRate = CBR_76800; break; +#endif +#ifdef CBR_38400 + case 38400: dcbSerialParams.BaudRate = CBR_38400; break; +#endif +#ifdef CBR_115200 + case 115200: dcbSerialParams.BaudRate = CBR_115200; break; +#endif +#ifdef CBR_128000 + case 128000: dcbSerialParams.BaudRate = CBR_128000; break; +#endif +#ifdef CBR_153600 + case 153600: dcbSerialParams.BaudRate = CBR_153600; break; +#endif +#ifdef CBR_230400 + case 230400: dcbSerialParams.BaudRate = CBR_230400; break; +#endif +#ifdef CBR_256000 + case 256000: dcbSerialParams.BaudRate = CBR_256000; break; +#endif +#ifdef CBR_460800 + case 460800: dcbSerialParams.BaudRate = CBR_460800; break; +#endif +#ifdef CBR_921600 + case 921600: dcbSerialParams.BaudRate = CBR_921600; break; +#endif + default: + // Try to blindly assign it + dcbSerialParams.BaudRate = baudrate_; + } + + // setup char len + if (bytesize_ == eightbits) + dcbSerialParams.ByteSize = 8; + else if (bytesize_ == sevenbits) + dcbSerialParams.ByteSize = 7; + else if (bytesize_ == sixbits) + dcbSerialParams.ByteSize = 6; + else if (bytesize_ == fivebits) + dcbSerialParams.ByteSize = 5; + else + throw invalid_argument ("invalid char len"); + + // setup stopbits + if (stopbits_ == stopbits_one) + dcbSerialParams.StopBits = ONESTOPBIT; + else if (stopbits_ == stopbits_one_point_five) + dcbSerialParams.StopBits = ONE5STOPBITS; + else if (stopbits_ == stopbits_two) + dcbSerialParams.StopBits = TWOSTOPBITS; + else + throw invalid_argument ("invalid stop bit"); + + // setup parity + if (parity_ == parity_none) { + dcbSerialParams.Parity = NOPARITY; + } else if (parity_ == parity_even) { + dcbSerialParams.Parity = EVENPARITY; + } else if (parity_ == parity_odd) { + dcbSerialParams.Parity = ODDPARITY; + } else { + throw invalid_argument ("invalid parity"); + } + + // activate settings + if(!SetCommState(fd_, &dcbSerialParams)){ + THROW (IOException, "Error setting serial port settings."); + } +} + +void +Serial::SerialImpl::close () +{ + if (is_open_ == true) { + if (fd_ != INVALID_HANDLE_VALUE) { + CloseHandle(fd_); + fd_ = INVALID_HANDLE_VALUE; + } + is_open_ = false; + } +} + +bool +Serial::SerialImpl::isOpen () const +{ + return is_open_; +} + +size_t +Serial::SerialImpl::available () +{ + THROW (IOException, "available is not implemented on Windows."); +} + +size_t +Serial::SerialImpl::read (uint8_t *buf, size_t size) +{ + if (!is_open_) { + throw PortNotOpenedException ("Serial::read"); + } + DWORD bytes_read; + if (!ReadFile(fd_, buf, size, &bytes_read, NULL)) { + stringstream ss; + ss << "Error while reading from the serial port: " << GetLastError(); + THROW (IOException, ss.str().c_str()); + } + return reinterpret_cast (bytes_read); +} + +size_t +Serial::SerialImpl::write (const uint8_t *data, size_t length) +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::write"); + } + DWORD bytes_written; + if (!ReadFile(fd_, buf, size, &bytes_written, NULL)) { + stringstream ss; + ss << "Error while writing to the serial port: " << GetLastError(); + THROW (IOException, ss.str().c_str()); + } + return reinterpret_cast (bytes_written); +} + +void +Serial::SerialImpl::setPort (const string &port) +{ + port_ = port; +} + +string +Serial::SerialImpl::getPort () const +{ + return port_; +} + +void +Serial::SerialImpl::setTimeout (serial::Timeout &timeout) +{ + timeout_ = timeout; + COMMTIMEOUTS timeouts = {0}; + timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout; + timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant; + timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier; + timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant; + timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier; + if(!SetCommTimeouts(fd_, &timeouts)){ + THROW (IOException, "Error setting timeouts."); + } +} + +serial::Timeout +Serial::SerialImpl::getTimeout () const +{ + return timeout_; +} + +void +Serial::SerialImpl::setBaudrate (unsigned long baudrate) +{ + baudrate_ = baudrate; + if (is_open_) + reconfigurePort (); +} + +unsigned long +Serial::SerialImpl::getBaudrate () const +{ + return baudrate_; +} + +void +Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize) +{ + bytesize_ = bytesize; + if (is_open_) + reconfigurePort (); +} + +serial::bytesize_t +Serial::SerialImpl::getBytesize () const +{ + return bytesize_; +} + +void +Serial::SerialImpl::setParity (serial::parity_t parity) +{ + parity_ = parity; + if (is_open_) + reconfigurePort (); +} + +serial::parity_t +Serial::SerialImpl::getParity () const +{ + return parity_; +} + +void +Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits) +{ + stopbits_ = stopbits; + if (is_open_) + reconfigurePort (); +} + +serial::stopbits_t +Serial::SerialImpl::getStopbits () const +{ + return stopbits_; +} + +void +Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol) +{ + flowcontrol_ = flowcontrol; + if (is_open_) + reconfigurePort (); +} + +serial::flowcontrol_t +Serial::SerialImpl::getFlowcontrol () const +{ + return flowcontrol_; +} + +void +Serial::SerialImpl::flush () +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::flush"); + } + FlushFileBuffers (fd_); +} + +void +Serial::SerialImpl::flushInput () +{ + THROW (IOException, "flushInput is not supported on Windows."); +} + +void +Serial::SerialImpl::flushOutput () +{ + THROW (IOException, "flushOutput is not supported on Windows."); +} + +void +Serial::SerialImpl::sendBreak (int duration) +{ + THROW (IOException, "sendBreak is not supported on Windows."); +} + +void +Serial::SerialImpl::setBreak (bool level) +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::setBreak"); + } + if (level) { + EscapeCommFunction (fd_, SETBREAK); + } else { + EscapeCommFunction (fd_, CLRBREAK); + } +} + +void +Serial::SerialImpl::setRTS (bool level) +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::setRTS"); + } + if (level) { + EscapeCommFunction (fd_, SETRTS); + } else { + EscapeCommFunction (fd_, CLRRTS); + } +} + +void +Serial::SerialImpl::setDTR (bool level) +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::setDTR"); + } + if (level) { + EscapeCommFunction (fd_, SETDTR); + } else { + EscapeCommFunction (fd_, CLRDTR); + } +} + +bool +Serial::SerialImpl::waitForChange () +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::waitForChange"); + } + DWORD dwCommEvent; + + if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) { + // Error setting communications mask + return false; + } + + if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) { + // An error occurred waiting for the event. + return false; + } else { + // Event has occurred. + return true; + } +} + +bool +Serial::SerialImpl::getCTS () +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::getCTS"); + } + DWORD dwModemStatus; + if (!GetCommModemStatus(fd_, &dwModemStatus)) + // Error in GetCommModemStatus; + THROW (IOException, "Error getting the status of the CTS line."); + + return MS_CTS_ON & dwModemStatus; +} + +bool +Serial::SerialImpl::getDSR () +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::getDSR"); + } + DWORD dwModemStatus; + if (!GetCommModemStatus(fd_, &dwModemStatus)) + // Error in GetCommModemStatus; + THROW (IOException, "Error getting the status of the DSR line."); + + return MS_DSR_ON & dwModemStatus; +} + +bool +Serial::SerialImpl::getRI() +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::getRI"); + } + DWORD dwModemStatus; + if (!GetCommModemStatus(fd_, &dwModemStatus)) + // Error in GetCommModemStatus; + THROW (IOException, "Error getting the status of the DSR line."); + + return MS_RING_ON & dwModemStatus; +} + +bool +Serial::SerialImpl::getCD() +{ + if (is_open_ == false) { + throw PortNotOpenedException ("Serial::getCD"); + } + DWORD dwModemStatus; + if (!GetCommModemStatus(fd_, &dwModemStatus)) + // Error in GetCommModemStatus; + THROW (IOException, "Error getting the status of the DSR line."); + + return MS_RLSD_ON & dwModemStatus; +} + +void +Serial::SerialImpl::readLock() +{ + if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) { + THROW (IOException, "Error claiming read mutex."); + } +} + +void +Serial::SerialImpl::readUnlock() +{ + if (!ReleaseMutex(read_mutex)) { + THROW (IOException, "Error releasing read mutex."); + } +} + +void +Serial::SerialImpl::writeLock() +{ + if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) { + THROW (IOException, "Error claiming write mutex."); + } +} + +void +Serial::SerialImpl::writeUnlock() +{ + if (!ReleaseMutex(write_mutex)) { + THROW (IOException, "Error releasing write mutex."); + } +} diff --git a/src/impl/windows.cc b/src/impl/windows.cc deleted file mode 100644 index 5e82227..0000000 --- a/src/impl/windows.cc +++ /dev/null @@ -1,670 +0,0 @@ -/* Copyright 2012 William Woodall and John Harrison */ - -#include "serial/impl/windows.h" - -using std::string; -using std::invalid_argument; -using serial::Serial; -using serial::SerialExecption; -using serial::PortNotOpenedException; -using serial::IOException; - - -Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate, - long timeout, bytesize_t bytesize, - parity_t parity, stopbits_t stopbits, - flowcontrol_t flowcontrol) -: port_ (port), fd_ (-1), isOpen_ (false), xonxoff_ (true), rtscts_ (false), - timeout_ (timeout), baudrate_ (baudrate), parity_ (parity), bytesize_ (bytesize), - stopbits_ (stopbits), flowcontrol_ (flowcontrol) -{ - if (port_.empty () == false) - open (); -} - -Serial::SerialImpl::~SerialImpl () -{ - close(); -} - -void -Serial::SerialImpl::open () -{ - if (port_.empty()) - { - throw invalid_argument ("bad port specified"); - } - if (isOpen_ == true) - { - throw SerialExecption ("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 ("to many file handles open"); - break; - default: - throw IOException (errno); - } - } - - reconfigurePort(); - isOpen_ = true; -} - -void -Serial::SerialImpl::reconfigurePort () -{ - if (fd_ == -1) - { - // Can only operate on a valid file descriptor - throw IOException ("invalid file descriptor"); - } - - struct termios options; // The options for the file descriptor - - 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_oflag &= (unsigned long) ~(OPOST); - options.c_iflag &= (unsigned long) ~(INLCR|IGNCR|ICRNL|IGNBRK); -#ifdef IUCLC - options.c_iflag &= (unsigned long) ~IUCLC; -#endif -#ifdef PARMRK - options.c_iflag &= (unsigned long) ~PARMRK; -#endif - - // setup baud rate - bool custom_baud = false; - speed_t baud; - switch (baudrate_) - { -#ifdef B0 - case 0: baud = B0; break; -#endif -#ifdef B50 - case 50: baud = B50; break; -#endif -#ifdef B75 - case 75: baud = B75; break; -#endif -#ifdef B110 - case 110: baud = B110; break; -#endif -#ifdef B134 - case 134: baud = B134; break; -#endif -#ifdef B150 - case 150: baud = B150; break; -#endif -#ifdef B200 - case 200: baud = B200; break; -#endif -#ifdef B300 - case 300: baud = B300; break; -#endif -#ifdef B600 - case 600: baud = B600; break; -#endif -#ifdef B1200 - case 1200: baud = B1200; break; -#endif -#ifdef B1800 - case 1800: baud = B1800; break; -#endif -#ifdef B2400 - case 2400: baud = B2400; break; -#endif -#ifdef B4800 - case 4800: baud = B4800; break; -#endif -#ifdef B7200 - case 7200: baud = B7200; break; -#endif -#ifdef B9600 - case 9600: baud = B9600; break; -#endif -#ifdef B14400 - case 14400: baud = B14400; break; -#endif -#ifdef B19200 - case 19200: baud = B19200; break; -#endif -#ifdef B28800 - case 28800: baud = B28800; break; -#endif -#ifdef B57600 - case 57600: baud = B57600; break; -#endif -#ifdef B76800 - case 76800: baud = B76800; break; -#endif -#ifdef B38400 - case 38400: baud = B38400; break; -#endif -#ifdef B115200 - case 115200: baud = B115200; break; -#endif -#ifdef B128000 - case 128000: baud = B128000; break; -#endif -#ifdef B153600 - case 153600: baud = B153600; break; -#endif -#ifdef B230400 - case 230400: baud = B230400; break; -#endif -#ifdef B256000 - case 256000: baud = B256000; break; -#endif -#ifdef B460800 - case 460800: baud = B460800; break; -#endif -#ifdef B921600 - case 921600: baud = B921600; break; -#endif - 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 -#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; - - if (ioctl(fd_, TIOCSSERIAL, ser) < 0) - { - throw IOException (errno); - } -#else - throw invalid_argument ("OS does not currently support custom bauds"); -#endif - } - if (custom_baud == false) - { -#ifdef _BSD_SOURCE - ::cfsetspeed(&options, baud); -#else - ::cfsetispeed(&options, baud); - ::cfsetospeed(&options, baud); -#endif - } - - // setup char len - options.c_cflag &= (unsigned long) ~CSIZE; - if (bytesize_ == EIGHTBITS) - options.c_cflag |= CS8; - else if (bytesize_ == SEVENBITS) - options.c_cflag |= CS7; - else if (bytesize_ == SIXBITS) - options.c_cflag |= CS6; - else if (bytesize_ == FIVEBITS) - options.c_cflag |= CS5; - else - throw invalid_argument ("invalid char len"); - // setup stopbits - if (stopbits_ == STOPBITS_ONE) - options.c_cflag &= (unsigned long) ~(CSTOPB); - else if (stopbits_ == STOPBITS_ONE_POINT_FIVE) - options.c_cflag |= (CSTOPB); // XXX same as TWO.. there is no POSIX support for 1.5 - else if (stopbits_ == STOPBITS_TWO) - options.c_cflag |= (CSTOPB); - else - 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_cflag &= (unsigned long) ~(PARODD); - options.c_cflag |= (PARENB); - } - 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) - else - options.c_iflag &= (unsigned long) ~(IXON|IXOFF|IXANY); -#else - if (xonxoff_) - options.c_iflag |= (IXON|IXOFF); - else - options.c_iflag &= (unsigned long) ~(IXON|IXOFF); -#endif - // rtscts -#ifdef CRTSCTS - if (rtscts_) - options.c_cflag |= (CRTSCTS); - else - options.c_cflag &= (unsigned long) ~(CRTSCTS); -#elif defined CNEW_RTSCTS - if (rtscts_) - options.c_cflag |= (CNEW_RTSCTS); - else - options.c_cflag &= (unsigned long) ~(CNEW_RTSCTS); -#else -#error "OS Support seems wrong." -#endif - - options.c_cc[VMIN] = 1; // Minimum of 1 character in the buffer - options.c_cc[VTIME] = 0; // timeout on waiting for new data - - // activate settings - ::tcsetattr (fd_, TCSANOW, &options); -} - -void -Serial::SerialImpl::close () -{ - if (isOpen_ == true) - { - if (fd_ != -1) - { - ::close (fd_); // Ignoring the outcome - fd_ = -1; - } - isOpen_ = false; - } -} - -bool -Serial::SerialImpl::isOpen () const -{ - return isOpen_; -} - -size_t -Serial::SerialImpl::available () -{ - if (!isOpen_) - { - return 0; - } - int count = 0; - int result = ioctl (fd_, TIOCINQ, &count); - if (result == 0) - { - return static_cast (count); - } - else - { - throw IOException (errno); - } -} - -size_t -Serial::SerialImpl::read (char* buf, size_t size) -{ - if (!isOpen_) - { - throw PortNotOpenedException ("Serial::read"); - } - fd_set readfds; - ssize_t bytes_read = 0; - int count = 0; - while (true) - { - count++; - if (timeout_ != -1) - { - FD_ZERO (&readfds); - FD_SET (fd_, &readfds); - struct timeval timeout; - timeout.tv_sec = timeout_ / 1000; - timeout.tv_usec = static_cast (timeout_ % 1000) * 1000; - int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout); - - if (r == -1 && errno == EINTR) - continue; - - if (r == -1) - { - throw IOException (errno); - } - } - - if (timeout_ == -1 || FD_ISSET (fd_, &readfds)) - { - bytes_read = ::read (fd_, buf, size); - // read should always return some data as select reported it was - // ready to read when we get to this point. - if (bytes_read < 1) - { - // Disconnected devices, at least on Linux, show the - // behavior that they are always ready to read immediately - // but reading returns nothing. - throw SerialExecption ("device reports readiness to read but " - "returned no data (device disconnected?)"); - } - break; - } - else - { - break; - } - } - return static_cast (bytes_read); -} - -size_t -Serial::SerialImpl::write (const string &data) -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::write"); - } - - fd_set writefds; - ssize_t bytes_written = 0; - while (true) - { - if (timeout_ != -1) - { - FD_ZERO (&writefds); - FD_SET (fd_, &writefds); - struct timeval timeout; - timeout.tv_sec = timeout_ / 1000; - timeout.tv_usec = static_cast (timeout_ % 1000) * 1000; - int r = select (fd_ + 1, NULL, &writefds, NULL, &timeout); - - if (r == -1 && errno == EINTR) - continue; - - if (r == -1) - { - throw IOException (errno); - } - } - - if (timeout_ == -1 || FD_ISSET (fd_, &writefds)) - { - bytes_written = ::write (fd_, data.c_str (), data.length ()); - // read should always return some data as select reported it was - // ready to read when we get to this point. - if (bytes_written < 1) - { - // Disconnected devices, at least on Linux, show the - // behavior that they are always ready to read immediately - // but reading returns nothing. - throw SerialExecption ("device reports readiness to read but " - "returned no data (device disconnected?)"); - } - break; - } - else - { - break; - } - } - - return static_cast (bytes_written); -} - -void -Serial::SerialImpl::setPort (const string &port) -{ - port_ = port; -} - -string -Serial::SerialImpl::getPort () const -{ - return port_; -} - -void -Serial::SerialImpl::setTimeout (long timeout) -{ - timeout_ = timeout; -} - -long -Serial::SerialImpl::getTimeout () const -{ - return timeout_; -} - -void -Serial::SerialImpl::setBaudrate (unsigned long baudrate) -{ - baudrate_ = baudrate; - if (isOpen_) - reconfigurePort (); -} - -unsigned long -Serial::SerialImpl::getBaudrate () const -{ - return baudrate_; -} - -void -Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize) -{ - bytesize_ = bytesize; - if (isOpen_) - reconfigurePort (); -} - -serial::bytesize_t -Serial::SerialImpl::getBytesize () const -{ - return bytesize_; -} - -void -Serial::SerialImpl::setParity (serial::parity_t parity) -{ - parity_ = parity; - if (isOpen_) - reconfigurePort (); -} - -serial::parity_t -Serial::SerialImpl::getParity () const -{ - return parity_; -} - -void -Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits) -{ - stopbits_ = stopbits; - if (isOpen_) - reconfigurePort (); -} - -serial::stopbits_t -Serial::SerialImpl::getStopbits () const -{ - return stopbits_; -} - -void -Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol) -{ - flowcontrol_ = flowcontrol; - if (isOpen_) - reconfigurePort (); -} - -serial::flowcontrol_t -Serial::SerialImpl::getFlowcontrol () const -{ - return flowcontrol_; -} - -void -Serial::SerialImpl::flush () -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::flush"); - } - tcdrain (fd_); -} - -void -Serial::SerialImpl::flushInput () -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::flushInput"); - } - tcflush (fd_, TCIFLUSH); -} - -void -Serial::SerialImpl::flushOutput () -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::flushOutput"); - } - tcflush (fd_, TCOFLUSH); -} - -void -Serial::SerialImpl::sendBreak (int duration) -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::sendBreak"); - } - tcsendbreak (fd_, static_cast (duration/4)); -} - -void -Serial::SerialImpl::setBreak (bool level) -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::setBreak"); - } - if (level) - { - ioctl (fd_, TIOCSBRK); - } - else { - ioctl (fd_, TIOCCBRK); - } -} - -void -Serial::SerialImpl::setRTS (bool level) -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::setRTS"); - } - if (level) - { - ioctl (fd_, TIOCMBIS, TIOCM_RTS); - } - else { - ioctl (fd_, TIOCMBIC, TIOCM_RTS); - } -} - -void -Serial::SerialImpl::setDTR (bool level) -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::setDTR"); - } - if (level) - { - ioctl (fd_, TIOCMBIS, TIOCM_DTR); - } - else - { - ioctl (fd_, TIOCMBIC, TIOCM_DTR); - } -} - -bool -Serial::SerialImpl::getCTS () -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::getCTS"); - } - int s = ioctl (fd_, TIOCMGET, 0); - return (s & TIOCM_CTS) != 0; -} - -bool -Serial::SerialImpl::getDSR() -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::getDSR"); - } - int s = ioctl(fd_, TIOCMGET, 0); - return (s & TIOCM_DSR) != 0; -} - -bool -Serial::SerialImpl::getRI() -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::getRI"); - } - int s = ioctl (fd_, TIOCMGET, 0); - return (s & TIOCM_RI) != 0; -} - -bool -Serial::SerialImpl::getCD() -{ - if (isOpen_ == false) - { - throw PortNotOpenedException ("Serial::getCD"); - } - int s = ioctl (fd_, TIOCMGET, 0); - return (s & TIOCM_CD) != 0; -} - diff --git a/src/serial.cc b/src/serial.cc index d391202..67336bc 100644 --- a/src/serial.cc +++ b/src/serial.cc @@ -48,7 +48,7 @@ private: SerialImpl *pimpl_; }; -Serial::Serial (const string &port, unsigned long baudrate, Timeout timeout, +Serial::Serial (const string &port, uint32_t baudrate, Timeout timeout, bytesize_t bytesize, parity_t parity, stopbits_t stopbits, flowcontrol_t flowcontrol) : read_cache_("") @@ -88,23 +88,23 @@ Serial::available () } size_t -Serial::read_ (unsigned char *buffer, size_t size) +Serial::read_ (uint8_t *buffer, size_t size) { return this->pimpl_->read (buffer, size); } size_t -Serial::read (unsigned char *buffer, size_t size) +Serial::read (uint8_t *buffer, size_t size) { ScopedReadLock (this->pimpl_); return this->pimpl_->read (buffer, size); } size_t -Serial::read (std::vector &buffer, size_t size) +Serial::read (std::vector &buffer, size_t size) { ScopedReadLock (this->pimpl_); - unsigned char *buffer_ = new unsigned char[size]; + uint8_t *buffer_ = new uint8_t[size]; size_t bytes_read = this->pimpl_->read (buffer_, size); buffer.insert (buffer.end (), buffer_, buffer_+bytes_read); delete[] buffer_; @@ -115,7 +115,7 @@ size_t Serial::read (std::string &buffer, size_t size) { ScopedReadLock (this->pimpl_); - unsigned char *buffer_ = new unsigned char[size]; + uint8_t *buffer_ = new uint8_t[size]; size_t bytes_read = this->pimpl_->read (buffer_, size); buffer.append (reinterpret_cast(buffer_), bytes_read); delete[] buffer_; @@ -135,8 +135,8 @@ Serial::readline (string &buffer, size_t size, string eol) { ScopedReadLock (this->pimpl_); size_t eol_len = eol.length (); - unsigned char *buffer_ = static_cast - (alloca (size * sizeof (unsigned char))); + uint8_t *buffer_ = static_cast + (alloca (size * sizeof (uint8_t))); size_t read_so_far = 0; while (true) { @@ -171,8 +171,8 @@ Serial::readlines (size_t size, string eol) ScopedReadLock (this->pimpl_); std::vector lines; size_t eol_len = eol.length (); - unsigned char *buffer_ = static_cast - (alloca (size * sizeof (unsigned char))); + uint8_t *buffer_ = static_cast + (alloca (size * sizeof (uint8_t))); size_t read_so_far = 0; size_t start_of_line = 0; while (read_so_far < size) { @@ -210,7 +210,28 @@ size_t Serial::write (const string &data) { ScopedWriteLock(this->pimpl_); - return pimpl_->write (data); + return this->write_ (reinterpret_cast(data.c_str()), + data.length()); +} + +size_t +Serial::write (const std::vector &data) +{ + ScopedWriteLock(this->pimpl_); + return this->write_ (&data[0], data.size()); +} + +size_t +Serial::write (const uint8_t *data, size_t size) +{ + ScopedWriteLock(this->pimpl_); + return this->write_(data, size); +} + +size_t +Serial::write_ (const uint8_t *data, size_t length) +{ + return pimpl_->write (data, length); } void @@ -242,15 +263,15 @@ Serial::getTimeout () const { } void -Serial::setBaudrate (unsigned long baudrate) +Serial::setBaudrate (uint32_t baudrate) { pimpl_->setBaudrate (baudrate); } -unsigned long +uint32_t Serial::getBaudrate () const { - return pimpl_->getBaudrate (); + return uint32_t(pimpl_->getBaudrate ()); } void