From aa306d913197159b98db89431d9172f83b6bbb60 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 8 Feb 2015 10:06:03 +0100 Subject: [PATCH] reworked and optimized device handling and check network device address, log failed device open, avoid blocking threads with sleep(), optimized shutdown --- src/ebusd/bushandler.cpp | 21 +- src/ebusd/bushandler.h | 15 +- src/ebusd/main.cpp | 22 +- src/ebusd/mainloop.cpp | 47 ++- src/ebusd/mainloop.h | 16 +- src/ebusd/network.cpp | 7 +- src/ebusd/network.h | 3 +- src/lib/ebus/Makefile.am | 4 +- src/lib/ebus/device.cpp | 295 +++++++++++++++ src/lib/ebus/device.h | 244 +++++++++++++ src/lib/ebus/port.cpp | 338 ------------------ src/lib/ebus/port.h | 296 --------------- src/lib/ebus/test/Makefile.am | 6 +- .../test/{test_port.cpp => test_device.cpp} | 47 +-- src/lib/utils/thread.cpp | 3 +- src/tools/ebusctl.cpp | 3 +- src/tools/ebusfeed.cpp | 32 +- 17 files changed, 664 insertions(+), 735 deletions(-) create mode 100644 src/lib/ebus/device.cpp create mode 100644 src/lib/ebus/device.h delete mode 100644 src/lib/ebus/port.cpp delete mode 100644 src/lib/ebus/port.h rename src/lib/ebus/test/{test_port.cpp => test_device.cpp} (50%) diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 15827901..dfb9d7bf 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -23,6 +23,7 @@ #include "result.h" #include "symbol.h" #include "log.h" +#include #include #include #include @@ -171,18 +172,18 @@ result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) void BusHandler::run() { do { - if (m_port->isOpen() == true) + if (m_device->isValid() == true) handleSymbol(); else { - // TODO define max reopen - sleep(10); - result_t result = m_port->open(); - - if (result != RESULT_OK) - logError(lf_bus, "can't open %s", m_port->getDeviceName()); + if (Wait(10) == false) + break; + result_t result = m_device->open(); + if (result == RESULT_OK) + logNotice(lf_bus, "re-opened %s", m_device->getName()); + else + logError(lf_bus, "unable to open %s: %s", m_device->getName(), getResultCode(result)); } - } while (isRunning() == true); } @@ -289,7 +290,7 @@ result_t BusHandler::handleSymbol() // send symbol if necessary result_t result; if (sending == true) { - result = m_port->send(sendSymbol); + result = m_device->send(sendSymbol); if (result == RESULT_OK) if (m_state == bs_ready) timeout = m_busAcquireTimeout; @@ -304,7 +305,7 @@ result_t BusHandler::handleSymbol() // receive next symbol (optionally check reception of sent symbol) unsigned char recvSymbol; - result = m_port->recv(timeout, recvSymbol); + result = m_device->recv(timeout, recvSymbol); time_t now; time(&now); diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index c0575e18..f823736b 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -24,7 +24,7 @@ #include "data.h" #include "symbol.h" #include "result.h" -#include "port.h" +#include "device.h" #include "wqueue.h" #include "thread.h" #include @@ -244,13 +244,13 @@ private: /** * Handles input from and output to the bus with respect to the eBUS protocol. */ -class BusHandler : public Thread +class BusHandler : public WaitThread { public: /** * Construct a new instance. - * @param port the @a Port instance for accessing the bus. + * @param device the @a Device instance for accessing the bus. * @param messages the @a MessageMap instance with all known @a Message instances. * @param ownAddress the own master address. * @param answer whether to answer queries for the own master/slave address. @@ -261,12 +261,12 @@ public: * @param lockCount the number of AUTO-SYN symbols before sending is allowed after lost arbitration. * @param pollInterval the interval in seconds in which poll messages are cycled, or 0 if disabled. */ - BusHandler(Port* port, MessageMap* messages, + BusHandler(Device* device, MessageMap* messages, const unsigned char ownAddress, const bool answer, const unsigned int busLostRetries, const unsigned int failedSendRetries, const unsigned int busAcquireTimeout, const unsigned int slaveRecvTimeout, const unsigned int lockCount, const unsigned int pollInterval) - : m_port(port), m_messages(messages), + : m_device(device), m_messages(messages), m_ownMasterAddress(ownAddress), m_ownSlaveAddress((ownAddress+5)&0xff), m_answer(answer), m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout), @@ -283,6 +283,7 @@ public: * Destructor. */ virtual ~BusHandler() { + stop(); if (m_scanMessage != NULL) delete m_scanMessage; } @@ -348,8 +349,8 @@ private: */ void receiveCompleted(); - /** the @a Port instance for accessing the bus. */ - Port* m_port; + /** the @a Device instance for accessing the bus. */ + Device* m_device; /** the @a MessageMap instance with all known @a Message instances. */ MessageMap* m_messages; diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 4a7b761c..ef7cc7a8 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -481,6 +481,19 @@ result_t loadConfigFiles(DataFieldTemplates* templates, MessageMap* messages, bo } +/** + * Create a log message for a received/sent raw data byte. + * @param byte the raw data byte. + * @param received true if the byte was received, false if it was sent. + */ +static void logRawData(const unsigned char byte, bool received) +{ + if (received == true) + logNotice(lf_bus, "<%02x", byte); + else + logNotice(lf_bus, ">%02x", byte); +} + /** * Main method. * @@ -507,6 +520,13 @@ int main(int argc, char* argv[]) return 0; } + // open the device + Device *device = Device::create(opt.device, opt.noDeviceCheck==false, &logRawData); + if (device == NULL) { + logError(lf_main, "unable to create device %s", opt.device); + return EINVAL; + } + if (opt.foreground == false) { setLogFile(opt.logFile); daemonize(); // make me daemon @@ -523,7 +543,7 @@ int main(int argc, char* argv[]) loadConfigFiles(&templates, &messages); // create the MainLoop and run it - mainLoop = new MainLoop(opt, &templates, &messages); + mainLoop = new MainLoop(opt, device, &templates, &messages); mainLoop->run(); // shutdown diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 8a6f19a2..c161c1b4 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -26,18 +26,24 @@ using namespace std; -MainLoop::MainLoop(const struct options opt, DataFieldTemplates* templates, MessageMap* messages) - : m_templates(templates), m_messages(messages), m_address(opt.address) +MainLoop::MainLoop(const struct options opt, Device *device, DataFieldTemplates* templates, MessageMap* messages) + : m_device(device), m_templates(templates), m_messages(messages), m_address(opt.address) { - // create Port - m_port = new Port(opt.device, opt.noDeviceCheck, opt.logRaw, &logRaw, opt.dump, opt.dumpFile, opt.dumpSize); - m_port->open(); + // setup Device + m_device->setLogRaw(opt.logRaw); + m_device->setDumpRawFile(opt.dumpFile); + m_device->setDumpRawMaxSize(opt.dumpSize); + m_device->setDumpRaw(opt.dump); - if (m_port->isOpen() == false) - logError(lf_bus, "can't open %s", m_port->getDeviceName()); + // open Device + result_t result = m_device->open(); + if (result != RESULT_OK) + logError(lf_bus, "unable to open %s: %s", m_device->getName(), getResultCode(result)); + else if (m_device->isValid() == false) + logError(lf_bus, "device %s not available", m_device->getName()); // create BusHandler - m_busHandler = new BusHandler(m_port, m_messages, + m_busHandler = new BusHandler(m_device, m_messages, m_address, opt.answer, opt.acquireRetries, opt.sendRetries, opt.acquireTimeout, opt.receiveTimeout, @@ -55,17 +61,13 @@ MainLoop::~MainLoop() delete m_network; m_network = NULL; } - if (m_busHandler != NULL) { - m_busHandler->stop(); - m_busHandler->join(); delete m_busHandler; m_busHandler = NULL; } - - if (m_port != NULL) { - delete m_port; - m_port = NULL; + if (m_device != NULL) { + delete m_device; + m_device = NULL; } m_messages->clear(); @@ -109,13 +111,6 @@ void MainLoop::run() } } -void MainLoop::logRaw(const unsigned char byte, bool received) { - if (received == true) - logNotice(lf_bus, "<%02x", byte); - else - logNotice(lf_bus, ">%02x", byte); -} - string MainLoop::decodeMessage(const string& data, bool& connected, bool& listening, bool& running) { ostringstream result; @@ -570,8 +565,8 @@ string MainLoop::executeRaw(vector &args) return "usage: 'raw'\n" " Toggle log raw data."; - bool enabled = !m_port->getLogRaw(); - m_port->setLogRaw(enabled); + bool enabled = !m_device->getLogRaw(); + m_device->setLogRaw(enabled); return enabled ? "raw output enabled" : "raw output disabled"; } @@ -582,8 +577,8 @@ string MainLoop::executeDump(vector &args) return "usage: 'dump'\n" " Toggle raw dump."; - bool enabled = !m_port->getDumpRaw(); - m_port->setDumpRaw(enabled); + bool enabled = !m_device->getDumpRaw(); + m_device->setDumpRaw(enabled); return enabled ? "dump enabled" : "dump disabled"; } diff --git a/src/ebusd/mainloop.h b/src/ebusd/mainloop.h index 495a5970..96310c2f 100644 --- a/src/ebusd/mainloop.h +++ b/src/ebusd/mainloop.h @@ -38,10 +38,11 @@ public: /** * Construct the main loop and create network and bus handling components. * @param opt the program options. + * @param device the @a Device instance. * @param templates the @a DataFieldTemplates instance. * @param messages the @a MessageMap instance. */ - MainLoop(const struct options opt, DataFieldTemplates* templates, MessageMap* messages); + MainLoop(const struct options opt, Device *device, DataFieldTemplates* templates, MessageMap* messages); /** * Destructor. @@ -59,15 +60,11 @@ public: */ void addMessage(NetMessage* message) { m_netQueue.add(message); } - /** - * Create a log message for a received/sent raw data byte. - * @param byte the raw data byte. - * @param received true if the byte was received, false if it was sent. - */ - static void logRaw(const unsigned char byte, bool received); - private: + /** the @a Device instance. */ + Device* m_device; + /** the @a DataFieldTemplates instance. */ DataFieldTemplates* m_templates; @@ -77,9 +74,6 @@ private: /** the own master address for sending on the bus. */ unsigned char m_address; - /** the created @a Port instance. */ - Port* m_port; - /** the created @a BusHandler instance. */ BusHandler* m_busHandler; diff --git a/src/ebusd/network.cpp b/src/ebusd/network.cpp index 9bdedb98..6f6fa192 100644 --- a/src/ebusd/network.cpp +++ b/src/ebusd/network.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) Roland Jax 2012-2014 + * Copyright (C) Roland Jax 2012-2014 , + * John Baier 2014-2015 * * This file is part of ebusd. * @@ -165,6 +166,8 @@ Network::Network(const bool local, const int port, WQueue* netQueue Network::~Network() { + stop(); + while (m_connections.empty() == false) { Connection* connection = m_connections.back(); m_connections.pop_back(); @@ -172,8 +175,6 @@ Network::~Network() connection->join(); delete connection; } - - stop(); join(); if (m_tcpServer != NULL) diff --git a/src/ebusd/network.h b/src/ebusd/network.h index 666485ce..60ee9c5c 100644 --- a/src/ebusd/network.h +++ b/src/ebusd/network.h @@ -1,5 +1,6 @@ /* - * Copyright (C) Roland Jax 2012-2014 + * Copyright (C) Roland Jax 2012-2014 , + * John Baier 2014-2015 * * This file is part of ebusd. * diff --git a/src/lib/ebus/Makefile.am b/src/lib/ebus/Makefile.am index 291586bb..ca9257ac 100644 --- a/src/lib/ebus/Makefile.am +++ b/src/lib/ebus/Makefile.am @@ -11,8 +11,8 @@ libebus_a_SOURCES = result.cpp \ symbol.h \ data.cpp \ data.h \ - port.cpp \ - port.h \ + device.cpp \ + device.h \ message.cpp \ message.h diff --git a/src/lib/ebus/device.cpp b/src/lib/ebus/device.cpp new file mode 100644 index 00000000..cfcc47bc --- /dev/null +++ b/src/lib/ebus/device.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (C) John Baier 2015 + * + * This file is part of ebusd. + * + * ebusd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ebusd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ebusd. If not, see http://www.gnu.org/licenses/. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "device.h" +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PPOLL +#include +#endif + +using namespace std; + +Device::~Device() +{ + close(); + m_dumpRawStream.close(); +} + +Device* Device::create(const char* name, const bool checkDevice, + void (*logRawFunc)(const unsigned char byte, bool received)) +{ + if (strchr(name, '/') == NULL) { + char* pos = strchr((char*)name, ':'); + if (pos != NULL) { + char* end = NULL; + unsigned int port = strtoul(pos+1, &end, 10); + if (end == NULL || *end != 0 || port < 1 || port > 65535) { + return NULL; // invalid port + } + struct sockaddr_in address; + memset((char*)&address, 0, sizeof(address)); + + char* host = strndup(name, pos-name); + if (inet_aton(host, &address.sin_addr) == 0) { + struct hostent* h = gethostbyname(host); + if (h == NULL) { + free(host); + return NULL; // invalid host + } + memcpy(&address.sin_addr, h->h_addr_list[0], h->h_length); + } + free(host); + address.sin_family = AF_INET; + address.sin_port = htons(port); + return new NetworkDevice(name, address, logRawFunc); + } + } + return new SerialDevice(name, checkDevice, logRawFunc); +} + +void Device::close() +{ + if (m_fd != -1) { + ::close(m_fd); + m_fd = -1; + } +} + +bool Device::isValid() +{ + if (m_fd == -1) + return false; + + if (m_checkDevice == true) + checkDevice(); + + return m_fd != -1; +} + +result_t Device::send(const unsigned char value) +{ + if (isValid() == false) + return RESULT_ERR_DEVICE; + + if (write(m_fd, &value, 1) != 1) + return RESULT_ERR_SEND; + + if (m_logRaw == true && m_logRawFunc != NULL) + (*m_logRawFunc)(value, false); + + return RESULT_OK; +} + +result_t Device::recv(const long timeout, unsigned char& value) +{ + if (isValid() == false) + return RESULT_ERR_DEVICE; + + if (timeout > 0) { + int ret; + struct timespec tdiff; + + // set select timeout + tdiff.tv_sec = 0; + tdiff.tv_nsec = timeout*1000; + +#ifdef HAVE_PPOLL + int nfds = 1; + struct pollfd fds[nfds]; + + memset(fds, 0, sizeof(fds)); + + fds[0].fd = m_fd; + fds[0].events = POLLIN; + + ret = ppoll(fds, nfds, &tdiff, NULL); +#else +#ifdef HAVE_PSELECT + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(m_fd, &readfds); + + ret = pselect(m_fd + 1, &readfds, NULL, NULL, &tdiff, NULL); +#else + ret = 1; // ignore timeout if neither ppoll nor pselect are available +#endif +#endif + if (ret == -1) return RESULT_ERR_DEVICE; + if (ret == 0) return RESULT_ERR_TIMEOUT; + } + + // directly read byte from device + ssize_t nbytes = read(m_fd, &value, 1); + if (nbytes == 0) + return RESULT_ERR_EOF; + if (nbytes < 0) + return RESULT_ERR_DEVICE; + + if (m_logRaw == true && m_logRawFunc != NULL) + (*m_logRawFunc)(value, true); + + if (m_dumpRaw == true && m_dumpRawStream.is_open() == true) { + m_dumpRawStream.write((char*)&value, 1); + m_dumpRawFileSize++; + if ((m_dumpRawFileSize%1024) == 0) + m_dumpRawStream.flush(); + + if (m_dumpRawFileSize >= m_dumpRawMaxSize * 1024) { + string oldfile = string(m_dumpRawFile) + ".old"; + if (rename(m_dumpRawFile, oldfile.c_str()) == 0) { + m_dumpRawStream.close(); + m_dumpRawStream.open(m_dumpRawFile, ios::out | ios::binary | ios::app); + m_dumpRawFileSize = 0; + } + } + } + + return RESULT_OK; +} + +void Device::setDumpRaw(bool dumpRaw) +{ + if (dumpRaw == m_dumpRaw) + return; + + m_dumpRaw = dumpRaw; + + if (dumpRaw == false || m_dumpRawFile == NULL) + m_dumpRawStream.close(); + else { + m_dumpRawStream.open(m_dumpRawFile, ios::out | ios::binary | ios::app); + m_dumpRawFileSize = 0; + } +} + +void Device::setDumpRawFile(const char* dumpFile) { + if ((dumpFile == NULL) ? (m_dumpRawFile == NULL) : (m_dumpRawFile != NULL && (m_dumpRawFile == dumpFile || strcmp(dumpFile, m_dumpRawFile) == 0))) + return; + + m_dumpRawStream.close(); + m_dumpRawFile = dumpFile; + + if (m_dumpRaw == true && m_dumpRawFile != NULL) { + m_dumpRawStream.open(m_dumpRawFile, ios::out | ios::binary | ios::app); + m_dumpRawFileSize = 0; + } +} + + +result_t SerialDevice::open() +{ + if (m_fd != -1) + close(); + + struct termios newSettings; + + // open file descriptor + m_fd = ::open(m_name, O_RDWR | O_NOCTTY); + + if (m_fd < 0 || isatty(m_fd) == 0) + return RESULT_ERR_NOTFOUND; + + // save current settings + tcgetattr(m_fd, &m_oldSettings); + + // create new settings + memset(&newSettings, '\0', sizeof(newSettings)); + + newSettings.c_cflag |= (B2400 | CS8 | CLOCAL | CREAD); + newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode + newSettings.c_iflag |= IGNPAR; // ignore parity errors + newSettings.c_oflag &= ~OPOST; + + // non-canonical mode: read() blocks until at least one byte is available + newSettings.c_cc[VMIN] = 1; + newSettings.c_cc[VTIME] = 0; + + // empty device buffer + tcflush(m_fd, TCIFLUSH); + + // activate new settings of serial device + tcsetattr(m_fd, TCSAFLUSH, &newSettings); + + // set serial device into blocking mode + fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL) & ~O_NONBLOCK); + + return RESULT_OK; +} + +void SerialDevice::close() +{ + if (m_fd != -1) { + // empty device buffer + tcflush(m_fd, TCIOFLUSH); + + // restore previous settings of the device + tcsetattr(m_fd, TCSANOW, &m_oldSettings); + } + Device::close(); +} + +void SerialDevice::checkDevice() +{ + int port; + + if (ioctl(m_fd, TIOCMGET, &port) == -1) { + close(); + } +} + + +result_t NetworkDevice::open() +{ + if (m_fd != -1) + close(); + + int ret; + + m_fd = socket(AF_INET, SOCK_STREAM, 0); + if (m_fd < 0) + return RESULT_ERR_GENERIC_IO; + + ret = connect(m_fd, (struct sockaddr*)&m_address, sizeof(m_address)); + if (ret < 0) { + close(); + return RESULT_ERR_GENERIC_IO; + } + return RESULT_OK; +} + +void NetworkDevice::checkDevice() +{ + unsigned char value; + ssize_t c = ::recv(m_fd, &value, 1, MSG_PEEK | MSG_DONTWAIT); + if (c == 0 || (c < 0 && errno != EAGAIN)) { + close(); + } +} diff --git a/src/lib/ebus/device.h b/src/lib/ebus/device.h new file mode 100644 index 00000000..3c2c7e29 --- /dev/null +++ b/src/lib/ebus/device.h @@ -0,0 +1,244 @@ +/* + * Copyright (C) John Baier 2015 + * + * This file is part of ebusd. + * + * ebusd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ebusd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ebusd. If not, see http://www.gnu.org/licenses/. + */ + +#ifndef LIBEBUS_DEVICE_H_ +#define LIBEBUS_DEVICE_H_ + +#include +#include +#include +#include +#include +#include "result.h" + +/** \file device.h */ + +using namespace std; + +/** + * The base class for accessing an eBUS. + */ +class Device +{ + +public: + /** + * Construct a new instance. + * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). + * @param checkDevice whether to regularly check the device availability (only for serial devices). + * @param logRawFunc the function to call for logging raw data, or NULL. + */ + Device(const char* name, const bool checkDevice, + void (*logRawFunc)(const unsigned char byte, bool received)) + : m_name(name), m_checkDevice(checkDevice), m_fd(-1), + m_logRaw(false), m_logRawFunc(logRawFunc), + m_dumpRaw(false), m_dumpRawFile(NULL), m_dumpRawMaxSize(0), m_dumpRawStream(NULL), m_dumpRawFileSize(0) {} + + /** + * Destructor. + */ + virtual ~Device(); + + /** + * Factory method for creating a new instance. + * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). + * @param checkDevice whether to regularly check the device availability (only for serial devices). + * @param logRawFunc the function to call for logging raw data, or NULL. + * @return the new @a Device, or NULL on error. + * Note: the caller needs to free the created instance. + */ + static Device* create(const char* name, const bool checkDevice=true, + void (*logRawFunc)(const unsigned char byte, bool received)=NULL); + + /** + * Open the file descriptor. + * @return the @a result_t code. + */ + virtual result_t open() = 0; // abstract + + /** + * Close the file descriptor if opened. + */ + virtual void close(); + + /** + * Write a single byte to the device. + * @param value the byte value to write. + * @return the @a result_t code. + */ + result_t send(const unsigned char value); + + /** + * Read a single byte from the device. + * @param timeout maximum time to wait for the byte in microseconds, or 0 for infinite. + * @param value the reference in which the received byte value is stored. + * @return the result_t code. + */ + result_t recv(const long timeout, unsigned char& value); + + /** + * Get whether logging of raw data is enabled. + * @return whether logging of raw data is enabled. + */ + bool getLogRaw() { return m_logRaw; } + + /** + * Enable or disable logging of raw data. + * @param logRaw true to enable logging of raw data, false to disable it. + */ + void setLogRaw(bool logRaw=true) { m_logRaw = logRaw; } + + /** + * Get whether dumping of raw data to a file is enabled. + * @return whether dumping of raw data to a file is enabled. + */ + bool getDumpRaw() { return m_dumpRaw; } + + /** + * Enable or disable dumping of raw data to a file. + * @param dumpRaw true to enable dumping of raw data to a file, false to disable it. + */ + void setDumpRaw(bool dumpRaw=true); + + /** + * Set the name of the file to dump raw data to. + * @param dumpFile the name of the file to dump raw data to. + */ + void setDumpRawFile(const char* dumpFile); + + /** + * Set the maximum size of a file to dump raw data to. + * @param maxSize the maximum size of a file to dump raw data to. + */ + void setDumpRawMaxSize(const long maxSize) { m_dumpRawMaxSize = maxSize; } + + /** + * Return the device name. + * @return the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). + */ + const char* getName() { return m_name; } + + /** + * Return whether the device is opened and available. + * @return whether the device is opened and available. + */ + bool isValid(); + +protected: + /** + * Check if the device is still available and close it if not. + */ + virtual void checkDevice() = 0; // abstract + +protected: + /** the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */ + const char* m_name; + + /** whether to regularly check the device availability (only for serial devices). */ + const bool m_checkDevice; + + /** the opened file descriptor, or -1. */ + int m_fd; + +private: + /** whether logging of raw data is enabled. */ + bool m_logRaw; + + /** the function to call for logging raw data, or NULL. */ + void (*m_logRawFunc)(const unsigned char byte, bool received); + + /** whether dumping of raw data to a file is enabled. */ + bool m_dumpRaw; + + /** the name of the file to dump raw data to. */ + const char* m_dumpRawFile; + + /** the maximum size of @a m_dumpFile, or 0 for infinite. */ + long m_dumpRawMaxSize; + + /** the @a ofstream for dumping raw data to. */ + ofstream m_dumpRawStream; + + /** the number of bytes already written to the @a m_dumpFile. */ + long m_dumpRawFileSize; + +}; + +/** + * The @a Device for directly connected serial interfaces (tty). + */ +class SerialDevice : public Device +{ +public: + /** + * Construct a new instance. + * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). + * @param checkDevice whether to regularly check the device availability (only for serial devices). + * @param logRawFunc the function to call for logging raw data, or NULL. + */ + SerialDevice(const char* name, const bool checkDevice, + void (*logRawFunc)(const unsigned char byte, bool received)) + : Device(name, checkDevice, logRawFunc) {} + + // @copydoc + virtual result_t open(); + + // @copydoc + void close(); + +protected: + // @copydoc + virtual void checkDevice(); + +private: + /** the previous settings of the device for restoring. */ + termios m_oldSettings; + +}; + +/** + * The @a Device for remote network interfaces. + */ +class NetworkDevice : public Device +{ +public: + /** + * Construct a new instance. + * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). + * @param address the socket address of the device. + * @param logRawFunc the function to call for logging raw data, or NULL. + */ + NetworkDevice(const char* name, const struct sockaddr_in address, + void (*logRawFunc)(const unsigned char byte, bool received)) + : Device(name, true, logRawFunc), m_address(address) {} + + // @copydoc + virtual result_t open(); + +protected: + // @copydoc + virtual void checkDevice(); + +private: + /** the socket address of the device. */ + const struct sockaddr_in m_address; + +}; + +#endif // LIBEBUS_DEVICE_H_ diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp deleted file mode 100644 index e332a5d7..00000000 --- a/src/lib/ebus/port.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-2014 - * - * This file is part of ebusd. - * - * ebusd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ebusd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ebusd. If not, see http://www.gnu.org/licenses/. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "port.h" -#include "result.h" -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PPOLL -#include -#endif - -using namespace std; - -bool Device::isOpen() -{ - if (isValid() == false) - m_open = false; - - return m_open; -} - -bool Device::isValid() -{ - if (m_noDeviceCheck == false) { - int port; - - if (ioctl(m_fd, TIOCMGET, &port) == -1) { - closeDevice(); - m_open = false; - return false; - } - } - - return true; -} - -result_t Device::send(const unsigned char value) -{ - if (isValid() == false) - return RESULT_ERR_DEVICE; - - // write bytes to device - return write(m_fd, &value, 1) == 1 ? RESULT_OK : RESULT_ERR_SEND; -} - -result_t Device::recv(const long timeout, unsigned char& value) -{ - if (isValid() == false) - return RESULT_ERR_DEVICE; - - if (timeout > 0) { - int ret; - struct timespec tdiff; - - // set select timeout - tdiff.tv_sec = 0; - tdiff.tv_nsec = timeout*1000; - -#ifdef HAVE_PPOLL - int nfds = 1; - struct pollfd fds[nfds]; - - memset(fds, 0, sizeof(fds)); - - fds[0].fd = m_fd; - fds[0].events = POLLIN; - - ret = ppoll(fds, nfds, &tdiff, NULL); -#else -#ifdef HAVE_PSELECT - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(m_fd, &readfds); - - ret = pselect(m_fd + 1, &readfds, NULL, NULL, &tdiff, NULL); -#else - ret = 1; // ignore timeout if neither ppoll nor pselect are available -#endif -#endif - if (ret == -1) return RESULT_ERR_DEVICE; - if (ret == 0) return RESULT_ERR_TIMEOUT; - } - - // directly read byte from device - ssize_t nbytes = read(m_fd, &value, 1); - if (nbytes == 0) - return RESULT_ERR_EOF; - - return nbytes < 0 ? RESULT_ERR_DEVICE : RESULT_OK; -} - - -result_t DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck) -{ - m_noDeviceCheck = noDeviceCheck; - struct termios newSettings; - m_open = false; - - // open file descriptor - m_fd = open(deviceName.c_str(), O_RDWR | O_NOCTTY); - - if (m_fd < 0 || isatty(m_fd) == 0) - return RESULT_ERR_NOTFOUND; - - // save current settings - tcgetattr(m_fd, &m_oldSettings); - - // create new settings - memset(&newSettings, '\0', sizeof(newSettings)); - - newSettings.c_cflag |= (B2400 | CS8 | CLOCAL | CREAD); - newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode - newSettings.c_iflag |= IGNPAR; // ignore parity errors - newSettings.c_oflag &= ~OPOST; - - // non-canonical mode: read() blocks until at least one byte is available - newSettings.c_cc[VMIN] = 1; - newSettings.c_cc[VTIME] = 0; - - // empty device buffer - tcflush(m_fd, TCIFLUSH); - - // activate new settings of serial device - tcsetattr(m_fd, TCSAFLUSH, &newSettings); - - // set serial device into blocking mode - fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL) & ~O_NONBLOCK); - - m_open = true; - return RESULT_OK; -} - -void DeviceSerial::closeDevice() -{ - if (m_open == true) { - // empty device buffer - tcflush(m_fd, TCIOFLUSH); - - // activate old settings of serial device - tcsetattr(m_fd, TCSANOW, &m_oldSettings); - - // close file descriptor from serial device - close(m_fd); - - m_fd = -1; - m_open = false; - } -} - - -result_t DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck) -{ - m_noDeviceCheck = noDeviceCheck; - - struct sockaddr_in sock; - char* hostport; - int ret; - - m_open = false; - - memset((char*) &sock, 0, sizeof(sock)); - - hostport = strdup(deviceName.c_str()); - char* host = strtok(hostport, ":"); - char* port = strtok(NULL, ":"); - - if (inet_addr(host) == INADDR_NONE) { - struct hostent* he; - - he = gethostbyname(host); - if (he == NULL) - return RESULT_ERR_NOTFOUND; - - memcpy(&sock.sin_addr, he->h_addr_list[0], he->h_length); - } - else { - ret = inet_aton(host, &sock.sin_addr); - if (ret == 0) - return RESULT_ERR_NOTFOUND; - } - - sock.sin_family = AF_INET; - sock.sin_port = htons(strtol(port, NULL, 10)); - - m_fd = socket(AF_INET, SOCK_STREAM, 0); - if (m_fd < 0) - return RESULT_ERR_GENERIC_IO; - - ret = connect(m_fd, (struct sockaddr*) &sock, sizeof(sock)); - if (ret < 0) - return RESULT_ERR_GENERIC_IO; - - free(hostport); - m_open = true; - - return RESULT_OK; -} - -void DeviceNetwork::closeDevice() -{ - if (m_open == true) { - // close file descriptor from network device - close(m_fd); - - m_fd = -1; - m_open = false; - } -} - - -Port::Port(const string deviceName, const bool noDeviceCheck, - const bool logRaw, void (*logRawFunc)(const unsigned char byte, bool received), - const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize) - : m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck), - m_logRaw(logRaw), m_logRawFunc(logRawFunc), - m_dumpRawFile(dumpRawFile), m_dumpRawMaxSize(dumpRawMaxSize), - m_dumpRawFileSize(0) -{ - m_device = NULL; - - if (strchr(deviceName.c_str(), '/') == NULL && strchr(deviceName.c_str(), ':') != NULL) { - setType(dt_network); - m_noDeviceCheck = true; - } - else - setType(dt_serial); - - m_dumpRaw = false; - - setDumpRaw(dumpRaw); // open fstream if necessary -} - -result_t Port::send(const unsigned char value) -{ - result_t ret = m_device->send(value); - if (ret == RESULT_OK && m_logRaw == true && m_logRawFunc != NULL) - (*m_logRawFunc)(value, false); - return ret; -} - -result_t Port::recv(const long timeout, unsigned char& value) -{ - result_t ret = m_device->recv(timeout, value); - if (ret == RESULT_OK) { - if (m_logRaw == true && m_logRawFunc != NULL) { - (*m_logRawFunc)(value, true); - } - - if (m_dumpRaw == true && m_dumpRawStream.is_open() == true) { - m_dumpRawStream.write((char*)&value, 1); - m_dumpRawFileSize++; - if ((m_dumpRawFileSize%1024) == 0) - m_dumpRawStream.flush(); - - if (m_dumpRawFileSize >= m_dumpRawMaxSize * 1024) { - string oldfile = m_dumpRawFile + ".old"; - if (rename(m_dumpRawFile.c_str(), oldfile.c_str()) == 0) { - m_dumpRawStream.close(); - m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app); - m_dumpRawFileSize = 0; - } - } - } - } - - return ret; -} - -void Port::setDumpRaw(bool dumpRaw) -{ - if (dumpRaw == m_dumpRaw) - return; - - m_dumpRaw = dumpRaw; - - if (dumpRaw == false) - m_dumpRawStream.close(); - else { - m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app); - m_dumpRawFileSize = 0; - } -} - -void Port::setDumpRawFile(const string& dumpFile) { - if (dumpFile == m_dumpRawFile) - return; - - m_dumpRawStream.close(); - m_dumpRawFile = dumpFile; - - if (m_dumpRaw == true) { - m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app); - m_dumpRawFileSize = 0; - } -} - -void Port::setType(const DeviceType type) -{ - if (m_device != NULL) - delete m_device; - - switch (type) { - case dt_serial: - m_device = new DeviceSerial(); - break; - case dt_network: - m_device = new DeviceNetwork(); - break; - }; -}; - diff --git a/src/lib/ebus/port.h b/src/lib/ebus/port.h deleted file mode 100644 index bbfcdd90..00000000 --- a/src/lib/ebus/port.h +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-2014 - * - * This file is part of ebusd. - * - * ebusd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ebusd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ebusd. If not, see http://www.gnu.org/licenses/. - */ - -#ifndef LIBEBUS_PORT_H_ -#define LIBEBUS_PORT_H_ - -#include -#include -#include -#include -#include -#include -#include "result.h" - -/** \file port.h */ - -using namespace std; - -/** available device types. */ -enum DeviceType { - dt_serial, /*!< serial device */ - dt_network /*!< network device */ -}; - - -/** - * base class for input devices. - */ -class Device -{ - -public: - /** - * constructs a new instance. - */ - Device() : m_fd(-1), m_open(false), m_noDeviceCheck(false) {} - - /** - * destructor. - */ - virtual ~Device() {} - - /** - * virtual open function for opening file descriptor - * @param deviceName to determine device type. - * @param noDeviceCheck en-/disable device check. - * @return the @a result_t code. - */ - virtual result_t openDevice(const string deviceName, const bool noDeviceCheck) = 0; - - /** - * virtual close function for closing opened file descriptor - */ - virtual void closeDevice() = 0; - - /** - * connection state of device. - * @return true if device is open - */ - bool isOpen(); - - /** - * Write a single byte to opened file descriptor. - * @param value the value to send. - * @return the result_t code. - */ - result_t send(const unsigned char value); - - /** - * Read a single byte from opened file descriptor. - * @param timeout max time out for new input data [usec], or 0 for infinite. - * @param value the reference in which the value is stored. - * @return the result_t code. - */ - result_t recv(const long timeout, unsigned char& value); - -protected: - /** file descriptor from input device */ - int m_fd; - - /** true if device is opened */ - bool m_open; - - /** true if device check is disabled */ - bool m_noDeviceCheck; - -private: - /** - * system check if opened file descriptor is valid - * @return true if file descriptor is valid - */ - bool isValid(); - -}; - -/** - * class for serial input device. - */ -class DeviceSerial : public Device -{ - -public: - /** - * destructor. - */ - ~DeviceSerial() { closeDevice(); } - - // @copydoc - virtual result_t openDevice(const string deviceName, const bool noDeviceCheck); - - // @copydoc - void closeDevice(); - -private: - /** save settings from serial device */ - termios m_oldSettings; - -}; - -/** - * class for network input device. - */ -class DeviceNetwork : public Device -{ - -public: - /** - * destructor. - */ - ~DeviceNetwork() { closeDevice(); } - - // @copydoc - virtual result_t openDevice(const string deviceName, const bool noDeviceCheck); - - // @copydoc - void closeDevice(); - -private: - -}; - -/** - * wrapper class for class device. - */ -class Port -{ - -public: - /** - * constructs a new instance and determine device type. - * @param deviceName to determine device type. - * @param noDeviceCheck en-/disable device check. - * @param logRaw whether logging of raw data is enabled. - * @param logRawFunc a function to call for logging raw data, or NULL. - * @param dumpRaw whether dumping of raw data to a file is enabled. - * @param dumpRawFile the name of the file to dump raw data to. - * @param dumpRawMaxSize the maximum size of @a m_dumpFile. - */ - Port(const string deviceName, const bool noDeviceCheck, - const bool logRaw, void (*logRawFunc)(const unsigned char byte, bool received), - const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize); - - /** - * destructor. - */ - ~Port() { delete m_device; m_dumpRawStream.close(); } - - /** - * open device - */ - result_t open() { return m_device->openDevice(m_deviceName, m_noDeviceCheck); } - - /** - * close device - */ - void close() { m_device->closeDevice(); } - - /** - * connection state of device. - * @return true if device is open - */ - bool isOpen() { return m_device->isOpen(); } - - /** - * Write a single byte to opened file descriptor. - * @param value the value to send. - * @return the result_t code. - */ - result_t send(const unsigned char value); - - /** - * Read a single byte from opened file descriptor. - * @param timeout max time out for new input data [usec], or 0 for infinite. - * @param value the reference in which the value is stored. - * @return the result_t code. - */ - result_t recv(const long timeout, unsigned char& value); - - /** - * Get whether logging of raw data is enabled. - * @return whether logging of raw data is enabled. - */ - bool getLogRaw() { return m_logRaw; } - - /** - * Enable or disable logging of raw data. - * @param logRaw true to enable logging of raw data, false to disable it. - */ - void setLogRaw(bool logRaw=true) { m_logRaw = logRaw; } - - /** - * Get whether dumping of raw data to a file is enabled. - * @return whether dumping of raw data to a file is enabled. - */ - bool getDumpRaw() { return m_dumpRaw; } - - /** - * Enable or disable dumping of raw data to a file. - * @param dumpRaw true to enable dumping of raw data to a file, false to disable it. - */ - void setDumpRaw(bool dumpRaw=true); - - /** - * Set the name of the file to dump raw data to. - * @param dumpFile the name of the file to dump raw data to. - */ - void setDumpRawFile(const string& dumpFile); - - /** - * Set the maximum size of a file to dump raw data to. - * @param maxSize the maximum size of a file to dump raw data to. - */ - void setDumpRawMaxSize(const long maxSize) { m_dumpRawMaxSize = maxSize; } - - /** - * Return the device name. - * @return the device name. - */ - const char* getDeviceName() { return m_deviceName.c_str(); } - -private: - /** the device name */ - const string m_deviceName; - - /** the device instance */ - Device* m_device; - - /** true if device check is disabled */ - bool m_noDeviceCheck; - - /** whether logging of raw data is enabled. */ - bool m_logRaw; - - /** a function to call for logging raw data, or NULL. */ - void (*m_logRawFunc)(const unsigned char byte, bool received); - - /** whether dumping of raw data to a file is enabled. */ - bool m_dumpRaw; - - /** the name of the file to dump raw data to. */ - string m_dumpRawFile; - - /** the maximum size of @a m_dumpFile. */ - long m_dumpRawMaxSize; - - /** the @a ofstream for dumping raw data to. */ - ofstream m_dumpRawStream; - - /** the number of bytes already written to the @a m_dumpFile. */ - long m_dumpRawFileSize; - - /** - * internal setter for device type. - * @param type of device - */ - void setType(const DeviceType type); - -}; - -#endif // LIBEBUS_PORT_H_ diff --git a/src/lib/ebus/test/Makefile.am b/src/lib/ebus/test/Makefile.am index 55d3e29f..63103e50 100644 --- a/src/lib/ebus/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -3,13 +3,13 @@ AM_CXXFLAGS = -fpic \ -Wextra \ -isystem$(top_srcdir)/src/lib/ebus -noinst_PROGRAMS = test_port \ +noinst_PROGRAMS = test_device \ test_symbol \ test_data \ test_message -test_port_SOURCES = test_port.cpp -test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a +test_device_SOURCES = test_device.cpp +test_device_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_symbol_SOURCES = test_symbol.cpp test_symbol_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a diff --git a/src/lib/ebus/test/test_port.cpp b/src/lib/ebus/test/test_device.cpp similarity index 50% rename from src/lib/ebus/test/test_port.cpp rename to src/lib/ebus/test/test_device.cpp index a65382e7..4333ac6a 100644 --- a/src/lib/ebus/test/test_port.cpp +++ b/src/lib/ebus/test/test_device.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) Roland Jax 2012-2014 + * Copyright (C) John Baier 2015 * * This file is part of ebusd. * @@ -17,7 +17,7 @@ * along with ebusd. If not, see http://www.gnu.org/licenses/. */ -#include "port.h" +#include "device.h" #include #include @@ -25,33 +25,38 @@ using namespace std; int main () { - string dev("/dev/ttyUSB20"); - Port port(dev, true, false, NULL, false, "", 1); + Device* device = Device::create("/dev/ttyUSB20", true, NULL); + if (device == NULL) { + cout << "unable to create device" << endl; + return -1; + } + result_t result = device->open(); + if (result != RESULT_OK) { + cout << "open failed: " << getResultCode(result) << endl; + } else { + if (device->isValid() == false) + cout << "device not available." << endl; - port.open(); + int count = 0; - if(port.isOpen() == true) - cout << "openPort successful." << endl; + while (1) { + unsigned char byte = 0; + result = device->recv(0, byte); - int count = 0; + if (result == RESULT_OK) + cout << hex << setw(2) << setfill('0') + << static_cast(byte) << endl; - while (1) { - result_t result; - unsigned char byte = 0; - result = port.recv(0, byte); + count++; + } - if (result == RESULT_OK) - cout << hex << setw(2) << setfill('0') - << static_cast(byte) << endl; + device->close(); - count++; + if(device->isValid() == false) + cout << "close successful." << endl; } - port.close(); - - if(port.isOpen() == false) - cout << "closePort successful." << endl; + delete device; return 0; - } diff --git a/src/lib/utils/thread.cpp b/src/lib/utils/thread.cpp index fa584391..0c85e732 100644 --- a/src/lib/utils/thread.cpp +++ b/src/lib/utils/thread.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) Roland Jax 2012-2014 + * Copyright (C) Roland Jax 2012-2014 , + * John Baier 2014-2015 * * This file is part of ebusd. * diff --git a/src/tools/ebusctl.cpp b/src/tools/ebusctl.cpp index 526e3cb3..3995b50f 100644 --- a/src/tools/ebusctl.cpp +++ b/src/tools/ebusctl.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) Roland Jax 2012-2014 + * Copyright (C) Roland Jax 2012-2014 , + * John Baier 2014-2015 * * This file is part of ebusd. * diff --git a/src/tools/ebusfeed.cpp b/src/tools/ebusfeed.cpp index 85e1c258..37d356fc 100644 --- a/src/tools/ebusfeed.cpp +++ b/src/tools/ebusfeed.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) Roland Jax 2012-2014 + * Copyright (C) Roland Jax 2012-2014 , + * John Baier 2014-2015 * * This file is part of ebusd. * @@ -22,7 +23,8 @@ #endif #include -#include "port.h" +#include "device.h" +#include #include #include #include @@ -129,12 +131,19 @@ int main(int argc, char* argv[]) if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &opt) != 0) return EINVAL; - string dev(opt.device); - Port port(dev, true, false, NULL, false, "", 1); + Device* device = Device::create(opt.device, true, NULL); + if (device == NULL) { + cout << "unable to create device " << opt.device << endl; + return EINVAL; + } + result_t result = device->open(); + if (result != RESULT_OK) + cout << "unable to open " << opt.device << ": " << getResultCode(result) << endl; - port.open(); - if(port.isOpen() == true) { - cout << "openPort successful." << endl; + if (device->isValid() == false) + cout << "device " << opt.device << " not available" << endl; + else { + cout << "device opened" << endl; fstream file(opt.dumpFile, ios::in | ios::binary); @@ -147,7 +156,7 @@ int main(int argc, char* argv[]) cout << hex << setw(2) << setfill('0') << static_cast(byte) << endl; - port.send(byte); + device->send(byte); usleep(opt.time); } @@ -155,14 +164,9 @@ int main(int argc, char* argv[]) } else cout << "error opening file " << opt.dumpFile << endl; - - port.close(); - if(port.isOpen() == false) - cout << "closePort successful." << endl; } - else - cout << "error opening device " << opt.device << endl; + delete device; exit(EXIT_SUCCESS); }