diff options
| author | Ján Sučan <sucanjan@fit.cvut.cz> | 2017-05-10 15:13:29 +0200 |
|---|---|---|
| committer | Ján Sučan <sucanjan@fit.cvut.cz> | 2017-05-10 15:13:29 +0200 |
| commit | 02e24f0f533fe904c3a5275c4060c10c38d7c17a (patch) | |
| tree | 19d05c60e3d6a6782c4712de960a8f6705054063 /SerialPort | |
Uvodny commit, subory su rovnake ako na CD prilozenom k vytlacenemu texu bakalarskej prace, naviac je pridany len subor LICENCIA
Diffstat (limited to 'SerialPort')
| -rwxr-xr-x | SerialPort/CMakeLists.txt | 19 | ||||
| -rwxr-xr-x | SerialPort/SerialPort.cpp | 157 | ||||
| -rwxr-xr-x | SerialPort/SerialPort.hpp | 37 | ||||
| -rwxr-xr-x | SerialPort/SerialPortFactory.cpp | 21 | ||||
| -rwxr-xr-x | SerialPort/SerialPortFactory.hpp | 13 | ||||
| -rwxr-xr-x | SerialPort/SerialPortUnix.cpp | 285 | ||||
| -rwxr-xr-x | SerialPort/SerialPortUnix.hpp | 35 | ||||
| -rwxr-xr-x | SerialPort/SerialPortWin32.cpp | 238 | ||||
| -rwxr-xr-x | SerialPort/SerialPortWin32.hpp | 49 |
9 files changed, 854 insertions, 0 deletions
diff --git a/SerialPort/CMakeLists.txt b/SerialPort/CMakeLists.txt new file mode 100755 index 0000000..dc7aa6b --- /dev/null +++ b/SerialPort/CMakeLists.txt @@ -0,0 +1,19 @@ +if (WIN32) + add_library (SerialPort STATIC + SerialPortFactory.cpp + SerialPort.cpp + SerialPortWin32.cpp + ) +else() + add_library (SerialPort STATIC + SerialPortFactory.cpp + SerialPort.cpp + SerialPortUnix.cpp + ) +endif() + +set_target_properties (SerialPort PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF +) diff --git a/SerialPort/SerialPort.cpp b/SerialPort/SerialPort.cpp new file mode 100755 index 0000000..93e9d20 --- /dev/null +++ b/SerialPort/SerialPort.cpp @@ -0,0 +1,157 @@ +#include "SerialPort.hpp" +#include "Logger.hpp" +#include "ExitException.hpp" +#include "ExitCodes.hpp" +#include <cstring> +#include <sstream> + +using std::ostringstream; + +#define READ_DEFAULT_TIMEOUT 3000 // ms + +void +CSerialPort::writeWord(uint16_t w) +{ + uint8_t b; + + b = (w & 0xff); + this->write(&b, 1, 1); + + b = (w & 0xff00) >> 8; + this->write(&b, 1, 1); +} + +uint16_t +CSerialPort::readWord() +{ + uint8_t b; + uint16_t w; + + w = 0; + + this->read(&b, 1); + w |= ((uint16_t) b); + + this->read(&b, 1); + w |= ((uint16_t) b) << 8; + + return w; +} + +uint32_t +CSerialPort::readDoubleWord() +{ + uint8_t b; + uint32_t dw; + + dw = 0; + + this->read(&b, 1); + dw |= ((uint32_t) b); + + this->read(&b, 1); + dw |= ((uint32_t) b) << 8; + + this->read(&b, 1); + dw |= ((uint32_t) b) << 16; + + this->read(&b, 1); + dw |= ((uint32_t) b) << 24; + + return dw; +} + +void +CSerialPort::setReadTimeout(int timetout) +{ + mReadTimeoutMs = timetout; +} + +void +CSerialPort::setDefaultTimeout() +{ + mReadTimeoutMs = READ_DEFAULT_TIMEOUT; +} + +void +CSerialPort::write(uint8_t *data, int data_length, int padd_to) +{ + // Write data + for (int i = 0; i < data_length; ) + i += writeSingle(data, data_length); + // Write pad + // TODO: odkial brat hodnotu pad byte?? + uint8_t p[512]; + memset(p, 0xFF, 512); + + for (padd_to -= data_length; padd_to > 0; ) { + int w = 512; + if (padd_to < 512) + w = padd_to; + padd_to -= writeSingle(p, w); + } +} + +void +CSerialPort::read(uint8_t *data, int data_length) +{ + for (int i = 0; i < data_length; ) { + int old_i = i; + i += readSingle(data + i, data_length - i); + // TODO: pre Win32, pretoze tam nedetekujeme timeout a moze vracat 0 bajtov precitanych + if (i == old_i) { + CLogger::error("Timeout occured while reading data from serial port", EXIT_SERIAL_PORT); + } + } +} + +void +CSerialPort::sendSafeByte(uint8_t b) +{ + uint8_t r; + + this->write(&b, 1, 1); + this->read(&r, 1); + if (r != b) { + ostringstream os; + os << "Bad echo when sending byte safely, expected " << CLogger::decToHex(b); + os << " received " << CLogger::decToHex(r); + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } + this->write(&b, 1, 1); + this->read(&r, 1); + if (r != 0x00) { + ostringstream os; + os << "Cannot send byte safely, expected 0x00 received " << CLogger::decToHex(r); + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } +} + +void +CSerialPort::sendSafeWord(uint16_t w) +{ + this->writeWord(w); + uint16_t r = this->readWord(); + if (r != w) { + ostringstream os; + os << "Bad echo when sending word safely, expected " << CLogger::decToHex(w); + os << " received " << CLogger::decToHex(r); + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } + this->writeWord(w); + r = this->readWord(); + if (r != 0x00) { + ostringstream os; + os << "Cannot send word safely, expected 0x0000 received " << CLogger::decToHex(r); + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } +} + +void +CSerialPort::sendSafeDoubleWord(uint32_t w) +{ + // Send low word + sendSafeWord(w & 0x0000FFFF); + // Send high word + sendSafeWord((w & 0xFFFF0000) >> 16); +} diff --git a/SerialPort/SerialPort.hpp b/SerialPort/SerialPort.hpp new file mode 100755 index 0000000..90bb87f --- /dev/null +++ b/SerialPort/SerialPort.hpp @@ -0,0 +1,37 @@ +#ifndef SERIAL_PORT_H +#define SERIAL_PORT_H 1 + +#include <iostream> +#include <cstdint> + +using std::string; + +class CSerialPort { +protected: + int mReadTimeoutMs; // Miliseconds + + virtual ssize_t readSingle(uint8_t *data, int data_length) = 0; + virtual ssize_t writeSingle(uint8_t *data, int data_length) = 0; +public: + virtual ~CSerialPort() { ; }; + + virtual void open(string portName, string speed) = 0; + virtual string getSpeeds(string portName) = 0; + + virtual void close() = 0; + + void setReadTimeout(int ms); + void setDefaultTimeout(); + + void writeWord(uint16_t w); + uint16_t readWord(); + uint32_t readDoubleWord(); + void read(uint8_t *data, int data_length); + void write(uint8_t *data, int data_length, int padd); + void sendSafeByte(uint8_t b); + void sendSafeWord(uint16_t w); + void sendSafeDoubleWord(uint32_t w); + +}; + +#endif diff --git a/SerialPort/SerialPortFactory.cpp b/SerialPort/SerialPortFactory.cpp new file mode 100755 index 0000000..a7e8e9f --- /dev/null +++ b/SerialPort/SerialPortFactory.cpp @@ -0,0 +1,21 @@ +#include "SerialPortFactory.hpp" + +#ifdef WIN32 +#include "SerialPortWin32.hpp" +#else +#include "SerialPortUnix.hpp" +#endif + +std::unique_ptr<CSerialPort> +CSerialPortFactory::getSerialPort() +{ + std::unique_ptr<CSerialPort> sp; + +#ifdef WIN32 + sp.reset(new CSerialPortWin32()); +#else + sp.reset(new CSerialPortUnix()); +#endif + + return sp; +} diff --git a/SerialPort/SerialPortFactory.hpp b/SerialPort/SerialPortFactory.hpp new file mode 100755 index 0000000..7cecc8c --- /dev/null +++ b/SerialPort/SerialPortFactory.hpp @@ -0,0 +1,13 @@ +#ifndef SERIAL_PORT_FACTORY_HPP +#define SERIAL_PORT_FACTORY_HPP 1 + +#include <memory> + +#include "SerialPort.hpp" + +class CSerialPortFactory { +public: + std::unique_ptr<CSerialPort> getSerialPort(); +}; + +#endif diff --git a/SerialPort/SerialPortUnix.cpp b/SerialPort/SerialPortUnix.cpp new file mode 100755 index 0000000..20fba2e --- /dev/null +++ b/SerialPort/SerialPortUnix.cpp @@ -0,0 +1,285 @@ +#include <stdio.h> +#include <string.h> /* String function definitions */ +#include <unistd.h> /* UNIX standard function definitions */ +#include <fcntl.h> /* File control definitions */ +#include <errno.h> /* Error number definitions */ +#include <termios.h> +#include <sys/select.h> +#include <errno.h> + +#include <sstream> +#include <iostream> +#include <iomanip> + +using std::ostringstream; +using std::endl; +using std::setw; +using std::right; + +#include "ExitCodes.hpp" +#include "SerialPortUnix.hpp" +#include "Logger.hpp" +#include "ExitException.hpp" + +#define DEFAULT_SERIAL_SPEED "19200" + +CSerialPortUnix::CSerialPortUnix() +{ + mSerialPortFd = -1; + mPortName = ""; + // Construct vector of available system baudrates +#ifdef B50 + mBaudrates.push_back(pair<string, speed_t>("50", B50)); +#endif +#ifdef B75 + mBaudrates.push_back(pair<string, speed_t>("75", B75)); +#endif +#ifdef B110 + mBaudrates.push_back(pair<string, speed_t>("110", B110)); +#endif +#ifdef B134 + mBaudrates.push_back(pair<string, speed_t>("134", B134)); +#endif +#ifdef B150 + mBaudrates.push_back(pair<string, speed_t>("150", B150)); +#endif +#ifdef B200 + mBaudrates.push_back(pair<string, speed_t>("200", B200)); +#endif +#ifdef B300 + mBaudrates.push_back(pair<string, speed_t>("300", B300)); +#endif +#ifdef B600 + mBaudrates.push_back(pair<string, speed_t>("600", B600)); +#endif +#ifdef B1200 + mBaudrates.push_back(pair<string, speed_t>("1200", B1200)); +#endif +#ifdef B1800 + mBaudrates.push_back(pair<string, speed_t>("1800", B1800)); +#endif +#ifdef B2400 + mBaudrates.push_back(pair<string, speed_t>("2400", B2400)); +#endif +#ifdef B4800 + mBaudrates.push_back(pair<string, speed_t>("4800", B4800)); +#endif +#ifdef B9600 + mBaudrates.push_back(pair<string, speed_t>("9600", B9600)); +#endif +#ifdef B19200 + mBaudrates.push_back(pair<string, speed_t>("19200", B19200)); +#endif +#ifdef B38400 + mBaudrates.push_back(pair<string, speed_t>("38400", B38400)); +#endif +#ifdef B57600 + mBaudrates.push_back(pair<string, speed_t>("57600", B57600)); +#endif +#ifdef B115200 + mBaudrates.push_back(pair<string, speed_t>("115200", B115200)); +#endif +#ifdef B230400 + mBaudrates.push_back(pair<string, speed_t>("230400", B230400)); +#endif +} + +CSerialPortUnix::~CSerialPortUnix() +{ + ; +} + +void +CSerialPortUnix::openPort(string portName) +{ + if (mSerialPortFd == -1) { + mSerialPortFd = ::open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + if (mSerialPortFd == -1) + CLogger::error("Cannot open serial port " + portName, EXIT_SERIAL_PORT); + mPortName = portName; + } +} + +void +CSerialPortUnix::open(string portName, string speed) +{ + this->setDefaultTimeout(); + + openPort(portName); + // Set parameters of serial communication + pair<string, speed_t> s = findSpeed(speed, getDeviceSpeeds()); + setSpeed(s); + + struct termios options; + + tcgetattr(mSerialPortFd, &options); + // Control options + options.c_cflag |= (CLOCAL | CREAD); + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + // Turn off hardware flow controll + options.c_cflag &= ~CRTSCTS; + // Input Options - Turn off software flow controll, and CR <-> LF mapping + options.c_iflag &= ~(IXON | IXOFF | IXANY | INLCR | ICRNL); + // Line options - Raw input + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + // Raw output + options.c_oflag &= ~OPOST; + tcsetattr(mSerialPortFd, TCSANOW, &options); + // Blocking read + fcntl(mSerialPortFd, F_SETFL, 0); + + CLogger::info("Serial port " + mPortName + " opened at speed " + s.first + " Bd"); +} + +void +CSerialPortUnix::close() +{ + // Close only valid descriptor + if (mSerialPortFd != -1) { + if (::close(mSerialPortFd) == -1) + CLogger::error("Cannot close serial port", EXIT_SERIAL_PORT); + mSerialPortFd = -1; + mPortName = ""; + } +} + +vector<pair<string, speed_t>> +CSerialPortUnix::getDeviceSpeeds() +{ + vector<pair<string, speed_t>> ds; + vector<pair<string, speed_t>>::const_iterator it; + + // Test which baudrates are supported by underlying device + for (it = mBaudrates.begin(); it != mBaudrates.end(); ++it) { + // Try to set the baudrate + struct termios options; + + if (tcgetattr(mSerialPortFd, &options) != 0) + CLogger::error("Cannot get attributes of serial port " + mPortName, EXIT_SERIAL_PORT); + + if (!cfsetispeed(&options, it->second) + && !cfsetospeed(&options, it->second) + && !tcsetattr(mSerialPortFd, TCSANOW, &options)) { + ds.push_back(*it); + } + } + + return ds; +} + +string +CSerialPortUnix::getSpeeds(string portName) +{ + ostringstream os; + int c; + vector<pair<string, speed_t>> s; + vector<pair<string, speed_t>>::const_iterator it; + + openPort(portName); + s = getDeviceSpeeds(); + for (c = 0, it = s.begin(); it != s.end(); ++c, ++it) + os << setw(7) << right << it->first << " Bd" << endl; + // Close serial port + close(); + + if (c == 0) + CLogger::error("Serial port device does not support any baudrates", EXIT_SERIAL_PORT); + + return os.str(); +} + +pair<string, speed_t> +CSerialPortUnix::findSpeed(string speed, const vector<pair<string, speed_t>> & list) +{ + vector<pair<string, speed_t>>::const_iterator it; + vector<pair<string, speed_t>>::const_iterator defit; + bool foundDef = false; + + for (it = list.begin(); it != list.end(); ++it) { + if (!(it->first).compare(speed)) + return *it; // Exact match + else if (!(it->first).compare(DEFAULT_SERIAL_SPEED)) { + defit = it; // We have found default serial speed + foundDef = true; + } + } + + if (foundDef) + // We have not found exact speed and default speed. Choose + // highest supported. + return *defit; + + return *(it - 1); +} + +void +CSerialPortUnix::setSpeed(pair<string, speed_t> speed) +{ + struct termios options; + + if (tcgetattr(mSerialPortFd, &options) + || cfsetispeed(&options, speed.second) + || cfsetospeed(&options, speed.second) + || tcsetattr(mSerialPortFd, TCSANOW, &options)) { + CLogger::error("Cannot set serial speed: " + speed.first + ": " + strerror(errno), EXIT_SERIAL_PORT); + } +} + + +ssize_t +CSerialPortUnix::writeSingle(uint8_t *data, int data_length) +{ + ssize_t r = ::write(mSerialPortFd, data, data_length); + + if (r <= 0) { + ostringstream os; + os << "Cannot write to serial port"; + if (r < 0) + os << ": " << string(strerror(errno)); + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } + + return r; +} + +ssize_t +CSerialPortUnix::readSingle(uint8_t *data, int data_length) +{ + ssize_t r = 0; + int s; + fd_set read_fds, write_fds, except_fds; + struct timeval timeout; + + // Renew file descriptor sets + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); + FD_SET(mSerialPortFd, &read_fds); + // Set timeout + timeout.tv_sec = mReadTimeoutMs / 1000; + timeout.tv_usec = 0; + // Wait for event + s = select(mSerialPortFd + 1, &read_fds, &write_fds, &except_fds, &timeout); + if (s == 1) { + // One descriptor changed, ready to read + r = ::read(mSerialPortFd, data, data_length); + } else if (s == 0) { + // Timeout occured + CLogger::error("Timeout occured while reading data from serial port", EXIT_SERIAL_PORT); + } + + if ((s < 0) || (r <= 0)) { + // Error occured in select or read + ostringstream os; + os << "Cannot read from serial port"; + if (r < 0) { + os << ": " << strerror(errno); + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } + } + + return r; +} diff --git a/SerialPort/SerialPortUnix.hpp b/SerialPort/SerialPortUnix.hpp new file mode 100755 index 0000000..db1ae73 --- /dev/null +++ b/SerialPort/SerialPortUnix.hpp @@ -0,0 +1,35 @@ +#ifndef SERIAL_PORT_UNIX_H +#define SERIAL_PORT_UNIX_H 1 + +#include <termios.h> + +#include <vector> +#include "SerialPort.hpp" + +using std::vector; +using std::pair; + +class CSerialPortUnix : public CSerialPort { +private: + int mSerialPortFd; + string mPortName; + vector< pair<string, speed_t> > mBaudrates; + + vector<pair<string, speed_t>> getDeviceSpeeds(); + pair<string, speed_t> findSpeed(string speed, const vector<pair<string, speed_t>> & list); + void setSpeed(pair<string, speed_t> speed); + void openPort(string portName); + + ssize_t readSingle(uint8_t *data, int data_length); + ssize_t writeSingle(uint8_t *data, int data_length); +public: + CSerialPortUnix(); + ~CSerialPortUnix(); + + void open(string portName, string speed); + string getSpeeds(string portName); + + void close(); +}; + +#endif diff --git a/SerialPort/SerialPortWin32.cpp b/SerialPort/SerialPortWin32.cpp new file mode 100755 index 0000000..15316d2 --- /dev/null +++ b/SerialPort/SerialPortWin32.cpp @@ -0,0 +1,238 @@ +#include <sstream> +#include <cstdio> + +#include "ExitCodes.hpp" +#include "SerialPortWin32.hpp" +#include "Logger.hpp" + +using std::ostringstream; +using std::istringstream; + +//Returns the last Win32 error, in string format. Returns an empty string if there is no error. +string +CSerialPortWin32::getLastErrorAsString() +{ + DWORD e = GetLastError(); + if (e == 0) + return string(); + + LPSTR msgBuff = nullptr; + size_t size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + e, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &msgBuff, + 0, + NULL); + + string m(msgBuff, size); + + LocalFree(msgBuff); + + return m; +} + + + + +CSerialPortWin32::CSerialPortWin32() +{ + mSerialPortH = INVALID_HANDLE_VALUE; + + mMaxBaudrates.push_back(s_speed("User defined", BAUD_USER, 0)); + mMaxBaudrates.push_back(s_speed("75", BAUD_075, 75)); + mMaxBaudrates.push_back(s_speed("110", BAUD_110, 110)); + mMaxBaudrates.push_back(s_speed("134.5", BAUD_134_5, 134)); + mMaxBaudrates.push_back(s_speed("150", BAUD_150, 150)); + mMaxBaudrates.push_back(s_speed("300", BAUD_300, 300)); + mMaxBaudrates.push_back(s_speed("600", BAUD_600, 600)); + mMaxBaudrates.push_back(s_speed("1200", BAUD_1200, 1200)); + mMaxBaudrates.push_back(s_speed("1800", BAUD_1800, 1800)); + mMaxBaudrates.push_back(s_speed("2400", BAUD_2400, 2400)); + mMaxBaudrates.push_back(s_speed("4800", BAUD_4800, 4800)); + mMaxBaudrates.push_back(s_speed("7200", BAUD_7200, 7200)); + mMaxBaudrates.push_back(s_speed("9600", BAUD_9600, 9600)); + mMaxBaudrates.push_back(s_speed("14400", BAUD_14400, 14400)); + mMaxBaudrates.push_back(s_speed("19200", BAUD_19200, 19200)); + mMaxBaudrates.push_back(s_speed("38400", BAUD_38400, 38400)); + mMaxBaudrates.push_back(s_speed("56000", BAUD_56K, 56000)); + mMaxBaudrates.push_back(s_speed("57600", BAUD_57600, 576000)); + mMaxBaudrates.push_back(s_speed("115200", BAUD_115200, 115200)); + mMaxBaudrates.push_back(s_speed("128000", BAUD_128K, 128000)); +} + +CSerialPortWin32::~CSerialPortWin32() +{ + ; +} + +void +CSerialPortWin32::openPort(string portName) +{ + if (mSerialPortH == INVALID_HANDLE_VALUE) { + // Construct Windows serial port name + ostringstream sn; + sn << "\\\\.\\" << portName; + // Open serial port + mSerialPortH = CreateFile(sn.str().c_str(), // Port name + GENERIC_READ | GENERIC_WRITE, // Read/Write + 0, // No Sharing + NULL, // No Security + OPEN_EXISTING,// Open existing port only + 0, // Non Overlapped I/O + NULL); // Null for Comm Devices + + if (mSerialPortH == INVALID_HANDLE_VALUE) { + CLogger::error("Cannot open port " + portName + ": " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + } +} + +void +CSerialPortWin32::open(string portName, string speed) +{ + this->setDefaultTimeout(); + + openPort(portName); + + DWORD ms = getMaxSpeed(portName).value; + + // Konfiguracia + DCB dcbSerialParams = { 0 }; + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + + if (GetCommState(mSerialPortH, &dcbSerialParams) == 0) { + CLogger::error("Cannot get state for port " + portName + ": " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + // Set speed + istringstream is(speed); + DWORD n; + is >> n; + if (n == 0) { + // User has requested default baudrate + n = ((ms == 0) || (19200 <= ms)) ? 19200 : ms; + } else if ((ms != 0) && (n > ms)) { + ostringstream os; + os << "Baudrate " << n << " Bd is higher than max. baudrate " << ms << " Bd supported by " << portName; + CLogger::error(os.str(), EXIT_SERIAL_PORT); + } + + dcbSerialParams.BaudRate = n; + dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8 + dcbSerialParams.StopBits = ONESTOPBIT;// Setting StopBits = 1 + dcbSerialParams.Parity = NOPARITY; // Setting Parity = None + + if (SetCommState(mSerialPortH, &dcbSerialParams) == 0) { + CLogger::error("Cannot set state for port " + portName + ": " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + + ostringstream os; + os << n; + CLogger::info("Serial port " + portName + " opened at speed " + os.str() + " Bd"); +} + +CSerialPortWin32::s_speed +CSerialPortWin32::getMaxSpeed(string portName) +{ + COMMPROP cp; + + if (GetCommProperties(mSerialPortH, &cp) == 0) { + CLogger::error("Cannot get properties of " + portName + " port: " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + + // Convert key to baudrate value + list<s_speed>::const_iterator it; + + for (it = mMaxBaudrates.begin(); it != mMaxBaudrates.end(); ++it) { + if (it->key == cp.dwMaxBaud) + break; + } + + return *it; +} + +string +CSerialPortWin32::getSpeeds(string portName) +{ + openPort(portName); + + s_speed m = getMaxSpeed(portName); + + ostringstream os; + os << "User defined baudrate"; + if (m.key != BAUD_USER) + os << " up to the " << m.name << " Bd"; + + close(); + return os.str(); +} + +void +CSerialPortWin32::close() +{ + if (mSerialPortH != INVALID_HANDLE_VALUE) { + if (CloseHandle(mSerialPortH) == 0) { + CLogger::error("Cannot close serial port: " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + mSerialPortH = INVALID_HANDLE_VALUE; + } +} + +void +CSerialPortWin32::setTimeouts(int ms) +{ + COMMTIMEOUTS timeouts; + + if (!GetCommTimeouts(mSerialPortH, &timeouts)) { + CLogger::error("Cannot get timeouts for serial port: " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + + timeouts.ReadIntervalTimeout = ms; + timeouts.ReadTotalTimeoutMultiplier = ms; + timeouts.ReadTotalTimeoutConstant = 0; + + timeouts.WriteTotalTimeoutMultiplier = ms; + timeouts.WriteTotalTimeoutConstant = 0; + + if (!SetCommTimeouts(mSerialPortH, &timeouts)) { + CLogger::error("Cannot set timeouts for port: " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } +} + +ssize_t +CSerialPortWin32::writeSingle(uint8_t *data, int data_length) +{ + DWORD written = 0; + + setTimeouts(mReadTimeoutMs); + // TODO: Rozlisovat medzi timeoutom a chybou + if (!WriteFile(mSerialPortH, data, data_length, &written, NULL)) { + CLogger::error("Cannot write data to the serial port: " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + + return written; +} + +ssize_t +CSerialPortWin32::readSingle(uint8_t *data, int data_length) +{ + DWORD read; + + setTimeouts(mReadTimeoutMs); + + if (!ReadFile(mSerialPortH, data, data_length, &read, NULL)) { + CLogger::error("Cannot read data from serial port: " + getLastErrorAsString(), + EXIT_SERIAL_PORT); + } + + return read; +} diff --git a/SerialPort/SerialPortWin32.hpp b/SerialPort/SerialPortWin32.hpp new file mode 100755 index 0000000..2cba0f7 --- /dev/null +++ b/SerialPort/SerialPortWin32.hpp @@ -0,0 +1,49 @@ +#ifndef SERIAL_PORT_WIN32_H +#define SERIAL_PORT_WIN32_H 1 + +#include <windows.h> +#include <list> +#include "SerialPort.hpp" + +using std::pair; +using std::list; + +class CSerialPortWin32 : public CSerialPort { +private: + HANDLE mSerialPortH; + + struct s_speed { + string name; + DWORD key; + DWORD value; + + s_speed(string n, DWORD k, DWORD v) { + name = n; + key = k; + value = v; + } + }; + + list<struct s_speed> mMaxBaudrates; + + + void openPort(string portName); + s_speed getMaxSpeed(string portName); + void setTimeouts(int ms); + string getLastErrorAsString(); + + ssize_t readSingle(uint8_t *data, int data_length); + ssize_t writeSingle(uint8_t *data, int data_length); +public: + CSerialPortWin32(); + ~CSerialPortWin32(); + + void open(string portName, string speed); + string getSpeeds(string portName); + + void close(); + void write(uint8_t *data, int data_length, int padd_to); + void read(uint8_t *data, int data_length); +}; + +#endif |
