From b245ffe487b4a25022f943d623e3b7e1268fec94 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 31 Oct 2014 15:27:01 +0100 Subject: [PATCH 01/15] documentation for class Port added. --- src/libebus/port.h | 146 ++++++++++++++++++++++++++++++++++++++- src/libebus/result.cpp | 2 +- src/libebus/result.h | 2 +- src/libebus/symbol.cpp | 2 +- src/libebus/symbol.h | 3 +- src/test/test_symbol.cpp | 2 +- 6 files changed, 150 insertions(+), 7 deletions(-) diff --git a/src/libebus/port.h b/src/libebus/port.h index f69ba276..2b0dc12f 100644 --- a/src/libebus/port.h +++ b/src/libebus/port.h @@ -28,90 +28,232 @@ namespace libebus { +/** available device types. */ enum DeviceType { SERIAL, NETWORK }; +/** max size of receive buffer. */ #define MAX_READ_SIZE 100 + +/** + * @brief Base class for input devices. + */ class Device { public: + /** + * @brief Constructs a new instance. + */ Device() : m_fd(-1), m_open(false), m_noDeviceCheck(false) {} + + /** + * @brief Destructor. + */ virtual ~Device() {} + /** + * @brief virtual open function for opening file descriptor + * @param deviceName to determine device type. + * @param noDeviceCheck en-/disable device check. + */ virtual void openDevice(const std::string deviceName, const bool noDeviceCheck) = 0; + + /** + * @brief virtual close function for closing opened file descriptor + */ virtual void closeDevice() = 0; + + /** + * @brief connection state of device. + * @return true if device is open + */ bool isOpen(); + /** + * @brief sendBytes write bytes into opened file descriptor. + * @param buffer data to send. + * @param nbytes number of bytes to send. + * @return number of written bytes or -1 if an error has occured. + */ ssize_t sendBytes(const unsigned char* buffer, size_t nbytes); + + /** + * @brief recvBytes read bytes from opened file descriptor. + * @param timeout max time out for new input data. + * @param maxCount max size of receive buffer. + * @return number of read bytes or -1 if an error has occured. + */ ssize_t recvBytes(const long timeout, size_t maxCount); + /** + * @brief fetch first byte from receive buffer. + * @return first byte (raw) + */ unsigned char getByte(); + + /** + * @brief get current size (bytes) of the receive buffer. + * @return number of bytes in queued. + */ ssize_t sizeRecvBuffer() const { return m_recvBuffer.size(); } protected: + /** if of file descriptor */ int m_fd; + /** state of device*/ bool m_open; + /** state of device check */ bool m_noDeviceCheck; + /** queue for received bytes */ std::queue m_recvBuffer; + /** receive buffer */ unsigned char m_buffer[MAX_READ_SIZE]; private: + /** + * @brief system check if opened file descriptor is valid + * @return true if file descriptor is valid + */ bool isValid(); }; +/** + * @brief Class for serial input device. + */ class DeviceSerial : public Device { public: + /** + * @brief Destructor. + */ ~DeviceSerial() { closeDevice(); } + /** + * @brief open function for opening file descriptor + * @param deviceName to determine device type. + * @param noDeviceCheck en-/disable device check. + */ void openDevice(const std::string deviceName, const bool noDeviceCheck); + + /** + * @brief close function for closing opened file descriptor + */ void closeDevice(); private: + /** save settings from serial device */ termios m_oldSettings; }; +/** + * @brief Class for network input device. + */ class DeviceNetwork : public Device { public: + /** + * @brief Destructor. + */ ~DeviceNetwork() { closeDevice(); } + /** + * @brief open function for opening file descriptor + * @param deviceName to determine device type. + * @param noDeviceCheck en-/disable device check. + */ void openDevice(const std::string deviceName, const bool noDeviceCheck); + + /** + * @brief close opened file descriptor + */ void closeDevice(); private: }; - +/** + * @brief Wrapper class for class Device. + */ class Port { public: + /** + * @brief Constructs a new instance and determine device type. + * @param deviceName to determine device type. + * @param noDeviceCheck en-/disable device check. + */ Port(const std::string deviceName, const bool noDeviceCheck); + + /** + * @brief Destructor. + */ ~Port() { delete m_device; } + /** + * @brief open device + */ void open() { m_device->openDevice(m_deviceName, m_noDeviceCheck); } + + /** + * @brief close device + */ void close() { m_device->closeDevice(); } + + /** + * @brief connection state of device. + * @return true if device is open + */ bool isOpen() { return m_device->isOpen(); } + /** + * @brief send write bytes into opened file descriptor. + * @param buffer data to send. + * @param nbytes number of bytes to send. + * @return number of written bytes or -1 if an error has occured. + */ ssize_t send(const unsigned char* buffer, size_t nbytes) { return m_device->sendBytes(buffer, nbytes); } - ssize_t recv(const long timeout, size_t maxCount=MAX_READ_SIZE) { return m_device->recvBytes(timeout, maxCount); } + /** + * @brief recv read bytes from opened file descriptor. + * @param timeout max time out for new input data. + * @param maxCount max size of receive buffer. + * @return number of read bytes or -1 if an error has occured. + */ + ssize_t recv(const long timeout, size_t maxCount = MAX_READ_SIZE) + { return m_device->recvBytes(timeout, maxCount); } + + /** + * @brief fetch first byte from receive buffer. + * @return first byte (raw) + */ unsigned char byte() { return m_device->getByte(); } + + /** + * @brief get current size (bytes) of the receive buffer. + * @return number of bytes in queued. + */ ssize_t size() const { return m_device->sizeRecvBuffer(); } private: + /** the device name */ std::string m_deviceName; + /** pointer to device instance */ Device* m_device; + /** true if device check is disabled */ bool m_noDeviceCheck; + /** + * @brief internal setter for device type. + * @param type of device + */ void setType(const DeviceType type); }; diff --git a/src/libebus/result.cpp b/src/libebus/result.cpp index 4374d3d9..ba2f6008 100644 --- a/src/libebus/result.cpp +++ b/src/libebus/result.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) John Baier 2012-2014 + * Copyright (C) John Baier 2014 * * This file is part of ebusd. * diff --git a/src/libebus/result.h b/src/libebus/result.h index bd0a9c13..dd669e8f 100644 --- a/src/libebus/result.h +++ b/src/libebus/result.h @@ -1,5 +1,5 @@ /* - * Copyright (C) John Baier 2012-2014 + * Copyright (C) John Baier 2014 * * This file is part of ebusd. * diff --git a/src/libebus/symbol.cpp b/src/libebus/symbol.cpp index 102c4760..2d35aa19 100644 --- a/src/libebus/symbol.cpp +++ b/src/libebus/symbol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) John Baier 2012-2014 + * Copyright (C) John Baier 2014 * * This file is part of ebusd. * diff --git a/src/libebus/symbol.h b/src/libebus/symbol.h index 7ed10ce4..9fd31508 100644 --- a/src/libebus/symbol.h +++ b/src/libebus/symbol.h @@ -1,5 +1,5 @@ /* - * Copyright (C) John Baier 2012-2014 + * Copyright (C) John Baier 2014 * * This file is part of ebusd. * @@ -41,6 +41,7 @@ static const unsigned char BROADCAST = 0xFE; // the broadcast destination addres */ class SymbolString { + public: /** * @brief Creates a new empty SymbolString. diff --git a/src/test/test_symbol.cpp b/src/test/test_symbol.cpp index 2e495d0b..625e93cc 100644 --- a/src/test/test_symbol.cpp +++ b/src/test/test_symbol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) John Baier 2012-2014 + * Copyright (C) John Baier 2014 * * This file is part of ebusd. * From 02b8b922492ef5f0cd8bf8ee8acb2a1ee74d2841 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 31 Oct 2014 15:42:48 +0100 Subject: [PATCH 02/15] documentation for class Dump added. --- src/libebus/dump.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libebus/dump.h b/src/libebus/dump.h index 2062104a..34418139 100644 --- a/src/libebus/dump.h +++ b/src/libebus/dump.h @@ -25,21 +25,44 @@ namespace libebus { - +/** + * @brief Class for writing raw bytes to binary file. + */ class Dump { public: + /** + * @brief Create a new instance to write dump files. + * @param filename which will be used for dumping raw bytes. + * @param filesize max. Size of the dump file, before switching. + */ Dump(std::string filename, long filesize) : m_filename(filename), m_filesize(filesize) {} + /** + * @brief write byte to dump file. + * @param byte to write + * @return -1 if dump file cannot opened or renaming of dump file failed. + */ int write(const char* byte); + /** + * @brief setter for dump file name. + * @param filename which will be used for dumping raw bytes. + */ void setFilename(const std::string& filename) { m_filename = filename; } + + /** + * @brief setter for max size of dump file. + * @param filesize max. Size of the dump file, before switching. + */ void setFilesize(const long filesize) { m_filesize = filesize; } private: + /** the name of dump file*/ std::string m_filename; + /** max. size of dump file */ long m_filesize; }; From 741fc985948c23b5ec518119491d2afc8cac41cb Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 31 Oct 2014 18:48:15 +0100 Subject: [PATCH 03/15] documentation for configuration classes added; readFile renamed to parse --- src/libebus/configfile.cpp | 8 ++--- src/libebus/configfile.h | 70 ++++++++++++++++++++++++++++++++++++-- src/libebus/port.h | 2 +- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/libebus/configfile.cpp b/src/libebus/configfile.cpp index 70e42917..0520580c 100644 --- a/src/libebus/configfile.cpp +++ b/src/libebus/configfile.cpp @@ -26,7 +26,7 @@ namespace libebus { -void ConfigFileCSV::readFile(std::istream& is, Commands& commands) +void ConfigFileCSV::parse(std::istream& is, Commands& commands) { std::string line; @@ -50,9 +50,9 @@ void ConfigFileCSV::readFile(std::istream& is, Commands& commands) }; -void ConfigFileXML::readFile(std::istream& is, Commands& commands) +void ConfigFileXML::parse(std::istream& is, Commands& commands) { - ; // ToDo: Implamantion for xml files + ; // ToDo: Implementation for xml files } @@ -91,7 +91,7 @@ Commands* ConfigCommands::getCommands() std::fstream file((*i).c_str(), std::ios::in); if(file.is_open() == true) { - m_configfile->readFile(file, *commands); + m_configfile->parse(file, *commands); file.close(); } } diff --git a/src/libebus/configfile.h b/src/libebus/configfile.h index 95d778ac..4d5183b1 100644 --- a/src/libebus/configfile.h +++ b/src/libebus/configfile.h @@ -27,55 +27,119 @@ namespace libebus { +/** available file endings / types. */ enum FileType { CSV, XML }; +/** + * @brief Base class for config files. + */ class ConfigFile { public: + /** + * @brief Destructor. + */ virtual ~ConfigFile() {} - virtual void readFile(std::istream& is, Commands& commands) = 0; + /** + * @brief read input stream and stored data into commands + * @param is open input stream for reading. + * @param commands object as datastore. + */ + virtual void parse(std::istream& is, Commands& commands) = 0; }; +/** + * @brief Class for CSV config files. + */ class ConfigFileCSV : public ConfigFile { public: + /** + * @brief Destructor. + */ ~ConfigFileCSV() {} - void readFile(std::istream& is, Commands& commands); + /** + * @brief read input stream and stored data into commands + * @param is open input stream for reading. + * @param commands object as datastore. + */ + void parse(std::istream& is, Commands& commands); }; +/** + * @brief Class for XML config files. + */ class ConfigFileXML : public ConfigFile { public: + /** + * @brief Destructor. + */ ~ConfigFileXML() {} - void readFile(std::istream& is, Commands& commands); + /** + * @brief read input stream and stored data into commands + * @param is open input stream for reading. + * @param commands object as datastore. + */ + void parse(std::istream& is, Commands& commands); }; +/** + * @brief Class for class Device. + */ class ConfigCommands { public: + /** + * @brief Set file type and add recursive files from given path. + * @param path to configuration files. + * @param Filetype to parse. + */ ConfigCommands(const std::string path, const FileType type); + + /** + * @brief Destructor. + */ ~ConfigCommands() { delete m_configfile; } + /** + * @brief setter for file type. + * @param FileType of files. + */ void setType(const FileType type); + + /** + * @brief Parse files for commands and store them into commands instance. + * @return a commands instance + */ Commands* getCommands(); private: + /** the configfile instance */ ConfigFile* m_configfile; + /** main path for configuration files */ std::string m_path; + /** valid file extension */ std::string m_extension; + /** vector of configuration files */ std::vector m_files; + /** + * @brief parse path for given file extension. + * @param path to configuration files. + * @param extension with file type. + */ void addFiles(const std::string path, const std::string extension); }; diff --git a/src/libebus/port.h b/src/libebus/port.h index 2b0dc12f..bb45ca4f 100644 --- a/src/libebus/port.h +++ b/src/libebus/port.h @@ -245,7 +245,7 @@ public: private: /** the device name */ std::string m_deviceName; - /** pointer to device instance */ + /** the device instance */ Device* m_device; /** true if device check is disabled */ bool m_noDeviceCheck; From e304d45f651bedd211d2e32afacbde44bd583fb5 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 31 Oct 2014 19:10:36 +0100 Subject: [PATCH 04/15] BUG: Appl::printArgs splitting of 'm_agrv' corrected to print executable name without path. --- src/libcore/appl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/appl.cpp b/src/libcore/appl.cpp index 795898f0..263f9554 100644 --- a/src/libcore/appl.cpp +++ b/src/libcore/appl.cpp @@ -62,7 +62,7 @@ void Appl::addItem(const char* name, Param param, const char* shortname, void Appl::printArgs() { std::cerr << std::endl << "Usage:" << std::endl << " " - << m_argv[0].substr(2) << " [OPTIONS...]" ; + << m_argv[0].substr(m_argv[0].find_last_of("/\\") + 1) << " [OPTIONS...]" ; if (m_argTxt.size() != 0) std::cerr << " " << m_argTxt; From b437b34836be318c8f24c38e1551e1dc6b2dfa7f Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Sun, 2 Nov 2014 11:21:04 +0100 Subject: [PATCH 05/15] code style. --- src/libebus/bus.cpp | 14 +++++++------- src/libebus/buscommand.cpp | 14 +++++--------- src/libebus/buscommand.h | 13 +++++++++---- src/libebus/port.cpp | 8 +++----- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/libebus/bus.cpp b/src/libebus/bus.cpp index 6748371c..5fa3fcc9 100644 --- a/src/libebus/bus.cpp +++ b/src/libebus/bus.cpp @@ -61,8 +61,8 @@ void Bus::printBytes() const int Bus::proceed() { - unsigned char byte_recv; - ssize_t bytes_recv; + unsigned char byte; + ssize_t nbytes; // fetch new message and get bus if (m_sendBuffer.size() != 0 && m_sstr.size() == 0) { @@ -71,18 +71,18 @@ int Bus::proceed() } // wait for new data - bytes_recv = m_port->recv(0); + nbytes = m_port->recv(0); - if (bytes_recv < 0) + if (nbytes < 0) return RESULT_ERR_DEVICE; - for (int i = 0; i < bytes_recv; i++) { + for (int i = 0; i < nbytes; i++) { // fetch next byte - byte_recv = recvByte(); + byte = recvByte(); // store byte - return proceedCycData(byte_recv); // TODO what if more than one byte was received? + return proceedCycData(byte); // TODO what if more than one byte was received? } return RESULT_SYN; diff --git a/src/libebus/buscommand.cpp b/src/libebus/buscommand.cpp index 59a6d891..0a09c52e 100644 --- a/src/libebus/buscommand.cpp +++ b/src/libebus/buscommand.cpp @@ -23,8 +23,8 @@ namespace libebus { -BusCommand::BusCommand(const std::string commandStr, const bool isPoll) - : m_isPoll(isPoll), m_command(commandStr), m_resultCode(RESULT_OK) +BusCommand::BusCommand(const std::string command, const bool isPoll) + : m_isPoll(isPoll), m_command(command), m_resultCode(RESULT_OK) { unsigned char dstAddress = m_command[1]; @@ -34,6 +34,7 @@ BusCommand::BusCommand(const std::string commandStr, const bool isPoll) m_type = masterMaster; else m_type = masterSlave; + pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_cond, NULL); } @@ -44,11 +45,6 @@ BusCommand::~BusCommand() pthread_cond_destroy(&m_cond); } -const char* BusCommand::getResultCodeCStr() -{ - return libebus::getResultCodeCStr(m_resultCode); -} - const std::string BusCommand::getMessageStr() { std::string result; @@ -62,9 +58,9 @@ const std::string BusCommand::getMessageStr() } else { result = "success"; } - } - else + } else { result = "error"; + } return result; } diff --git a/src/libebus/buscommand.h b/src/libebus/buscommand.h index b469ae3c..bf06e37d 100644 --- a/src/libebus/buscommand.h +++ b/src/libebus/buscommand.h @@ -34,17 +34,22 @@ class BusCommand { public: - BusCommand(const std::string commandStr, const bool isPoll); + BusCommand(const std::string command, const bool isPoll); ~BusCommand(); CommandType getType() const { return m_type; } bool isPoll() const { return m_isPoll; } + SymbolString getCommand() const { return m_command; } - bool isErrorResult() const { return m_resultCode < 0; } - const char* getResultCodeCStr(); SymbolString getResult() const { return m_result; } - void setResult(const SymbolString result, const int resultCode) { m_result = result; m_resultCode = resultCode; } + + bool isErrorResult() const { return m_resultCode < 0; } + const char* getResultCodeCStr() const { return libebus::getResultCodeCStr(m_resultCode); } + void setResult(const SymbolString result, const int resultCode) + { m_result = result; m_resultCode = resultCode; } + const std::string getMessageStr(); + void waitSignal() { pthread_cond_wait(&m_cond, &m_mutex); } // TODO timeout void sendSignal() { pthread_cond_signal(&m_cond); } diff --git a/src/libebus/port.cpp b/src/libebus/port.cpp index 8b1dd1c8..1951ed8a 100644 --- a/src/libebus/port.cpp +++ b/src/libebus/port.cpp @@ -86,18 +86,16 @@ ssize_t Device::recvBytes(const long timeout, size_t maxCount) return -2; // TODO RESULT_ERR_TIMEOUT } - ssize_t bytes_read = sizeof(m_buffer); if (maxCount > sizeof(m_buffer)) maxCount = sizeof(m_buffer); - // read bytes from device - bytes_read = read(m_fd, m_buffer, maxCount); + ssize_t nbytes = read(m_fd, m_buffer, maxCount); - for (int i = 0; i < bytes_read; i++) + for (int i = 0; i < nbytes; i++) m_recvBuffer.push(m_buffer[i]); - return bytes_read; + return nbytes; } unsigned char Device::getByte() From fce50774cd5de03b1f865e67b941646dd2b7b875 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Mon, 3 Nov 2014 15:58:03 +0100 Subject: [PATCH 06/15] Merge branch 'john30-master' --- .gitignore | 1 + src/ebusd/ebusloop.cpp | 2 +- src/libebus/Makefile.am | 2 + src/libebus/bus.cpp | 88 ++---- src/libebus/bus.h | 1 - src/libebus/buscommand.cpp | 11 +- src/libebus/data.cpp | 599 +++++++++++++++++++++++++++++++++++++ src/libebus/data.h | 313 +++++++++++++++++++ src/libebus/result.h | 1 + src/libebus/symbol.cpp | 125 ++++---- src/libebus/symbol.h | 66 ++-- src/test/Makefile.am | 4 + src/test/test_data.cpp | 110 +++++++ src/test/test_symbol.cpp | 16 +- 14 files changed, 1170 insertions(+), 169 deletions(-) create mode 100644 src/libebus/data.cpp create mode 100644 src/libebus/data.h create mode 100644 src/test/test_data.cpp diff --git a/.gitignore b/.gitignore index 119040b6..ef3fe657 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ Makefile.in /src/test/test_decode /src/test/test_encode /src/test/test_symbol +/src/test/test_data diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index d6d8a26b..6832d7b7 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -114,7 +114,7 @@ void* EBusLoop::run() // add new bus command to send if (busResult == RESULT_SYN && busCommandActive == false && m_sendBuffer.size() != 0) { BusCommand* busCommand = m_sendBuffer.remove(); - L.log(bus, debug, " msg: %s", busCommand->getCommand().getDataStr(true).c_str()); + L.log(bus, debug, " msg: %s", busCommand->getCommand().getDataStr().c_str()); m_bus->addCommand(busCommand); L.log(bus, debug, " addCommand success"); busCommandActive = true; diff --git a/src/libebus/Makefile.am b/src/libebus/Makefile.am index e5451b7b..e78d40bc 100644 --- a/src/libebus/Makefile.am +++ b/src/libebus/Makefile.am @@ -8,6 +8,8 @@ libebus_a_SOURCES = result.cpp \ result.h \ symbol.cpp \ symbol.h \ + data.cpp \ + data.h \ port.cpp \ port.h \ buscommand.cpp \ diff --git a/src/libebus/bus.cpp b/src/libebus/bus.cpp index 5fa3fcc9..e12d9ac2 100644 --- a/src/libebus/bus.cpp +++ b/src/libebus/bus.cpp @@ -27,7 +27,7 @@ namespace libebus Bus::Bus(const std::string deviceName, const bool noDeviceCheck, const long recvTimeout, const std::string dumpFile, const long dumpSize, const bool dumpState) - : m_previousEscape(false), m_recvTimeout(recvTimeout), m_dumpState(dumpState), + : m_sstr(), m_recvTimeout(recvTimeout), m_dumpState(dumpState), m_busLocked(false), m_busPriorRetry(false) { m_port = new Port(deviceName, noDeviceCheck); @@ -91,14 +91,13 @@ int Bus::proceed() int Bus::proceedCycData(const unsigned char byte) { if (byte != SYN) { - m_sstr.push_back_unescape(byte, m_previousEscape, false); + m_sstr.push_back(byte, true, false); if (m_busLocked == true) m_busLocked = false; return RESULT_DATA; } - m_previousEscape = false; if (byte == SYN && m_sstr.size() != 0) { // lock bus after SYN-BYTE-SYN Sequence if (m_sstr.size() == 1 && m_busPriorRetry == false) @@ -265,7 +264,7 @@ BusCommand* Bus::sendCommand() goto on_exit; // receive NN, Dx, CRC - slaveData = SymbolString(); + slaveData.clear(); retval = recvSlaveDataAndCRC(slaveData); // are calculated and received CRC equal? @@ -346,76 +345,39 @@ unsigned char Bus::recvByte() int Bus::recvSlaveDataAndCRC(SymbolString& result) { - unsigned char byte_recv; + unsigned char byte_recv, crc_calc = 0; ssize_t bytes_recv; - bool previousEscape = false; + size_t NN = 0; + bool updateCrc = true; + int retval = 0; - // receive NN - bytes_recv = m_port->recv(RECV_TIMEOUT, 1); - if (bytes_recv < 0) - return RESULT_ERR_TIMEOUT; - - byte_recv = recvByte(); - byte_recv = result.push_back_unescape(byte_recv, previousEscape); - if (previousEscape == true && byte_recv == 0) - return RESULT_ERR_ESC; - - // escape sequence: get another symbol to find NN - if (previousEscape == true) { + for (size_t i = 0, needed = 1; i < needed; i++) { bytes_recv = m_port->recv(RECV_TIMEOUT, 1); if (bytes_recv < 0) return RESULT_ERR_TIMEOUT; byte_recv = recvByte(); - byte_recv = result.push_back_unescape(byte_recv, previousEscape); - if (previousEscape == true) - return RESULT_ERR_ESC; + retval = result.push_back(byte_recv, true, updateCrc); + if (retval < 0) + return retval; + + if (retval == RESULT_IN_ESC) + needed++; + else if (result.size() == 1) { // NN received + NN = result[0]; + needed += NN; + } + else if (NN > 0 && result.size() == 1+NN) {// all data received + updateCrc = false; + crc_calc = result.getCRC(); + needed++; + } } - int NN = byte_recv; - - // receive Dx - for (int i = 0; i < NN; i++) { - bytes_recv = m_port->recv(RECV_TIMEOUT, 1); - if (bytes_recv < 0) - return RESULT_ERR_TIMEOUT; - - byte_recv = recvByte(); - byte_recv = result.push_back_unescape(byte_recv, previousEscape); - if (previousEscape == true && byte_recv == 0) - return RESULT_ERR_ESC; - - // escape sequence: increase NN - if (previousEscape == true) - NN++; - } - if (previousEscape == true) + if (retval == RESULT_IN_ESC) return RESULT_ERR_ESC; - unsigned char crc_calc = result.getCRC(); - // receive CRC - bytes_recv = m_port->recv(RECV_TIMEOUT, 1); - if (bytes_recv < 0) - return RESULT_ERR_TIMEOUT; - - byte_recv = recvByte(); - byte_recv = result.push_back_unescape(byte_recv, previousEscape, false); - if (previousEscape == true && byte_recv == 0) - return RESULT_ERR_ESC; - - // escape sequence: get another symbol to find CRC - if (previousEscape == true) { - bytes_recv = m_port->recv(RECV_TIMEOUT, 1); - if (bytes_recv < 0) - return RESULT_ERR_TIMEOUT; - - byte_recv = recvByte(); - byte_recv = result.push_back_unescape(byte_recv, previousEscape); - if (previousEscape == true) - return RESULT_ERR_ESC; - } - - if (crc_calc != byte_recv) + if (updateCrc || crc_calc != result[result.size()-1]) return RESULT_ERR_CRC; return RESULT_OK; diff --git a/src/libebus/bus.h b/src/libebus/bus.h index be07313c..d752dbd7 100644 --- a/src/libebus/bus.h +++ b/src/libebus/bus.h @@ -64,7 +64,6 @@ public: private: Port* m_port; - bool m_previousEscape; SymbolString m_sstr; std::queue m_cycBuffer; std::queue m_sendBuffer; diff --git a/src/libebus/buscommand.cpp b/src/libebus/buscommand.cpp index 0a09c52e..e7c35dd0 100644 --- a/src/libebus/buscommand.cpp +++ b/src/libebus/buscommand.cpp @@ -22,9 +22,8 @@ namespace libebus { - -BusCommand::BusCommand(const std::string command, const bool isPoll) - : m_isPoll(isPoll), m_command(command), m_resultCode(RESULT_OK) +BusCommand::BusCommand(const std::string commandStr, const bool isPoll) + : m_isPoll(isPoll), m_command(commandStr), m_result(), m_resultCode(RESULT_OK) { unsigned char dstAddress = m_command[1]; @@ -51,16 +50,16 @@ const std::string BusCommand::getMessageStr() if (m_resultCode >= 0) { if (m_type == masterSlave) { - result = m_command.getDataStr(true); + result = m_command.getDataStr(); result += "00"; result += m_result.getDataStr(); result += "00"; } else { result = "success"; } - } else { - result = "error"; } + else + result = "error: "+std::string(getResultCodeCStr()); return result; } diff --git a/src/libebus/data.cpp b/src/libebus/data.cpp new file mode 100644 index 00000000..c2065727 --- /dev/null +++ b/src/libebus/data.cpp @@ -0,0 +1,599 @@ +/* + * Copyright (C) John Baier 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/. + */ + +#include "data.h" +#include "decode.h" +#include "encode.h" +#include +#include +#include +#include +#include +#include + +namespace libebus +{ + +/** the known data field types. */ +static const dataType_t dataTypes[] = { + {"STR",16, bt_str, ADJ,' ', 1, 16, 0}, // >= 1 byte character string filled up with space + {"HEX",16, bt_hexstr,ADJ, 0, 2, 47, 0}, // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d + {"BDA", 4, bt_date, BCD, 0, 10, 10, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) + {"BDA", 3, bt_date, BCD, 0, 10, 10, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) + {"HDA", 4, bt_date, 0, 0, 10, 10, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) // TODO remove duplicate of BDA + {"HDA", 3, bt_date, 0, 0, 10, 10, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) // TODO remove duplicate of BDA + {"BTI", 3, bt_time,BCD|REV,0, 8, 8, 0}, // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23) + {"TTM", 1, bt_time, 0, 0, 5, 5, 0}, // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer) + {"BDY", 1, bt_list,BCD|DAY,0, 0, 6, 0}, // weekday, "Mon" - "Sun" + {"HDY", 1, bt_list,BCD|DAY,0, 1, 7, 0}, // weekday, "Mon" - "Sun" + {"BCD", 1, bt_number,BCD|LST,0xff, 0, 0x99, 1}, // unsigned decimal in BCD, 0 - 99 + {"UCH", 1, bt_number, LST, 0xff, 0, 0xff, 1}, // unsigned integer, 0 - 255 + {"SCH", 1, bt_number, SIG, 0x80, 0x80, 0x7f, 1}, // signed integer, -128 - +127 + {"D1B", 1, bt_number, SIG, 0x80, 0x81, 0x7f, 1}, // signed integer, -127 - +127 + {"D1C", 1, bt_number, 0, 0xff, 0x00, 0xc8, 2}, // unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff) + {"UIN", 2, bt_number, LST, 0xffff, 0, 0xffff, 1}, // unsigned integer, 0 - 65535 + {"SIN", 2, bt_number, SIG, 0x8000, 0x8000, 0x7fff, 1}, // signed integer, -32768 - +32767 + {"FLT", 2, bt_number, SIG, 0x8000, 0x8000, 0x7fff, 1000}, // signed number (fraction 1/1000), -32.768 - +32.767 + {"D2B", 2, bt_number, SIG, 0x8000, 0x8001, 0x7fff, 256}, // signed number (fraction 1/256), -127.99 - +127.99 + {"D2C", 2, bt_number, SIG, 0x8000, 0x8001, 0x7fff, 16}, // signed number (fraction 1/16), -2047.9 - +2047.9 + {"ULG", 4, bt_number, LST, 0xffffffff, 0, 0xffffffff, 1}, // unsigned integer, 0 - 4294967295 + {"SLG", 4, bt_number, SIG, 0x80000000, 0x80000000, 0xffffffff, 1}, // signed integer, -2147483648 - +2147483647 +}; // TODO check value range for numberdf + +/** the week day names. */ +static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; + + +DataField* DataField::create(const unsigned char dstAddress, const bool isSetMessage, + std::vector::iterator& it, const std::vector::iterator end) { + std::string name, unit, comment; + PartType partType; + float factor; + size_t baseOffset = 0, offset = 0, length = 0, maxPos = 16, offsetCnt = 0; + + if (it == end) + return NULL; + name = *it++; + if (it == end || name.size() == 0) + return NULL; + const char* posStr = (*it++).c_str(); + if (it == end) + return NULL; + if (dstAddress == BROADCAST + || isMaster(dstAddress) + || (isSetMessage == true && posStr[0] <= '9') + || posStr[0] == 'm') { // master data + partType = pt_masterData; + baseOffset = 5; // skip QQ ZZ PB SB NN + //len = command.getMasterDataLength(); + if (posStr[0] == 'm') + posStr++; + } else if ((isSetMessage == false && posStr[0] <= '9') + || posStr[0] == 's') { // slave data + baseOffset = 1; + //offset = 5+command.getMasterDataLength()+3; // skip QQ ZZ PB SB NN Dx CRC ACK NN + //len = command.getSlaveDataLength(); + if (posStr[0] == 's') + posStr++; + } else { + return NULL; // TODO error code: invalid pos definition + } + std::string token; + std::istringstream stream(posStr); + while (std::getline(stream, token, '-') != 0) { + if (++offsetCnt > 2) + return NULL; // TODO error code: invalid pos definition + const char* start = token.c_str(); + char* end = NULL; + unsigned int pos = strtoul(start, &end, 10)-1; // 1-based + if (end != start+strlen(start)) + return NULL; // TODO error code: invalid pos definition + if (baseOffset+pos > maxPos) + return NULL; // TODO error code: invalid pos definition + else if (offsetCnt==1) + offset = baseOffset+pos; + else if (baseOffset+pos >= offset) + length = baseOffset+pos+1-offset; + else { // wrong order e.g. 4-3 + length = offset-(baseOffset+pos+1); + offset = baseOffset+pos; + } + } + + const char* typeStr = (*it++).c_str(); + + std::map values; + if (it == end) + factor = 1.0; + else { + std::string factorStr = *it++; + if (factorStr.empty()) + factor = 1.0; + else if (factorStr.find_first_not_of("0123456789.") == std::string::npos) + factor = static_cast(strtod(factorStr.c_str(), NULL)); + else { + factor = 1.0; + std::istringstream stream(factorStr); + while (std::getline(stream, token, ',') != 0) { + const char* start = token.c_str(); + char* end = NULL; + unsigned int id = strtoul(start, &end, 10); + if (end == NULL || end == start || *end != '=') + return NULL; // TODO error code: invalid values definition + values[id] = std::string(end+1); + } + } + } + + if (it == end) + unit = ""; + else { + unit = *it++; + + if (unit.length() == 1 && unit[0] == '-') + unit.clear(); + } + + if (it == end) + comment = ""; + else { + comment = *it++; + if (comment.length() == 1 && comment[0] == '-') + comment.clear(); + } + + for (size_t i = 0; i < sizeof(dataTypes)/sizeof(dataTypes[0]); i++) { + dataType_t dataType = dataTypes[i]; + if (strcasecmp(typeStr, dataType.name) == 0) { + if ((dataType.flags&ADJ) != 0) { + if (length == 0) + length = 1; // minimum length defaults to 1 + else if (length > dataType.numBytes) + return NULL; // invalid length + } + else if (length == 0) + length = dataType.numBytes; + else if (length != dataType.numBytes) + continue; // check for another one with same name but different length + + switch (dataType.type) { + case bt_str: + case bt_hexstr: + case bt_date: // TODO better numeric? + case bt_time: // TODO better numeric? + return new StringDataField(name, partType, offset, length, dataType, unit, comment); + case bt_list: + if (values.empty() == false) { + if (values.begin()->first < dataType.minValueOrLength) + return NULL; // invalid value id + std::map::iterator end = values.end(); + end--; + if (end->first > dataType.maxValueOrLength) + return NULL; // invalid value id + } + else if ((dataType.flags&DAY) != 0) { + for (unsigned int i=0; i 0) + output << " " << m_unit; + if (verbose && m_comment.length() > 0) + output << " [" << m_comment << "]"; + return output.str(); +} + +bool DataField::write(const std::string& value, SymbolString& masterData, SymbolString& slaveData) +{ + SymbolString& output = m_partType == pt_masterData ? masterData : slaveData; + switch (m_partType) { + case pt_masterData: + case pt_slaveData: + break; + default: + return false; // TODO error code + } + std::istringstream input(value); + if (writeSymbols(input, output) == false) + return false; // TODO error code + return true; +} + + + +bool StringDataField::readSymbols(SymbolString& input, std::ostringstream& output) +{ + size_t start = m_offset, end = m_offset + m_length; + int incr = 1; + unsigned char ch; + + if (end > input.size()) + return false; // TODO error not enough data available + + if ((m_dataType.flags&REV) != 0) { // reverted binary representation (most significant byte first) + end = start - 1; + start = m_offset + m_length - 1; + incr = -1; + } + + for (size_t pos = start, i = 0; pos != end; pos += incr, i++) { + if (m_length == 4 && i == 2 && m_dataType.type == bt_date) + continue; // skip weekday in between + ch = input[pos]; + if ((m_dataType.flags & BCD) != 0) { + if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) + return false; // invalid BCD + ch = (ch >> 4) * 10 + (ch & 0x0f); + } + switch (m_dataType.type) { + case bt_hexstr: + if (i > 0) + output << ' '; + output << std::nouppercase << std::setw(2) << std::hex + << std::setfill('0') << static_cast(ch); + break; + case bt_date: + if (i + 1 == m_length) + output << (2000+ch); + else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12)) + return false; // invalid date + else + output << std::setw(2) << std::setfill('0') << static_cast(ch) << "."; + break; + case bt_time: + if (m_length == 1) { // truncated time + if (ch > 24*6) + return false; // invalid time + output << std::setw(2) << std::setfill('0') << static_cast(ch/6) << ":" + << std::setw(2) << std::setfill('0') << static_cast((ch%6)*10); + break; + } + if (i > 0) + output << ":"; + if ((i == 0 && ch > 23) || (i > 0 && ch > 59)) + return false; // invalid time + output << std::setw(2) << std::setfill('0') << static_cast(ch); + break; + default: + if (ch < 0x20) + ch = m_dataType.replacement; + output << static_cast(ch); + break; + } + } + + return true; +} + +bool StringDataField::writeSymbols(std::istringstream& input, SymbolString& output) +{ + size_t start = m_offset, end = m_offset + m_length; + int incr = 1; + const char* str; + char* strEnd; + unsigned long int value = 0, minutes = 0; + std::string token; + + if ((m_dataType.flags&REV) != 0) { // reverted binary representation (most significant byte first) + end = start - 1; + start = m_offset + m_length - 1; + incr = -1; + } + + for (size_t pos = start, i = 0; pos != end; pos += incr, i++) { + switch (m_dataType.type) { + case bt_hexstr: + while (input.peek()==' ') + input.get(); + token.clear(); + token.push_back(input.get()); + if (input.eof() == true) + return false; // TODO error code: invalid value + token.push_back(input.get()); + if (input.eof() == true) + return false; // TODO error code: invalid value + + str = token.c_str(); + strEnd = NULL; + value = strtoul(str, &strEnd, 16); + if (strEnd != str+strlen(str)) + return false; // TODO error code: invalid value + break; + case bt_date: + if (m_length == 4 && i == 2) + continue; // skip weekday in between + if (std::getline(input, token, '.') == 0) + return false; + str = token.c_str(); + strEnd = NULL; + value = strtoul(str, &strEnd, 10); + if (strEnd != str+strlen(str)) + return false; // TODO error code: invalid value + if (i + 1 == m_length && value >= 2000) + value -= 2000; + else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) + return false; // invalid date + break; + case bt_time: + if (std::getline(input, token, ':') == 0) + return false; + str = token.c_str(); + strEnd = NULL; + value = strtoul(str, &strEnd, 10); + if (strEnd != str+strlen(str)) + return false; // TODO error code: invalid value + if (m_length == 1) { // truncated time + if (std::getline(input, token, ':') == 0) + return false; + str = token.c_str(); + strEnd = NULL; + minutes = strtoul(str, &strEnd, 10); + if (strEnd != str+strlen(str)) + return false; // TODO error code: invalid value + if ((minutes % 10) != 0) + return false; // invalid time + value = value*6 + (minutes / 10); + if (value > 24*6) + return false; // invalid time + break; + } + if ((i == 0 && value > 23) || (i > 0 && value > 59)) + return false; // invalid time + break; + default: + value = input.get(); + if (input.eof() == true || value < 0x20) + value = m_dataType.replacement; + break; + } + if ((m_dataType.flags & BCD) != 0) { + if (value > 99) + return false; // invalid BCD + value = (value/10)<<4 | (value%10); + } + if (value > 0xff) + return false; + output[pos] = (unsigned char)value; + } + + return true; +} + + +bool NumericDataField::readRawValue(SymbolString& input, unsigned int& value) +{ + size_t start = m_offset, end = m_offset + m_length; + int incr = 1; + unsigned char ch; + + if (end > input.size()) + return false; // TODO error not enough data available + + if ((m_dataType.flags&REV) != 0) { // reverted binary representation (most significant byte first) + end = start - 1; + start = m_offset + m_length - 1; + incr = -1; + } + + value = 0; + for (size_t pos = start, exp = 1; pos != end; pos += incr) { + ch = input[pos]; + if ((m_dataType.flags & BCD) != 0) { + if (ch == m_dataType.replacement) { + value = m_dataType.replacement; + return true; + } + if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) + return false; // invalid BCD + + ch = (ch >> 4) * 10 + (ch & 0x0f); + value += ch*exp; + exp = exp*100; + } + else { + value |= ch*exp; + exp = exp<<8; + } + } + return true; +} + +bool NumericDataField::writeRawValue(unsigned int value, SymbolString& output) +{ + size_t start = m_offset, end = m_offset + m_length; + int incr = 1; + unsigned char ch; + + if ((m_dataType.flags&REV) != 0) { // reverted binary representation (most significant byte first) + end = start - 1; + start = m_offset + m_length - 1; + incr = -1; + } + + for (size_t pos = start, exp = 1; pos != end; pos += incr) { + if ((m_dataType.flags & BCD) != 0) { + if (value == m_dataType.replacement) + ch = m_dataType.replacement; + else { + ch = (value/exp)%100; + ch = ((ch/10)<<4) | (ch%10); + } + exp = exp*100; + } + else { + ch = (value/exp)&0xff; + exp = exp<<8; + } + output[pos] = ch; + } + + return true; +} + + +bool NumberDataField::readSymbols(SymbolString& input, std::ostringstream& output) +{ + unsigned int value = 0; + int signedValue; + + if (readRawValue(input, value) == false) + return false; + + if (value == m_dataType.replacement) { + output << "-"; + return true; + } + + if ((m_dataType.flags&SIG) != 0 && (value & (1 << (m_dataType.numBytes*8 - 1))) != 0) // negative signed value + if (m_dataType.numBytes == 4) + signedValue = (int)value; + else + signedValue = (int)value - (1 << (m_dataType.numBytes*8)); + else { + if (m_dataType.numBytes == 4) { + if (m_factor == 1.0) + output << static_cast(value); + else + output << std::setprecision(3) << std::fixed << static_cast(value * m_factor); + return true; + } + + signedValue = (int)value; + } + + if (m_factor == 1.0) + output << static_cast(signedValue); + else + output << std::setprecision(3) << std::fixed << static_cast(signedValue * m_factor); + + return true; +} + +bool NumberDataField::writeSymbols(std::istringstream& input, SymbolString& output) +{ + unsigned int value; + + const char* str = input.str().c_str(); + if (strcasecmp(str, "-") == 0) + // replacement value + value = m_dataType.replacement; + else { + char* strEnd = NULL; + if (m_factor == 1.0) { + if ((m_dataType.flags&SIG) != 0) { + int signedValue = strtol(str, &strEnd, 10); + if (signedValue < 0 && m_dataType.numBytes != 4) + value = (unsigned int)(signedValue + (1<<(m_dataType.numBytes*8))); + else + value = (unsigned int)signedValue; + } + else + value = strtoul(str, &strEnd, 10); + if (strEnd != str+strlen(str)) + return false; // TODO error code: invalid value + } + else { + char* strEnd = NULL; + double dvalue = strtod(str, &strEnd); + if (strEnd != str+strlen(str)) + return false; // TODO error code: invalid value + dvalue = dvalue / m_factor + 0.5; // round + if ((m_dataType.flags&SIG) != 0) { + if (dvalue < -(1LL<<(8*m_length)) || dvalue >= (1LL<<(8*m_length))) + return false; // TODO error code: invalid value + if (dvalue < 0 && m_dataType.numBytes != 4) + value = (unsigned int)(dvalue + (1<<(m_dataType.numBytes*8))); + else + value = (unsigned int)dvalue; + } + else { + if (dvalue < 0.0 || dvalue >= (1LL<<(8*m_length))) + return false; // TODO error code: invalid value + value = (unsigned int)dvalue; + } + } + } + + return writeRawValue(value, output); +} + + +bool ValueListDataField::readSymbols(SymbolString& input, std::ostringstream& output) +{ + unsigned int value = 0; + + if (readRawValue(input, value) == false) + return false; + + if (value == m_dataType.replacement) { + output << "-"; + return true; + } + + std::map::iterator it = m_values.find(value); + if (it == m_values.end()) + return false; + + output << it->second; + return true; +} + +bool ValueListDataField::writeSymbols(std::istringstream& input, SymbolString& output) +{ + std::string str; + input >> str; + + for (std::map::iterator it = m_values.begin(); it != m_values.end(); it++) + if (it->second.compare(str) == 0) + return writeRawValue(it->first, output); + + return false; +} + + +} //namespace + diff --git a/src/libebus/data.h b/src/libebus/data.h new file mode 100644 index 00000000..bd5d40c1 --- /dev/null +++ b/src/libebus/data.h @@ -0,0 +1,313 @@ +/* + * Copyright (C) John Baier 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_DATA_H_ +#define LIBEBUS_DATA_H_ + +#include "symbol.h" +#include +#include +#include + +namespace libebus +{ + + +/** the message part in which a data field is stored. */ +enum PartType { + pt_masterData, // stored in master data + pt_slaveData, // stored in slave data + }; + +/** the available base data types. */ +enum BaseType { + bt_str, // text string in a StringDataField + bt_hexstr, // hex digit string in a StringDataField + bt_date, // date in a StringDataField + bt_time, // time in a StringDataField + bt_list, // numeric list value in a ValueListDataField + bt_number // number value in a NumberDataField +}; + +/** flags for dataType_t. */ +const unsigned int ADJ = 0x01; // adjustable length, numBytes is maximum length +const unsigned int BCD = 0x02; // binary representation is BCD +const unsigned int REV = 0x04; // reverted binary representation (most significant byte first) +const unsigned int SIG = 0x08; // signed value +const unsigned int LST = 0x10; // value list is possible (without applied factor) +const unsigned int DAY = 0x20; // default value list is week days + +/** the structure for defining field types with their properties. */ +typedef struct { + const char* name; // field identifier + const unsigned int numBytes; // number of bytes (maximum length if ADJ flag is set) + const BaseType type; // base data type + const unsigned int flags; // flags (e.g. BCD) + const unsigned int replacement; // replacement value (fill-up value for bt_str/bt_hexstr) + const unsigned int minValueOrLength; // minimum binary value (minimum length of string for StringDataField) + const unsigned int maxValueOrLength; // maximum binary value (maximum length of string for StringDataField) + const unsigned int divisor; // divisor for bt_number values (or 0 for non-numeric) +} dataType_t; + + +/** + * @brief Base class for all kinds of data fields. + */ +class DataField +{ +public: + /** + * @brief Constructs a new instance. + * @param name the field name. + * @param partType the message part in which the field is stored. + * @param offset the offset to the first symbol in the message part in which the field is stored. + * @param length the number of symbols in the message part in which the field is stored. + * @param dataType the data type definition. + * @param unit the value unit. + * @param comment the field comment. + */ + DataField(const std::string name, const PartType partType, + const unsigned char offset, const unsigned char length, + const dataType_t dataType, const std::string unit, + const std::string comment) + : m_name(name), m_partType(partType), m_offset(offset), + m_length(length), m_dataType(dataType), m_unit(unit), + m_comment(comment) {} + /** + * @brief Destructor. + */ + virtual ~DataField() {} + + /** + * @brief Factory method for creating a new instance. + * @param dstAddress the destination bus address. + * @param isSetMessage whther the field is part of a set message. + * @param it the iterator to traverse for the definition parts. + * @param end the iterator pointing to the end of the definition parts. + */ + static DataField* create(const unsigned char dstAddress, const bool isSetMessage, + std::vector::iterator& it, const std::vector::iterator end); + + /** + * @brief Reads the value from the master or slave @a SymbolString. + * @param masterData the unescaped master data @a SymbolString for reading binary data. + * @param slaveData the unescaped slave data @a SymbolString for reading binary data. + * @return the formatted value as string. + */ + const std::string read(SymbolString& masterData, SymbolString& slaveData, bool verbose=false); + /** + * @brief Writes the value to the master or slave @a SymbolString. + * @param masterData the unescaped master data @a SymbolString for writing binary data. + * @param slaveData the unescaped slave data @a SymbolString for writing binary data. + * @param value the formatted value as string. + */ + bool write(const std::string& value, SymbolString& masterData, SymbolString& slaveData); + +protected: + /** + * @brief Internal method for reading the field from a @a SymbolString. + * @param input the unescaped @a SymbolString to read the binary value from. + * @param output the ostringstream to append the formatted value to. + * @return true if the value was parsed successfully. + */ + virtual bool readSymbols(SymbolString& input, std::ostringstream& output) = 0; + /** + * @brief Internal method for writing the field to a @a SymbolString. + * @param input the istringstream to parse the formatted value from. + * @param output the unescaped @a SymbolString to write the binary value to. + * @return true if the value was formatted successfully. + */ + virtual bool writeSymbols(std::istringstream& input, SymbolString& output) = 0; + + /** the field name. */ + const std::string m_name; + /** the message part in which the field is stored. */ + const PartType m_partType; + /** the offset to the first symbol in the message part in which the field is stored. */ + const unsigned char m_offset; + /** the number of symbols in the message part in which the field is stored. */ + const unsigned char m_length; + /** the data type definition. */ + const dataType_t m_dataType; + /** the value unit. */ + const std::string m_unit; + /** the field comment. */ + const std::string m_comment; +}; + + +/** + * @brief Base class for all string based data fields. + */ +class StringDataField : public DataField +{ +public: + /** + * @brief Constructs a new instance. + * @param name the field name. + * @param partType the message part in which the field is stored. + * @param offset the offset to the first symbol in the message part in which the field is stored. + * @param length the number of symbols in the message part in which the field is stored. + * @param dataType the data type definition. + * @param unit the value unit. + * @param comment the field comment. + */ + StringDataField(const std::string name, const PartType partType, + const unsigned char offset, const unsigned char length, + const dataType_t dataType, const std::string unit, + const std::string comment) + : DataField(name, partType, offset, length, dataType, unit, comment) {} + /** + * @brief Destructor. + */ + virtual ~StringDataField() {} + +protected: + virtual bool readSymbols(SymbolString& input, std::ostringstream& output); + virtual bool writeSymbols(std::istringstream& input, SymbolString& output); + +}; + + +/** + * @brief Base class for all numeric data fields. + */ +class NumericDataField : public DataField +{ +public: + /** + * @brief Constructs a new instance. + * @param name the field name. + * @param partType the message part in which the field is stored. + * @param offset the offset to the first symbol in the message part in which the field is stored. + * @param length the number of symbols in the message part in which the field is stored. + * @param dataType the data type definition. + * @param comment the field comment. + * @param unit the value unit. + * @param replacement the (binary) replacement value to use if the value is not set. + */ + NumericDataField(const std::string name, const PartType partType, + const unsigned char offset, const unsigned char length, + const dataType_t dataType, const std::string unit, + const std::string comment) + : DataField(name, partType, offset, length, dataType, unit, comment) {} + /** + * @brief Destructor. + */ + virtual ~NumericDataField() {} + +protected: + /** + * @brief Internal method for reading the raw value from a @a SymbolString. + * @param input the unescaped @a SymbolString to read the binary value from. + * @param value the variable in which to store the raw value. + * @return true if the value was read successfully. + */ + bool readRawValue(SymbolString& input, unsigned int& value); + /** + * @brief Internal method for writing the raw value to a @a SymbolString. + * @param value the raw value to write. + * @param output the unescaped @a SymbolString to write the binary value to. + * @return true if the value was written successfully. + */ + bool writeRawValue(unsigned int value, SymbolString& output); + +}; + +/** + * @brief Base class for all numeric data fields with a number representation. + */ +class NumberDataField : public NumericDataField +{ +public: + /** + * @brief Constructs a new instance. + * @param name the field name. + * @param partType the message part in which the field is stored. + * @param offset the offset to the first symbol in the message part in which the field is stored. + * @param length the number of symbols in the message part in which the field is stored. + * @param dataType the data type definition. + * @param comment the field comment. + * @param unit the value unit. + * @param replacement the (binary) replacement value to use if the value is not set. + * @param factor the factor to apply on the value. + */ + NumberDataField(const std::string name, const PartType partType, + const unsigned char offset, const unsigned char length, + const dataType_t dataType, const std::string unit, + const std::string comment, const float factor) + : NumericDataField(name, partType, offset, length, dataType, unit, comment), + m_factor(factor / dataType.divisor) {} + /** + * @brief Destructor. + */ + virtual ~NumberDataField() {} + +protected: + virtual bool readSymbols(SymbolString& input, std::ostringstream& output); + virtual bool writeSymbols(std::istringstream& input, SymbolString& output); + + /** the factor to apply on the value. */ + const float m_factor; + +}; + +/** + * @brief A numeric data field with a list of value=text assignments and a string representation. + */ +class ValueListDataField : public NumericDataField +{ +public: + /** + * @brief Constructs a new instance. + * @param name the field name. + * @param partType the message part in which the field is stored. + * @param offset the offset to the first symbol in the message part in which the field is stored. + * @param length the number of symbols in the message part in which the field is stored. + * @param dataType the data type definition. + * @param comment the field comment. + * @param unit the value unit. + * @param factor the factor to apply on the value. + * @param replacement the (binary) replacement value to use if the value is not set. + * @param values the value=text assignments. + */ + ValueListDataField(const std::string name, const PartType partType, + const unsigned char offset, const unsigned char length, + const dataType_t dataType, const std::string unit, + const std::string comment, const std::map values) + : NumericDataField(name, partType, offset, length, dataType, unit, comment), + m_values(values) {} + /** + * @brief Destructor. + */ + virtual ~ValueListDataField() {} + +protected: + virtual bool readSymbols(SymbolString& input, std::ostringstream& output); + virtual bool writeSymbols(std::istringstream& input, SymbolString& output); + + /** the value=text assignments. */ + std::map m_values; + +}; + + +} //namespace + +#endif // LIBEBUS_DATA_H_ diff --git a/src/libebus/result.h b/src/libebus/result.h index dd669e8f..7a439382 100644 --- a/src/libebus/result.h +++ b/src/libebus/result.h @@ -31,6 +31,7 @@ static const int RESULT_DATA = 2; // some data received static const int RESULT_SYN = 3; // regular SYN after message received static const int RESULT_BUS_LOCKED = 4; // bus is locked for access static const int RESULT_BUS_PRIOR_RETRY = 5; // retry to access bus +static const int RESULT_IN_ESC = 6; // start of escape sequence received static const int RESULT_ERR_SEND = -1; // send error static const int RESULT_ERR_EXTRA_DATA = -2; // received bytes > sent bytes diff --git a/src/libebus/symbol.cpp b/src/libebus/symbol.cpp index 2d35aa19..a1110157 100644 --- a/src/libebus/symbol.cpp +++ b/src/libebus/symbol.cpp @@ -18,6 +18,7 @@ */ #include "symbol.h" +#include "result.h" #include #include @@ -27,7 +28,7 @@ namespace libebus /** * @brief CRC8 lookup table for the polynom 0x9b = x^8 + x^7 + x^4 + x^3 + x^1 + 1. */ -static const unsigned char CRC_LOOKUP_TABLE[] +static const unsigned char CRC_LOOKUP_TABLE[] = { 0x00, 0x9b, 0xad, 0x36, 0xc1, 0x5a, 0x6c, 0xf7, 0x19, 0x82, 0xb4, 0x2f, 0xd8, 0x43, 0x75, 0xee, 0x32, 0xa9, 0x9f, 0x04, 0xf3, 0x68, 0x5e, 0xc5, 0x2b, 0xb0, 0x86, 0x1d, 0xea, 0x71, 0x47, 0xdc, @@ -49,41 +50,35 @@ static const unsigned char CRC_LOOKUP_TABLE[] SymbolString::SymbolString(const std::string str) - : m_crc(0) + : m_unescapeState(0), m_crc(0) { // parse + escape for (size_t i = 0; i+1 < str.size(); i += 2) { - unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16); - push_back_escape((unsigned char)value); + unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16); // TODO check + push_back((unsigned char)value, false, true); } // add CRC + escape - push_back_escape(m_crc, false); + push_back(m_crc, false, false); } -SymbolString::SymbolString(const std::string str, bool escaped) - : m_crc(0) +SymbolString::SymbolString(const std::string str, bool isEscaped) + : m_unescapeState(1), m_crc(0) { - bool previousEscape = false; - // parse + optionally unescape for (size_t i = 0; i+1 < str.size(); i += 2) { - unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16); - if (escaped == true) { - push_back_unescape((unsigned char)value, previousEscape, false); - } - else - m_data.push_back((unsigned char)value); + unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16); // TODO check + push_back((unsigned char)value, isEscaped, false); } } -const std::string SymbolString::getDataStr(bool unescape) +const std::string SymbolString::getDataStr(const bool unescape) { std::stringstream sstr; bool previousEscape = false; - for (size_t i = 0; i < size(); i++) { - unsigned char value = at(i); - if (unescape == true && previousEscape == true) { + for (size_t i = 0; i < m_data.size(); i++) { + unsigned char value = m_data[i]; + if (m_unescapeState == 0 && unescape == true && previousEscape == true) { if (value == 0x00) { sstr << "a9"; // ESC } @@ -95,7 +90,7 @@ const std::string SymbolString::getDataStr(bool unescape) } previousEscape = false; } - else if (unescape == true && value == ESC) { + else if (m_unescapeState == 0 && unescape == true && value == ESC) { previousEscape = true; // escape sequence not yet finished } else { @@ -107,56 +102,80 @@ const std::string SymbolString::getDataStr(bool unescape) return sstr.str(); } -void SymbolString::push_back_escape(const unsigned char value, bool updateCRC) +int SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) { - if (value == ESC) { - m_data.push_back(ESC); - m_data.push_back(0x00); - if (updateCRC) { - addCRC(ESC); - addCRC(0x00); + if (m_unescapeState == 0) { // store escaped data + if (isEscaped == false && value == ESC) { + m_data.push_back(ESC); + m_data.push_back(0x00); + if (updateCRC) { + addCRC(ESC); + addCRC(0x00); + } } - } - else if (value == SYN) { - m_data.push_back(ESC); - m_data.push_back(0x01); - if (updateCRC) { - addCRC(ESC); - addCRC(0x01); + else if (isEscaped == false && value == SYN) { + m_data.push_back(ESC); + m_data.push_back(0x01); + if (updateCRC) { + addCRC(ESC); + addCRC(0x01); + } } + else { + m_data.push_back(value); + if (updateCRC) { + addCRC(value); + } + } + return RESULT_OK; } - else { + else if (isEscaped == false) { + if (m_unescapeState != 1) + return RESULT_ERR_ESC; // invalid unescape state m_data.push_back(value); + if (updateCRC) { + if (value == ESC) { + addCRC(ESC); + addCRC(0x00); + } + else if (value == SYN) { + addCRC(ESC); + addCRC(0x01); + } + else { + addCRC(value); + } + } + return RESULT_OK; + } + else if (m_unescapeState != 1) { if (updateCRC) { addCRC(value); } - } -} - -unsigned char SymbolString::push_back_unescape(const unsigned char value, bool& previousEscape, bool updateCRC) -{ - if (updateCRC) { - addCRC(value); - } - if (previousEscape == true) { if (value == 0x00) { m_data.push_back(ESC); - previousEscape = false; - return ESC; + m_unescapeState = 1; + return RESULT_OK; } if (value == 0x01) { m_data.push_back(SYN); - previousEscape = false; - return SYN; + m_unescapeState = 1; + return RESULT_OK; } - return 0; // invalid escape sequence + return RESULT_ERR_ESC; // invalid escape sequence } - if (value == ESC) { - previousEscape = true; - return 1; // escape sequence not yet finished + else if (value == ESC) { + if (updateCRC) { + addCRC(value); + } + m_unescapeState = 2; + return RESULT_IN_ESC; + } + if (updateCRC) { + addCRC(value); } m_data.push_back(value); - return value; + return RESULT_OK; } void SymbolString::addCRC(const unsigned char value) { diff --git a/src/libebus/symbol.h b/src/libebus/symbol.h index 9fd31508..833e1c1e 100644 --- a/src/libebus/symbol.h +++ b/src/libebus/symbol.h @@ -37,72 +37,62 @@ static const unsigned char BROADCAST = 0xFE; // the broadcast destination addres /** - * @brief A string of bus symbols. + * @brief A string of escaped or unescaped bus symbols. */ class SymbolString { public: /** - * @brief Creates a new empty SymbolString. + * @brief Creates a new unescaped empty instance. + * @param escaped whether to create an escaped instance. */ - SymbolString() : m_crc(0) {} + SymbolString() : m_unescapeState(1), m_crc(0) {} /** - * @brief Creates a new escaped SymbolString from an unescaped hex string and adds the calculated CRC. + * @brief Creates a new escaped instance from an unescaped hex string and adds the calculated CRC. * @param str the unescaped hex string. */ SymbolString(const std::string str); /** - * @brief Creates a new unescaped SymbolString from a hex string. - * @param escaped whether the hex string is escaped and shall be unescaped. + * @brief Creates a new unescaped instance from a hex string. + * @param isEscaped whether the hex string is escaped and shall be unescaped. * @param str the hex string. */ - SymbolString(const std::string str, bool escaped); + SymbolString(const std::string str, const bool isEscaped); /** * @brief Returns the symbols as hex string. - * @param escaped whether to unescape the symbols. + * @param unescape whether to unescape an escaped instance. * @return the symbols as hex string. */ - const std::string getDataStr(bool unescape=false); + const std::string getDataStr(const bool unescape=true); /** - * @brief Returns the symbol at the specified index. + * @brief Returns a reference to the symbol at the specified index. * @param index the index of the symbol to return. - * @return the symbol at the specified index. - * @throw std::out_of_range if @a index is invalid. + * @return the reference to the symbol at the specified index. */ - unsigned char at(const size_t index) { return m_data.at(index); } + unsigned char& operator[](const size_t index) { if (index >= m_data.size()) m_data.resize(index+1, 0); return m_data[index]; } /** * @brief Returns the symbol at the specified index. * @param index the index of the symbol to return. * @return the symbol at the specified index. */ - unsigned char operator[](const size_t index) { return m_data[index]; } + const unsigned char& operator[](const size_t index) const { return m_data[index]; } /** - * @brief Returns the symbol at the specified index. - * @param index the index of the symbol to return. - * @return the symbol at the specified index. + * @brief Returns whether this instance is equal to the other instance. + * @param other the other instance. + * @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols). */ - unsigned char operator[](const size_t index) const { return m_data[index]; } + bool operator==(SymbolString other) { return (m_unescapeState==0)==(m_unescapeState==0) && m_data==other.m_data; } /** - * @brief Inserts a the symbol at the specified index. - * @param index the index at which to insert the symbol. - * @param value the symbol to insert. - */ - void insert(const size_t index, const unsigned char value) { m_data.insert(m_data.begin()+index, value); } - /** - * @brief Appends a the symbol to the end of the symbol string and escapes it if necessary. + * @brief Appends a the symbol to the end of the symbol string and escapes/unescapes it if necessary. * @param value the symbol to append. + * @param isEscaped whether the symbol is escaped. * @param updateCrc whether to update the calculated CRC in @a m_crc. + * @return RESULT_OK if another symbol was appended, + * RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was received, + * RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected. */ - void push_back_escape(const unsigned char value, bool updateCRC=true); - /** - * @brief Appends a the symbol to the end of the symbol string and unescapes it. - * @param value the symbol to append. - * @param previousEscape whether the previous value was the escape symbol (set to false for the initial call). - * @param updateCrc whether to update the calculated CRC in @a m_crc. - * @return if previousEscape is false on return: the unescaped symbol. otherwise: zero if the escape sequence was invalid, one if the escape sequence is not yet finished. - */ - unsigned char push_back_unescape(const unsigned char value, bool& previousEscape, bool updateCRC=true); + int push_back(const unsigned char value, const bool isEscaped, const bool updateCRC=true); /** * @brief Returns the number of symbols in this symbol string. * @return the number of available symbols. @@ -116,7 +106,7 @@ public: /** * @brief Clears the symbols. */ - void clear() { m_crc=0; m_data.clear(); } + void clear() { m_data.clear(); m_unescapeState = m_unescapeState==0 ? 0 : 1; m_crc = 0; } private: /** @@ -129,6 +119,12 @@ private: * @brief the string of bus symbols. */ std::vector m_data; + /** + * @brief 0 if the symbols in @a m_data are escaped, + * 1 if the symbols in @a m_data are unescaped and the last symbol passed to @a push_back was a normal symbol, + * 2 if the symbols in @a m_data are unescaped and the last symbol passed to @a push_back was the escape symbol. + */ + int m_unescapeState; /** * @brief the calculated CRC. */ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index b2befdc6..8d9c0746 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -5,6 +5,7 @@ AM_CXXFLAGS = -fpic \ noinst_PROGRAMS = test_port \ test_symbol \ + test_data \ test_bus \ test_commands \ test_configfile \ @@ -17,6 +18,9 @@ test_port_LDADD = $(top_srcdir)/src/libebus/libebus.a test_symbol_SOURCES = test_symbol.cpp test_symbol_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_data_SOURCES = test_data.cpp +test_data_LDADD = $(top_srcdir)/src/libebus/libebus.a + test_bus_SOURCES = test_bus.cpp test_bus_LDADD = $(top_srcdir)/src/libebus/libebus.a diff --git a/src/test/test_data.cpp b/src/test/test_data.cpp new file mode 100644 index 00000000..19310cc2 --- /dev/null +++ b/src/test/test_data.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) John Baier 2014 + * + * This file is part of libebus. + * + * libebus 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. + * + * libebus 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 libebus. If not, see http://www.gnu.org/licenses/. + */ + +#include "data.h" +#include +#include + +using namespace libebus; + +int main () +{ + std::string checks[][4] = { + //name;position(s);type;factor;unit;comment +// {"temp;1;d2b;;°C;Aussentemperatur","temp=18.004 °C [Aussentemperatur]","10fe070009019258042126100714cc", "00"}, +// {"zeit;1;ttm;2;Uhr;","zeit=22:40 Uhr","10feffff0188", "00"}, + {"x;1-10;hex","53 70 65 69 63 68 65 72 20 20", "10fe07000a53706569636865722020", "00"}, + {"x;1;bti","21:04:58","10fe070009580421", "00"}, + {"x;1;bda","26.10.2014","10fe07000926100714", "00"}, + {"x;1-3;bda","26.10.2014","10fe070003261014", "00"}, + {"x;1;hdy","Sun","10fe07000307", "00"}, + {"x;1;bdy","Sun","10fe07000306", "00"}, + {"x;1;d2b","18.004","10fe0700090112", "00"}, + {"x;1;d2c","288.062","10fe0700090112", "00"}, + {"x;1;ttm","22:40","10feffff0188", "00"}, + {"x;1;bcd","26","10feffff0126", "00"}, + {"x;1;bcd","-","10feffff01ff", "00"}, + {"x;1;uch","38","10feffff0126", "00"}, + {"x;1;sch","-90","10feffff01a6", "00"}, + {"x;1;d1b","-90","10feffff01a6", "00"}, + {"x;1;d1c","19.500","10feffff0127", "00"}, + {"x;1;uin","38","10feffff022600", "00"}, + {"x;1;sin","-90","10feffff02a6ff", "00"}, + {"x;1;ulg","38","10feffff0426000000", "00"}, + {"x;1;slg","-90","10feffff04a6ffffff", "00"}, + {"x;1;flt","-0.090","10feffff02a6ff", "00"}, + {"x;1-9;str","hallo Du!","10feffff0868616c6c6f20447521", "00"}, + {"x;1-9;str","hallo Du ","10feffff0868616c6c6f20447520", "00"}, + {"new;1;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00"}, + }; + for (size_t i = 0; i < sizeof(checks)/sizeof(checks[0]); i++) { + std::istringstream isstr(checks[i][0]); + std::string expectStr = checks[i][1]; + SymbolString mstr = SymbolString(checks[i][2], false); + SymbolString sstr = SymbolString(checks[i][3], false); + std::string item; + std::vector entries; + + while (std::getline(isstr, item, ';') != 0) + entries.push_back(item); + + std::vector::iterator it = entries.begin(); + DataField* field = DataField::create(mstr[1], false, it, entries.end()); + + if (field == NULL) { + std::cout << "create \"" << checks[i][0] << "\" invalid: null" << std::endl; + return 1; + } + std::cout << "create \"" << checks[i][0] << "\" successful" << std::endl; + + + std::string gotStr = field->read(mstr, sstr); + + if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) + std::cout << "read successful: " << gotStr << std::endl; + else + std::cout << "read invalid: got " << gotStr + << ", expected " << expectStr << std::endl; + + SymbolString writeMstr = SymbolString(mstr.getDataStr().substr(0, 10), false); + SymbolString writeSstr = SymbolString(sstr.getDataStr().substr(0, 2), false); + if (field->write(gotStr, writeMstr, writeSstr) == false) + std::cout << "write failed" << std::endl; + else { + if (mstr == writeMstr && sstr == writeSstr) + std::cout << "write successful" << std::endl; + else { + std::cout << "write invalid: "; + if (mstr == writeMstr) + std::cout << "master OK"; + else + std::cout << "master got " << writeMstr.getDataStr() << ", expected " << mstr.getDataStr(); + + if (sstr == writeSstr) + std::cout << ", slave OK"; + else + std::cout << ", slave got " << writeSstr.getDataStr() << ", expected " << sstr.getDataStr(); + std::cout << std::endl; + } + } + delete field; + } + return 0; + +} diff --git a/src/test/test_symbol.cpp b/src/test/test_symbol.cpp index 625e93cc..b68ef9df 100644 --- a/src/test/test_symbol.cpp +++ b/src/test/test_symbol.cpp @@ -25,15 +25,9 @@ using namespace libebus; int main () { - SymbolString sstr("10feb5050427a915aa"); + SymbolString sstr = SymbolString("10feb5050427a915aa"); - std::stringstream out; - for (size_t i = 0; i(sstr[i]); - } - - std::string gotStr = out.str(), expectStr = "10feb5050427a90015a90177"; + std::string gotStr = sstr.getDataStr(false), expectStr = "10feb5050427a90015a90177"; if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) std::cout << "ctor escaped successful." << std::endl; @@ -54,7 +48,7 @@ int main () << std::setfill('0') << static_cast(expectCrc) << std::endl; - gotStr = sstr.getDataStr(true), expectStr = "10feb5050427a915aa77"; + gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa77"; if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) std::cout << "unescape successful." << std::endl; @@ -63,7 +57,9 @@ int main () << ", expected " << expectStr << std::endl; sstr = SymbolString("10feb5050427a90015a90177", true); - gotStr = sstr.getDataStr(false); + + gotStr = sstr.getDataStr(); + if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) std::cout << "ctor unescaped successful." << std::endl; else From 727bf600da9291f47693ca10213501bdb931263c Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Tue, 4 Nov 2014 20:23:43 +0100 Subject: [PATCH 07/15] code style. --- src/libebus/symbol.cpp | 26 ++++++++++++-------------- src/libebus/symbol.h | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/libebus/symbol.cpp b/src/libebus/symbol.cpp index a1110157..05d09ab1 100644 --- a/src/libebus/symbol.cpp +++ b/src/libebus/symbol.cpp @@ -79,15 +79,13 @@ const std::string SymbolString::getDataStr(const bool unescape) for (size_t i = 0; i < m_data.size(); i++) { unsigned char value = m_data[i]; if (m_unescapeState == 0 && unescape == true && previousEscape == true) { - if (value == 0x00) { + if (value == 0x00) sstr << "a9"; // ESC - } - else if (value == 0x01) { + else if (value == 0x01) sstr << "aa"; // SYN - } - else { + else sstr << "XX"; // invalid escape sequence - } + previousEscape = false; } else if (m_unescapeState == 0 && unescape == true && value == ESC) { @@ -123,9 +121,9 @@ int SymbolString::push_back(const unsigned char value, const bool isEscaped, con } else { m_data.push_back(value); - if (updateCRC) { + if (updateCRC) addCRC(value); - } + } return RESULT_OK; } @@ -149,9 +147,9 @@ int SymbolString::push_back(const unsigned char value, const bool isEscaped, con return RESULT_OK; } else if (m_unescapeState != 1) { - if (updateCRC) { + if (updateCRC) addCRC(value); - } + if (value == 0x00) { m_data.push_back(ESC); m_unescapeState = 1; @@ -165,15 +163,15 @@ int SymbolString::push_back(const unsigned char value, const bool isEscaped, con return RESULT_ERR_ESC; // invalid escape sequence } else if (value == ESC) { - if (updateCRC) { + if (updateCRC) addCRC(value); - } + m_unescapeState = 2; return RESULT_IN_ESC; } - if (updateCRC) { + if (updateCRC) addCRC(value); - } + m_data.push_back(value); return RESULT_OK; } diff --git a/src/libebus/symbol.h b/src/libebus/symbol.h index 833e1c1e..c54a1fc8 100644 --- a/src/libebus/symbol.h +++ b/src/libebus/symbol.h @@ -82,7 +82,7 @@ public: * @param other the other instance. * @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols). */ - bool operator==(SymbolString other) { return (m_unescapeState==0)==(m_unescapeState==0) && m_data==other.m_data; } + bool operator==(SymbolString other) { return (m_unescapeState==0)==(other.m_unescapeState==0) && m_data==other.m_data; } /** * @brief Appends a the symbol to the end of the symbol string and escapes/unescapes it if necessary. * @param value the symbol to append. From 793c64d9226b79596377fb4345a28f5625858440 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Thu, 6 Nov 2014 16:08:11 +0100 Subject: [PATCH 08/15] file struturce changed. --- .gitignore | 22 ++++++++++----------- Makefile.am | 2 +- configure.ac | 8 ++++---- src/ebusctl/Makefile.am | 17 ++++++++++++++++ src/{tools => ebusctl}/ebusctl.cpp | 0 src/ebusd/Makefile.am | 8 ++++---- src/{libebus => lib/ebus}/Makefile.am | 0 src/{libebus => lib/ebus}/bus.cpp | 0 src/{libebus => lib/ebus}/bus.h | 0 src/{libebus => lib/ebus}/buscommand.cpp | 0 src/{libebus => lib/ebus}/buscommand.h | 0 src/{libebus => lib/ebus}/command.cpp | 0 src/{libebus => lib/ebus}/command.h | 0 src/{libebus => lib/ebus}/commands.cpp | 0 src/{libebus => lib/ebus}/commands.h | 0 src/{libebus => lib/ebus}/configfile.cpp | 0 src/{libebus => lib/ebus}/configfile.h | 0 src/{libebus => lib/ebus}/data.cpp | 0 src/{libebus => lib/ebus}/data.h | 0 src/{libebus => lib/ebus}/decode.cpp | 0 src/{libebus => lib/ebus}/decode.h | 0 src/{libebus => lib/ebus}/dump.cpp | 0 src/{libebus => lib/ebus}/dump.h | 0 src/{libebus => lib/ebus}/encode.cpp | 0 src/{libebus => lib/ebus}/encode.h | 0 src/{libebus => lib/ebus}/port.cpp | 0 src/{libebus => lib/ebus}/port.h | 0 src/{libebus => lib/ebus}/result.cpp | 0 src/{libebus => lib/ebus}/result.h | 0 src/{libebus => lib/ebus}/symbol.cpp | 0 src/{libebus => lib/ebus}/symbol.h | 0 src/{ => lib/ebus}/test/Makefile.am | 18 ++++++++--------- src/{ => lib/ebus}/test/command.csv | 0 src/{ => lib/ebus}/test/test_bus.cpp | 0 src/{ => lib/ebus}/test/test_commands.cpp | 0 src/{ => lib/ebus}/test/test_configfile.cpp | 0 src/{ => lib/ebus}/test/test_data.cpp | 0 src/{ => lib/ebus}/test/test_decode.cpp | 0 src/{ => lib/ebus}/test/test_encode.cpp | 0 src/{ => lib/ebus}/test/test_port.cpp | 0 src/{ => lib/ebus}/test/test_symbol.cpp | 0 src/lib/utils/Makefile.am | 21 ++++++++++++++++++++ src/{libcore => lib/utils}/appl.cpp | 0 src/{libcore => lib/utils}/appl.h | 0 src/{libcore => lib/utils}/daemon.cpp | 0 src/{libcore => lib/utils}/daemon.h | 0 src/{libcore => lib/utils}/logger.cpp | 0 src/{libcore => lib/utils}/logger.h | 0 src/{libcore => lib/utils}/notify.h | 0 src/{libcore => lib/utils}/tcpsocket.cpp | 0 src/{libcore => lib/utils}/tcpsocket.h | 0 src/{libcore => lib/utils}/thread.cpp | 0 src/{libcore => lib/utils}/thread.h | 0 src/{libcore => lib/utils}/wqueue.h | 0 src/libcore/Makefile.am | 21 -------------------- src/tools/Makefile.am | 17 ---------------- 56 files changed, 67 insertions(+), 67 deletions(-) create mode 100644 src/ebusctl/Makefile.am rename src/{tools => ebusctl}/ebusctl.cpp (100%) rename src/{libebus => lib/ebus}/Makefile.am (100%) rename src/{libebus => lib/ebus}/bus.cpp (100%) rename src/{libebus => lib/ebus}/bus.h (100%) rename src/{libebus => lib/ebus}/buscommand.cpp (100%) rename src/{libebus => lib/ebus}/buscommand.h (100%) rename src/{libebus => lib/ebus}/command.cpp (100%) rename src/{libebus => lib/ebus}/command.h (100%) rename src/{libebus => lib/ebus}/commands.cpp (100%) rename src/{libebus => lib/ebus}/commands.h (100%) rename src/{libebus => lib/ebus}/configfile.cpp (100%) rename src/{libebus => lib/ebus}/configfile.h (100%) rename src/{libebus => lib/ebus}/data.cpp (100%) rename src/{libebus => lib/ebus}/data.h (100%) rename src/{libebus => lib/ebus}/decode.cpp (100%) rename src/{libebus => lib/ebus}/decode.h (100%) rename src/{libebus => lib/ebus}/dump.cpp (100%) rename src/{libebus => lib/ebus}/dump.h (100%) rename src/{libebus => lib/ebus}/encode.cpp (100%) rename src/{libebus => lib/ebus}/encode.h (100%) rename src/{libebus => lib/ebus}/port.cpp (100%) rename src/{libebus => lib/ebus}/port.h (100%) rename src/{libebus => lib/ebus}/result.cpp (100%) rename src/{libebus => lib/ebus}/result.h (100%) rename src/{libebus => lib/ebus}/symbol.cpp (100%) rename src/{libebus => lib/ebus}/symbol.h (100%) rename src/{ => lib/ebus}/test/Makefile.am (53%) rename src/{ => lib/ebus}/test/command.csv (100%) rename src/{ => lib/ebus}/test/test_bus.cpp (100%) rename src/{ => lib/ebus}/test/test_commands.cpp (100%) rename src/{ => lib/ebus}/test/test_configfile.cpp (100%) rename src/{ => lib/ebus}/test/test_data.cpp (100%) rename src/{ => lib/ebus}/test/test_decode.cpp (100%) rename src/{ => lib/ebus}/test/test_encode.cpp (100%) rename src/{ => lib/ebus}/test/test_port.cpp (100%) rename src/{ => lib/ebus}/test/test_symbol.cpp (100%) create mode 100644 src/lib/utils/Makefile.am rename src/{libcore => lib/utils}/appl.cpp (100%) rename src/{libcore => lib/utils}/appl.h (100%) rename src/{libcore => lib/utils}/daemon.cpp (100%) rename src/{libcore => lib/utils}/daemon.h (100%) rename src/{libcore => lib/utils}/logger.cpp (100%) rename src/{libcore => lib/utils}/logger.h (100%) rename src/{libcore => lib/utils}/notify.h (100%) rename src/{libcore => lib/utils}/tcpsocket.cpp (100%) rename src/{libcore => lib/utils}/tcpsocket.h (100%) rename src/{libcore => lib/utils}/thread.cpp (100%) rename src/{libcore => lib/utils}/thread.h (100%) rename src/{libcore => lib/utils}/wqueue.h (100%) delete mode 100644 src/libcore/Makefile.am delete mode 100644 src/tools/Makefile.am diff --git a/.gitignore b/.gitignore index ef3fe657..69207eca 100644 --- a/.gitignore +++ b/.gitignore @@ -11,15 +11,15 @@ Makefile.in .deps/ *.o *.dirstamp -/src/libcore/libcore.a -/src/libebus/libebus.a /src/ebusd/ebusd -/src/tools/ebusctl -/src/test/test_bus -/src/test/test_port -/src/test/test_configfile -/src/test/test_commands -/src/test/test_decode -/src/test/test_encode -/src/test/test_symbol -/src/test/test_data +/src/ebusctl/ebusctl +/src/lib/utils/libutils.a +/src/lib/ebus/libebus.a +/src/lib/ebus/test/test_bus +/src/lib/ebus/test/test_port +/src/lib/ebus/test/test_configfile +/src/lib/ebus/test/test_commands +/src/lib/ebus/test/test_decode +/src/lib/ebus/test/test_encode +/src/lib/ebus/test/test_symbol +/src/lib/ebus/test/test_data diff --git a/Makefile.am b/Makefile.am index 7146e27c..2bf1f2d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src/libebus src/test src/libcore src/ebusd src/tools +SUBDIRS = src/lib/ebus src/lib/ebus/test src/lib/utils src/ebusd src/ebusctl distclean-local: -rm -rf autom4te.cache diff --git a/configure.ac b/configure.ac index 91356aaa..37d4ab21 100644 --- a/configure.ac +++ b/configure.ac @@ -7,11 +7,11 @@ AC_CONFIG_AUX_DIR([build]) AC_CONFIG_SRCDIR([src/ebusd/main.cpp]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile - src/libebus/Makefile - src/test/Makefile - src/libcore/Makefile + src/lib/ebus/Makefile + src/lib/ebus/test/Makefile + src/lib/utils/Makefile src/ebusd/Makefile - src/tools/Makefile]) + src/ebusctl/Makefile]) AM_INIT_AUTOMAKE([1.11 -Wall -Werror foreign]) diff --git a/src/ebusctl/Makefile.am b/src/ebusctl/Makefile.am new file mode 100644 index 00000000..5b5088ce --- /dev/null +++ b/src/ebusctl/Makefile.am @@ -0,0 +1,17 @@ +AM_CXXFLAGS = -fpic \ + -Wall \ + -Wextra \ + -I$(top_srcdir)/src/lib/utils \ + -I$(top_srcdir)/src/lib/ebus + +bin_PROGRAMS = ebusctl + +ebusctl_SOURCES = ebusctl.cpp + +ebusctl_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ + $(top_srcdir)/src/lib/ebus/libebus.a + +distclean-local: + -rm -f Makefile.in + -rm -rf .libs + diff --git a/src/tools/ebusctl.cpp b/src/ebusctl/ebusctl.cpp similarity index 100% rename from src/tools/ebusctl.cpp rename to src/ebusctl/ebusctl.cpp diff --git a/src/ebusd/Makefile.am b/src/ebusd/Makefile.am index a0990baf..742edf10 100644 --- a/src/ebusd/Makefile.am +++ b/src/ebusd/Makefile.am @@ -1,8 +1,8 @@ AM_CXXFLAGS = -fpic \ -Wall \ -Wextra \ - -I$(top_srcdir)/src/libcore \ - -I$(top_srcdir)/src/libebus + -I$(top_srcdir)/src/lib/utils \ + -I$(top_srcdir)/src/lib/ebus bin_PROGRAMS = ebusd @@ -17,8 +17,8 @@ ebusd_SOURCES = message.h \ baseloop.h \ main.cpp -ebusd_LDADD = $(top_srcdir)/src/libcore/libcore.a \ - $(top_srcdir)/src/libebus/libebus.a \ +ebusd_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ + $(top_srcdir)/src/lib/ebus/libebus.a \ -lpthread distclean-local: diff --git a/src/libebus/Makefile.am b/src/lib/ebus/Makefile.am similarity index 100% rename from src/libebus/Makefile.am rename to src/lib/ebus/Makefile.am diff --git a/src/libebus/bus.cpp b/src/lib/ebus/bus.cpp similarity index 100% rename from src/libebus/bus.cpp rename to src/lib/ebus/bus.cpp diff --git a/src/libebus/bus.h b/src/lib/ebus/bus.h similarity index 100% rename from src/libebus/bus.h rename to src/lib/ebus/bus.h diff --git a/src/libebus/buscommand.cpp b/src/lib/ebus/buscommand.cpp similarity index 100% rename from src/libebus/buscommand.cpp rename to src/lib/ebus/buscommand.cpp diff --git a/src/libebus/buscommand.h b/src/lib/ebus/buscommand.h similarity index 100% rename from src/libebus/buscommand.h rename to src/lib/ebus/buscommand.h diff --git a/src/libebus/command.cpp b/src/lib/ebus/command.cpp similarity index 100% rename from src/libebus/command.cpp rename to src/lib/ebus/command.cpp diff --git a/src/libebus/command.h b/src/lib/ebus/command.h similarity index 100% rename from src/libebus/command.h rename to src/lib/ebus/command.h diff --git a/src/libebus/commands.cpp b/src/lib/ebus/commands.cpp similarity index 100% rename from src/libebus/commands.cpp rename to src/lib/ebus/commands.cpp diff --git a/src/libebus/commands.h b/src/lib/ebus/commands.h similarity index 100% rename from src/libebus/commands.h rename to src/lib/ebus/commands.h diff --git a/src/libebus/configfile.cpp b/src/lib/ebus/configfile.cpp similarity index 100% rename from src/libebus/configfile.cpp rename to src/lib/ebus/configfile.cpp diff --git a/src/libebus/configfile.h b/src/lib/ebus/configfile.h similarity index 100% rename from src/libebus/configfile.h rename to src/lib/ebus/configfile.h diff --git a/src/libebus/data.cpp b/src/lib/ebus/data.cpp similarity index 100% rename from src/libebus/data.cpp rename to src/lib/ebus/data.cpp diff --git a/src/libebus/data.h b/src/lib/ebus/data.h similarity index 100% rename from src/libebus/data.h rename to src/lib/ebus/data.h diff --git a/src/libebus/decode.cpp b/src/lib/ebus/decode.cpp similarity index 100% rename from src/libebus/decode.cpp rename to src/lib/ebus/decode.cpp diff --git a/src/libebus/decode.h b/src/lib/ebus/decode.h similarity index 100% rename from src/libebus/decode.h rename to src/lib/ebus/decode.h diff --git a/src/libebus/dump.cpp b/src/lib/ebus/dump.cpp similarity index 100% rename from src/libebus/dump.cpp rename to src/lib/ebus/dump.cpp diff --git a/src/libebus/dump.h b/src/lib/ebus/dump.h similarity index 100% rename from src/libebus/dump.h rename to src/lib/ebus/dump.h diff --git a/src/libebus/encode.cpp b/src/lib/ebus/encode.cpp similarity index 100% rename from src/libebus/encode.cpp rename to src/lib/ebus/encode.cpp diff --git a/src/libebus/encode.h b/src/lib/ebus/encode.h similarity index 100% rename from src/libebus/encode.h rename to src/lib/ebus/encode.h diff --git a/src/libebus/port.cpp b/src/lib/ebus/port.cpp similarity index 100% rename from src/libebus/port.cpp rename to src/lib/ebus/port.cpp diff --git a/src/libebus/port.h b/src/lib/ebus/port.h similarity index 100% rename from src/libebus/port.h rename to src/lib/ebus/port.h diff --git a/src/libebus/result.cpp b/src/lib/ebus/result.cpp similarity index 100% rename from src/libebus/result.cpp rename to src/lib/ebus/result.cpp diff --git a/src/libebus/result.h b/src/lib/ebus/result.h similarity index 100% rename from src/libebus/result.h rename to src/lib/ebus/result.h diff --git a/src/libebus/symbol.cpp b/src/lib/ebus/symbol.cpp similarity index 100% rename from src/libebus/symbol.cpp rename to src/lib/ebus/symbol.cpp diff --git a/src/libebus/symbol.h b/src/lib/ebus/symbol.h similarity index 100% rename from src/libebus/symbol.h rename to src/lib/ebus/symbol.h diff --git a/src/test/Makefile.am b/src/lib/ebus/test/Makefile.am similarity index 53% rename from src/test/Makefile.am rename to src/lib/ebus/test/Makefile.am index 8d9c0746..8236c57c 100644 --- a/src/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -1,7 +1,7 @@ AM_CXXFLAGS = -fpic \ -Wall \ -Wextra \ - -I$(top_srcdir)/src/libebus + -I$(top_srcdir)/src/lib/ebus noinst_PROGRAMS = test_port \ test_symbol \ @@ -13,28 +13,28 @@ noinst_PROGRAMS = test_port \ test_encode test_port_SOURCES = test_port.cpp -test_port_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_symbol_SOURCES = test_symbol.cpp -test_symbol_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_symbol_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_data_SOURCES = test_data.cpp -test_data_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_data_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_bus_SOURCES = test_bus.cpp -test_bus_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_bus_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_commands_SOURCES = test_commands.cpp -test_commands_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_commands_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_configfile_SOURCES = test_configfile.cpp -test_configfile_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_configfile_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_decode_SOURCES = test_decode.cpp -test_decode_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_decode_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_encode_SOURCES = test_encode.cpp -test_encode_LDADD = $(top_srcdir)/src/libebus/libebus.a +test_encode_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a distclean-local: -rm -f Makefile.in diff --git a/src/test/command.csv b/src/lib/ebus/test/command.csv similarity index 100% rename from src/test/command.csv rename to src/lib/ebus/test/command.csv diff --git a/src/test/test_bus.cpp b/src/lib/ebus/test/test_bus.cpp similarity index 100% rename from src/test/test_bus.cpp rename to src/lib/ebus/test/test_bus.cpp diff --git a/src/test/test_commands.cpp b/src/lib/ebus/test/test_commands.cpp similarity index 100% rename from src/test/test_commands.cpp rename to src/lib/ebus/test/test_commands.cpp diff --git a/src/test/test_configfile.cpp b/src/lib/ebus/test/test_configfile.cpp similarity index 100% rename from src/test/test_configfile.cpp rename to src/lib/ebus/test/test_configfile.cpp diff --git a/src/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp similarity index 100% rename from src/test/test_data.cpp rename to src/lib/ebus/test/test_data.cpp diff --git a/src/test/test_decode.cpp b/src/lib/ebus/test/test_decode.cpp similarity index 100% rename from src/test/test_decode.cpp rename to src/lib/ebus/test/test_decode.cpp diff --git a/src/test/test_encode.cpp b/src/lib/ebus/test/test_encode.cpp similarity index 100% rename from src/test/test_encode.cpp rename to src/lib/ebus/test/test_encode.cpp diff --git a/src/test/test_port.cpp b/src/lib/ebus/test/test_port.cpp similarity index 100% rename from src/test/test_port.cpp rename to src/lib/ebus/test/test_port.cpp diff --git a/src/test/test_symbol.cpp b/src/lib/ebus/test/test_symbol.cpp similarity index 100% rename from src/test/test_symbol.cpp rename to src/lib/ebus/test/test_symbol.cpp diff --git a/src/lib/utils/Makefile.am b/src/lib/utils/Makefile.am new file mode 100644 index 00000000..d10f81d6 --- /dev/null +++ b/src/lib/utils/Makefile.am @@ -0,0 +1,21 @@ +AM_CXXFLAGS = -fpic \ + -Wall \ + -Wextra + +noinst_LIBRARIES = libutils.a + +libutils_a_SOURCES = wqueue.h \ + notify.h \ + appl.cpp \ + appl.h \ + daemon.cpp \ + daemon.h \ + logger.cpp \ + logger.h \ + thread.cpp \ + thread.h \ + tcpsocket.cpp \ + tcpsocket.h + +distclean-local: + -rm -f Makefile.in diff --git a/src/libcore/appl.cpp b/src/lib/utils/appl.cpp similarity index 100% rename from src/libcore/appl.cpp rename to src/lib/utils/appl.cpp diff --git a/src/libcore/appl.h b/src/lib/utils/appl.h similarity index 100% rename from src/libcore/appl.h rename to src/lib/utils/appl.h diff --git a/src/libcore/daemon.cpp b/src/lib/utils/daemon.cpp similarity index 100% rename from src/libcore/daemon.cpp rename to src/lib/utils/daemon.cpp diff --git a/src/libcore/daemon.h b/src/lib/utils/daemon.h similarity index 100% rename from src/libcore/daemon.h rename to src/lib/utils/daemon.h diff --git a/src/libcore/logger.cpp b/src/lib/utils/logger.cpp similarity index 100% rename from src/libcore/logger.cpp rename to src/lib/utils/logger.cpp diff --git a/src/libcore/logger.h b/src/lib/utils/logger.h similarity index 100% rename from src/libcore/logger.h rename to src/lib/utils/logger.h diff --git a/src/libcore/notify.h b/src/lib/utils/notify.h similarity index 100% rename from src/libcore/notify.h rename to src/lib/utils/notify.h diff --git a/src/libcore/tcpsocket.cpp b/src/lib/utils/tcpsocket.cpp similarity index 100% rename from src/libcore/tcpsocket.cpp rename to src/lib/utils/tcpsocket.cpp diff --git a/src/libcore/tcpsocket.h b/src/lib/utils/tcpsocket.h similarity index 100% rename from src/libcore/tcpsocket.h rename to src/lib/utils/tcpsocket.h diff --git a/src/libcore/thread.cpp b/src/lib/utils/thread.cpp similarity index 100% rename from src/libcore/thread.cpp rename to src/lib/utils/thread.cpp diff --git a/src/libcore/thread.h b/src/lib/utils/thread.h similarity index 100% rename from src/libcore/thread.h rename to src/lib/utils/thread.h diff --git a/src/libcore/wqueue.h b/src/lib/utils/wqueue.h similarity index 100% rename from src/libcore/wqueue.h rename to src/lib/utils/wqueue.h diff --git a/src/libcore/Makefile.am b/src/libcore/Makefile.am deleted file mode 100644 index d1b3b997..00000000 --- a/src/libcore/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -AM_CXXFLAGS = -fpic \ - -Wall \ - -Wextra - -noinst_LIBRARIES = libcore.a - -libcore_a_SOURCES = wqueue.h \ - notify.h \ - appl.cpp \ - appl.h \ - daemon.cpp \ - daemon.h \ - logger.cpp \ - logger.h \ - thread.cpp \ - thread.h \ - tcpsocket.cpp \ - tcpsocket.h - -distclean-local: - -rm -f Makefile.in diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am deleted file mode 100644 index c9b83ddf..00000000 --- a/src/tools/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -AM_CXXFLAGS = -fpic \ - -Wall \ - -Wextra \ - -I$(top_srcdir)/src/libcore \ - -I$(top_srcdir)/src/libebus - -bin_PROGRAMS = ebusctl - -ebusctl_SOURCES = ebusctl.cpp - -ebusctl_LDADD = $(top_srcdir)/src/libcore/libcore.a \ - $(top_srcdir)/src/libebus/libebus.a - -distclean-local: - -rm -f Makefile.in - -rm -rf .libs - From 6db67385b5cc70e0c9f07fdec5da0ea8b6b9db83 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Thu, 6 Nov 2014 21:57:15 +0100 Subject: [PATCH 09/15] integration from bus into ebusloop started; logautosyn renamed to lograwdata --- src/ebusd/ebusloop.cpp | 179 ++++++++++++++++++++++++++++++++++++----- src/ebusd/ebusloop.h | 34 ++++++-- src/ebusd/main.cpp | 4 +- 3 files changed, 188 insertions(+), 29 deletions(-) diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index 6832d7b7..ef3a1098 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -26,39 +26,179 @@ extern Appl& A; EBusLoop::EBusLoop(Commands* commands) : m_commands(commands), m_stop(false) { - m_deviceName = A.getParam("p_device"); + m_port = new Port(A.getParam("p_device"), A.getParam("p_nodevicecheck")); - m_bus = new Bus(m_deviceName, - A.getParam("p_nodevicecheck"), - A.getParam("p_recvtimeout"), - A.getParam("p_dumpfile"), - A.getParam("p_dumpsize"), - A.getParam("p_dump")); + m_port->open(); - m_retries = A.getParam("p_retries"); + if (m_port->isOpen() == false) + L.log(bus, error, "can't open %s", A.getParam("p_device")); - m_lookbusretries = A.getParam("p_lookbusretries"); - m_pollInterval = A.getParam("p_pollinterval"); + m_dump = new Dump(A.getParam("p_dumpfile"), A.getParam("p_dumpsize")); - m_logAutoSyn = A.getParam("p_logautosyn"); + m_dumpState = A.getParam("p_dump"); - m_bus->connect(); + m_logRawData = A.getParam("p_lograwdata"); - if (m_bus->isConnected() == false) - L.log(bus, error, "can't open %s", m_deviceName.c_str()); + //~ m_deviceName = A.getParam("p_device"); + + //~ m_bus = new Bus(m_deviceName, + //~ A.getParam("p_nodevicecheck"), + //~ A.getParam("p_recvtimeout"), + //~ A.getParam("p_dumpfile"), + //~ A.getParam("p_dumpsize"), + //~ A.getParam("p_dump")); + + //~ m_retries = A.getParam("p_retries"); +//~ + //~ m_lookbusretries = A.getParam("p_lookbusretries"); +//~ + //~ m_pollInterval = A.getParam("p_pollinterval"); +//~ + + + //~ m_bus->connect(); + + //~ if (m_bus->isConnected() == false) + //~ L.log(bus, error, "can't open %s", m_deviceName.c_str()); } EBusLoop::~EBusLoop() { - m_bus->disconnect(); + if (m_port->isOpen() == true) + m_port->close(); - if (m_bus->isConnected() == true) - L.log(bus, error, "error during disconnect."); - - delete m_bus; + delete m_port; + delete m_dump; + //~ m_bus->disconnect(); +//~ + //~ if (m_bus->isConnected() == true) + //~ L.log(bus, error, "error during disconnect."); +//~ + //~ delete m_bus; } +void* EBusLoop::run() +{ + bool busLock = false; + + for (;;) { + if (m_port->isOpen() == true) { + unsigned char byte; + ssize_t numBytes; + + // read device - no timeout needed (AUTO-SYN) + numBytes = m_port->recv(0); + + if (numBytes < 0) { + L.log(bus, error, " ERR_DEVICE: generic device error"); + continue; + } + + for (int i = 0; i < numBytes; i++) { + + // fetch byte + byte = recvByte(); + + // collect cycle data + if (byte != SYN) + m_sstr.push_back(byte, true, false); + + // unlock bus + if (byte == SYN && busLock == true) { + busLock = false; + L.log(bus, trace, " bus unlocked"); + } + + // analyse cycle data + if (byte == SYN && m_sstr.size() > 0) { + + analyseCycData(m_sstr); + + if (m_sstr.size() == 1) { + busLock = true; + L.log(bus, trace, " bus locked"); + } + + m_sstr.clear(); + } + } + + // send command + if (m_sstr.size() == 0 && busLock == false + && m_sendBuffer.size() > 0) { + // TODO: sendCommand.... + } + + // poll command - timer reached + if (m_sstr.size() == 0 && busLock == false + && m_sendBuffer.size() > 0) { + // TODO: pollCommand.... + } + } + else { + // TODO: define max reopen + sleep(10); + m_port->open(); + + if (m_port->isOpen() == false) + L.log(bus, error, "can't open %s", A.getParam("p_device")); + + } + + if (m_stop == true) { + if (m_port->isOpen() == true) + m_port->close(); + + return NULL; + } + + } + + return NULL; +} + +unsigned char EBusLoop::recvByte() +{ + unsigned char byte; + + // fetch byte + byte = m_port->byte(); + + if (m_dumpState == true) + m_dump->write((const char*) &byte); + + if (m_logRawData == true) + L.log(bus, event, "%02x", byte); + + return byte; +} + +void EBusLoop::analyseCycData(SymbolString data) const +{ + L.log(bus, trace, "%s", data.getDataStr().c_str()); + + int index = m_commands->storeCycData(data.getDataStr()); + + if (index == -1) { + L.log(bus, debug, " command not found"); + } + else if (index == -2) { + L.log(bus, debug, " no commands defined"); + } + else if (index == -3) { + L.log(bus, debug, " search skipped - string too short"); + } + else { + std::string tmp; + tmp += (*m_commands)[index][1]; + tmp += " "; + tmp += (*m_commands)[index][2]; + L.log(bus, event, " cycle [%d] %s", index, tmp.c_str()); + } +} + +/* void* EBusLoop::run() { int busResult; @@ -228,3 +368,4 @@ void* EBusLoop::run() return NULL; } +*/ diff --git a/src/ebusd/ebusloop.h b/src/ebusd/ebusloop.h index 09c69992..245d01f6 100644 --- a/src/ebusd/ebusloop.h +++ b/src/ebusd/ebusloop.h @@ -20,8 +20,11 @@ #ifndef EBUSLOOP_H_ #define EBUSLOOP_H_ -#include "bus.h" +//~ #include "bus.h" #include "commands.h" +#include "port.h" +#include "dump.h" +#include "buscommand.h" #include "wqueue.h" #include "thread.h" @@ -40,20 +43,35 @@ public: void addBusCommand(BusCommand* busCommand) { m_sendBuffer.add(busCommand); } - void dump(const bool dumpState) { m_bus->setDumpState(dumpState); } + //~ void dump(const bool dumpState) { m_bus->setDumpState(dumpState); } + void dump(const bool dumpState) { m_dumpState = dumpState; } void newCommands(Commands* commands) { m_commands = commands; } private: Commands* m_commands; - std::string m_deviceName; - Bus* m_bus; + Port* m_port; + + Dump* m_dump; + bool m_dumpState; + + bool m_logRawData; + bool m_stop; + + SymbolString m_sstr; + + //~ std::string m_deviceName; + //~ bool m_noDeviceCheck; + //~ Bus* m_bus; + WQueue m_sendBuffer; - int m_retries; - int m_lookbusretries; - double m_pollInterval; - bool m_logAutoSyn; + //~ int m_retries; + //~ int m_lookbusretries; + //~ double m_pollInterval; + + unsigned char recvByte(); + void analyseCycData(SymbolString data) const; }; diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 015eee56..cd456d02 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -91,8 +91,8 @@ void define_args() "\tlog level - error|event|trace|debug (event)", Appl::type_string, Appl::opt_mandatory); - A.addItem("p_logautosyn", Appl::Param(false), "", "logautosyn", - "log AUTO-SYN bytes\n", + A.addItem("p_lograwdata", Appl::Param(false), "", "lograwdata", + "log raw data (bytes)\n", Appl::type_bool, Appl::opt_none); A.addItem("p_dump", Appl::Param(false), "D", "dump", From 6b0f58b2917b604f3e75f85c895b195b9e351f65 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 7 Nov 2014 20:30:38 +0100 Subject: [PATCH 10/15] integration from bus into ebusloop continued. --- src/ebusd/ebusloop.cpp | 614 +++++++++++++++++++++++------------- src/ebusd/ebusloop.h | 32 +- src/ebusd/main.cpp | 8 +- src/lib/ebus/buscommand.cpp | 4 +- src/lib/ebus/port.h | 5 +- src/lib/utils/wqueue.h | 14 + 6 files changed, 435 insertions(+), 242 deletions(-) diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index ef3a1098..e429086d 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -24,43 +24,27 @@ extern LogInstance& L; extern Appl& A; -EBusLoop::EBusLoop(Commands* commands) : m_commands(commands), m_stop(false) +EBusLoop::EBusLoop(Commands* commands) + : m_commands(commands), m_stop(false), m_busLocked(false), m_priorRetry(false) { m_port = new Port(A.getParam("p_device"), A.getParam("p_nodevicecheck")); - m_port->open(); if (m_port->isOpen() == false) L.log(bus, error, "can't open %s", A.getParam("p_device")); - m_dump = new Dump(A.getParam("p_dumpfile"), A.getParam("p_dumpsize")); - m_dumpState = A.getParam("p_dump"); m_logRawData = A.getParam("p_lograwdata"); - //~ m_deviceName = A.getParam("p_device"); + m_pollInterval = A.getParam("p_pollinterval"); - //~ m_bus = new Bus(m_deviceName, - //~ A.getParam("p_nodevicecheck"), - //~ A.getParam("p_recvtimeout"), - //~ A.getParam("p_dumpfile"), - //~ A.getParam("p_dumpsize"), - //~ A.getParam("p_dump")); + m_recvTimeout = A.getParam("p_recvtimeout"); - //~ m_retries = A.getParam("p_retries"); -//~ - //~ m_lookbusretries = A.getParam("p_lookbusretries"); -//~ - //~ m_pollInterval = A.getParam("p_pollinterval"); -//~ + m_sendRetries = A.getParam("p_sendretries"); - - //~ m_bus->connect(); - - //~ if (m_bus->isConnected() == false) - //~ L.log(bus, error, "can't open %s", m_deviceName.c_str()); + m_lockRetries = A.getParam("p_lockretries"); } EBusLoop::~EBusLoop() @@ -70,23 +54,35 @@ EBusLoop::~EBusLoop() delete m_port; delete m_dump; - //~ m_bus->disconnect(); -//~ - //~ if (m_bus->isConnected() == true) - //~ L.log(bus, error, "error during disconnect."); -//~ - //~ delete m_bus; } void* EBusLoop::run() { - bool busLock = false; + int sendRetries = 0; + int lockRetries = 0; + + // polling + time_t pollStart, pollEnd; + time(&pollStart); + double pollDelta; for (;;) { if (m_port->isOpen() == true) { - unsigned char byte; ssize_t numBytes; + // add poll command - timer reached + if (m_commands->sizePolDB() > 0) { + // check polling delta + time(&pollEnd); + pollDelta = difftime(pollEnd, pollStart); + + // add new polling command to send + if (pollDelta >= m_pollInterval) { + addPollCommand(); + time(&pollStart); + } + } + // read device - no timeout needed (AUTO-SYN) numBytes = m_port->recv(0); @@ -95,46 +91,63 @@ void* EBusLoop::run() continue; } - for (int i = 0; i < numBytes; i++) { - - // fetch byte - byte = recvByte(); - - // collect cycle data - if (byte != SYN) - m_sstr.push_back(byte, true, false); - - // unlock bus - if (byte == SYN && busLock == true) { - busLock = false; - L.log(bus, trace, " bus unlocked"); - } - - // analyse cycle data - if (byte == SYN && m_sstr.size() > 0) { - - analyseCycData(m_sstr); - - if (m_sstr.size() == 1) { - busLock = true; - L.log(bus, trace, " bus locked"); - } - - m_sstr.clear(); - } - } + // cycle bytes + collectCycData(numBytes); // send command - if (m_sstr.size() == 0 && busLock == false - && m_sendBuffer.size() > 0) { - // TODO: sendCommand.... + if (m_sstr.size() == 0 && m_busLocked == false && m_sendBuffer.size() > 0) { + // acquire Bus + int busResult = acquireBus(); + + // send bus command + if (busResult == RESULT_BUS_ACQUIRED) { + BusCommand* busCommand = sendCommand(); + L.log(bus, trace, " %s", busCommand->getMessageStr().c_str()); + + if (busCommand->isErrorResult() == true) { + if (sendRetries < m_sendRetries) { + sendRetries++; + L.log(bus, trace, " send retry %d", sendRetries); + busCommand->setResult(std::string(), RESULT_OK); + } + else { + sendRetries = 0; + if (busCommand->isPoll() == true) + delete m_sendBuffer.remove(); + else + busCommand->sendSignal(); + } + } + else { + sendRetries = 0; + if (busCommand->isPoll() == true) { + m_commands->storePolData(busCommand->getMessageStr().c_str()); // TODO use getResult() + delete busCommand; + } + else + busCommand->sendSignal(); + } + + } + else { + L.log(bus, trace, " acquire bus failed"); + if (lockRetries >= m_lockRetries) { + L.log(bus, event, " lock bus failed"); + BusCommand* busCommand = m_sendBuffer.remove(); + if (busCommand->isPoll() == true) + delete busCommand; + else + busCommand->sendSignal(); + + lockRetries = 0; + } + else + lockRetries++; + + } + } - // poll command - timer reached - if (m_sstr.size() == 0 && busLock == false - && m_sendBuffer.size() > 0) { - // TODO: pollCommand.... - } } else { // TODO: define max reopen @@ -158,7 +171,7 @@ void* EBusLoop::run() return NULL; } -unsigned char EBusLoop::recvByte() +unsigned char EBusLoop::fetchByte() { unsigned char byte; @@ -174,11 +187,48 @@ unsigned char EBusLoop::recvByte() return byte; } -void EBusLoop::analyseCycData(SymbolString data) const +void EBusLoop::collectCycData(const int numRecv) { - L.log(bus, trace, "%s", data.getDataStr().c_str()); + // cycle bytes + for (int i = 0; i < numRecv; i++) { - int index = m_commands->storeCycData(data.getDataStr()); + // fetch byte + unsigned char byte = fetchByte(); + + // collect cycle data + if (byte != SYN) + m_sstr.push_back(byte, true, false); + + // unlock bus + if (byte == SYN && m_busLocked == true) { + m_busLocked = false; + L.log(bus, trace, " bus unlocked"); + } + + // analyse cycle data + if (byte == SYN && m_sstr.size() > 0) { + + analyseCycData(); + + if (m_sstr.size() == 1) { + if (m_priorRetry == true) + m_priorRetry = false; + else { + m_busLocked = true; + L.log(bus, trace, " bus locked"); + } + } + + m_sstr.clear(); + } + } +} + +void EBusLoop::analyseCycData() +{ + L.log(bus, trace, "%s", m_sstr.getDataStr().c_str()); + + int index = m_commands->storeCycData(m_sstr.getDataStr()); if (index == -1) { L.log(bus, debug, " command not found"); @@ -198,174 +248,292 @@ void EBusLoop::analyseCycData(SymbolString data) const } } -/* -void* EBusLoop::run() +void EBusLoop::addPollCommand() { - int busResult; - int retries = 0; - int lookbusretries = 0; - bool busCommandActive = false; + int index = m_commands->nextPolCommand(); + if (index < 0) { + L.log(bus, error, "polling index out of range"); + } + else { + // TODO: implement as methode from class commands? + std::string tmp; + tmp += (*m_commands)[index][1]; + tmp += " "; + tmp += (*m_commands)[index][2]; + L.log(bus, event, " polling [%d] %s", index, tmp.c_str()); - // polling - time_t pollStart, pollEnd; - time(&pollStart); - double pollDelta = 0.0; + std::string ebusCommand(A.getParam("p_address")); + ebusCommand += m_commands->getEbusCommand(index); + std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); - for (;;) { - if (m_bus->isConnected() == true) { + BusCommand* busCommand = new BusCommand(ebusCommand, true); + L.log(bus, trace, " msg: %s", ebusCommand.c_str()); - // work on bus - busResult = m_bus->proceed(); + addBusCommand(busCommand); + } +} - // new cyc message arrived - if (busResult == RESULT_SYN || busResult == RESULT_BUS_LOCKED) { - SymbolString data = m_bus->getCycData(); +int EBusLoop::acquireBus() +{ + unsigned char recvByte, sendByte; + ssize_t numRecv, numSend; - if (data.size() == 0 && m_logAutoSyn == true) - L.log(bus, trace, "aa"); + sendByte = m_sendBuffer.next()->getCommand()[0]; - if (data.size() != 0) { - L.log(bus, trace, "%s", data.getDataStr().c_str()); + // send QQ + numSend = m_port->send(&sendByte); + if (numSend <= 0) { + L.log(bus, trace, " ERR_SEND: send error"); + return RESULT_ERR_SEND; + } - int index = m_commands->storeCycData(data.getDataStr()); + // receive 1 byte - must be QQ + numRecv = m_port->recv(0); - if (index == -1) { - L.log(bus, debug, " command not found"); + if (numRecv < 0) { + L.log(bus, trace, " ERR_DEVICE: generic device error"); + return RESULT_ERR_DEVICE; + } - } else if (index == -2) { - L.log(bus, debug, " no commands defined"); + if (numRecv == 1) { + // fetch byte + recvByte = fetchByte(); - } else if (index == -3) { - L.log(bus, debug, " search skipped - string too short"); - - } else { - std::string tmp; - tmp += (*m_commands)[index][1]; - tmp += " "; - tmp += (*m_commands)[index][2]; - L.log(bus, event, " cycle [%d] %s", index, tmp.c_str()); - } - } - - if (busResult == RESULT_BUS_LOCKED) - L.log(bus, trace, "bus locked"); - } - - // add new bus command to send - if (busResult == RESULT_SYN && busCommandActive == false && m_sendBuffer.size() != 0) { - BusCommand* busCommand = m_sendBuffer.remove(); - L.log(bus, debug, " msg: %s", busCommand->getCommand().getDataStr().c_str()); - m_bus->addCommand(busCommand); - L.log(bus, debug, " addCommand success"); - busCommandActive = true; - } - - // add new polling command - if (m_commands->sizePolDB() > 0) { - // check polling delta - time(&pollEnd); - pollDelta = difftime(pollEnd, pollStart); - - // add new polling command to send - if (busResult == RESULT_SYN && busCommandActive == false && pollDelta >= m_pollInterval) { - L.log(bus, trace, "polling Intervall reached"); - - int index = m_commands->nextPolCommand(); - if (index < 0) { - L.log(bus, error, "polling index out of range"); - time(&pollStart); - continue; - } - - std::string tmp; - tmp += (*m_commands)[index][1]; - tmp += " "; - tmp += (*m_commands)[index][2]; - L.log(bus, event, " polling [%d] %s", index, tmp.c_str()); - - std::string ebusCommand(A.getParam("p_address")); - ebusCommand += m_commands->getEbusCommand(index); - std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); - - BusCommand* busCommand = new BusCommand(ebusCommand, true); - L.log(bus, trace, " msg: %s", ebusCommand.c_str()); - - m_bus->addCommand(busCommand); - L.log(bus, debug, " addCommand success"); - busCommandActive = true; - - time(&pollStart); - } - - } - - // send bus command - if (busResult == RESULT_BUS_ACQUIRED && busCommandActive == true) { - L.log(bus, trace, " getBus success"); - lookbusretries = 0; - BusCommand* busCommand = m_bus->sendCommand(); - L.log(bus, trace, " %s", busCommand->getMessageStr().c_str()); - - if (busCommand->isErrorResult() == true && retries < m_retries) { - retries++; - L.log(bus, trace, " retry number: %d", retries); - busCommand->setResult(std::string(), RESULT_OK); - m_bus->addCommand(busCommand); - } else { - retries = 0; - if (busCommand->isPoll() == true) { - // only save correct results - if (busCommand->isErrorResult() == false) - m_commands->storePolData(busCommand->getMessageStr().c_str()); // TODO use getResult() - - delete busCommand; - } else { - busCommand->sendSignal(); - } - - busCommandActive = false; - } - } - - // get bus retry - if (busResult == RESULT_BUS_PRIOR_RETRY) - L.log(bus, trace, " getBus prior retry"); - - if (busResult == RESULT_ERR_BUS_LOST) { - L.log(bus, trace, " getBus failure"); - if (lookbusretries >= m_lookbusretries) { - L.log(bus, event, " getBus failed - command deleted"); - BusCommand* busCommand = m_bus->delCommand(); - if (busCommand->isPoll() == true) { - delete busCommand; - } else { - busCommand->sendSignal(); - } - lookbusretries = 0; - busCommandActive = false; - }else { - lookbusretries++; - } - } - - if (busResult == RESULT_ERR_SEND) - L.log(bus, event, " getBus send error"); - - } else { - sleep(10); - m_bus->connect(); - - if (m_bus->isConnected() == false) - L.log(bus, error, "can't open %s", m_deviceName.c_str()); + // compare sent and received byte + if (sendByte == recvByte) { + L.log(bus, trace, " bus acquired"); + return RESULT_BUS_ACQUIRED; } - if (m_stop == true) { - m_bus->disconnect(); - return NULL; + // collect cycle data + if (recvByte != SYN) + m_sstr.push_back(recvByte, true, false); + + // compare prior nibble for retry + if ((sendByte & 0x0F) == (recvByte & 0x0F)) { + m_priorRetry = true; + L.log(bus, trace, " bus prior retry"); + return RESULT_BUS_PRIOR_RETRY; + } + + L.log(bus, trace, " ERR_BUS_LOST: lost bus arbitration"); + return RESULT_ERR_BUS_LOST; + } + + // cycle bytes + collectCycData(numRecv); + + L.log(bus, trace, " ERR_BUS_LOST: lost bus arbitration"); + return RESULT_ERR_BUS_LOST; +} + +BusCommand* EBusLoop::sendCommand() +{ + unsigned char recvByte; + std::string result; + SymbolString slaveData; + int retval = RESULT_OK; + + BusCommand* busCommand = m_sendBuffer.next(); + + // send ZZ PB SB NN Dx CRC + SymbolString command = busCommand->getCommand(); + for (size_t i = 1; i < command.size(); i++) { + retval = sendByte(command[i]); + if (retval < 0) + goto on_exit; + } + + // BC -> send SYN + if (busCommand->getType() == broadcast) { + sendByte(SYN); + goto on_exit; + } + + // receive ACK + retval = recvSlaveAck(recvByte); + if (retval < 0) + goto on_exit; + + // is slave ACK negative? + if (recvByte == NAK) { + + // send QQ ZZ PB SB NN Dx CRC again + for (size_t i = 0; i < command.size(); i++) { + retval = sendByte(command[i]); + if (retval < 0) + goto on_exit; + } + + // receive ACK + retval = recvSlaveAck(recvByte); + if (retval < 0) + goto on_exit; + + // is slave ACK negative? + if (recvByte == NAK) { + sendByte(SYN); + L.log(bus, trace, " ERR_NAK: NAK received"); + retval = RESULT_ERR_NAK; + goto on_exit; } } - return NULL; + // MM -> send SYN + if (busCommand->getType() == masterMaster) { + sendByte(SYN); + goto on_exit; + } + + // receive NN, Dx, CRC + retval = recvSlaveData(slaveData); + + // are calculated and received CRC equal? + if (retval == RESULT_ERR_CRC) { + + // send NAK + retval = sendByte(NAK); + if (retval < 0) + goto on_exit; + + // receive NN, Dx, CRC + slaveData.clear(); + retval = recvSlaveData(slaveData); + + // are calculated and received CRC equal? + if (retval == RESULT_ERR_CRC) { + + // send NAK + retval = sendByte(NAK); + if (retval >= 0) + retval = RESULT_ERR_CRC; + } + } + + if (retval < 0) + goto on_exit; + + // send ACK + retval = sendByte(ACK); + if (retval == -1) { + L.log(bus, trace, " ERR_ACK: ACK error"); + retval = RESULT_ERR_ACK; + goto on_exit; + } + + // MS -> send SYN + sendByte(SYN); + +on_exit: + + // empty receive buffer + while (m_port->size() != 0) + recvByte = fetchByte(); + + busCommand->setResult(slaveData, retval); + + if (retval == RESULT_OK) + return m_sendBuffer.remove(); + else + return busCommand; + +} + +int EBusLoop::sendByte(const unsigned char sendByte) +{ + unsigned char recvByte; + ssize_t numRecv, numSend; + + numSend = m_port->send(&sendByte); + + // receive 1 byte - must be equal + numRecv = m_port->recv(RECV_TIMEOUT); + + if (numSend != numRecv) { + L.log(bus, trace, " ERR_EXTRA_DATA: received bytes > sent bytes"); + return RESULT_ERR_EXTRA_DATA; + } + + recvByte = fetchByte(); + + if (sendByte != recvByte) { + L.log(bus, trace, " ERR_SEND: send error"); + return RESULT_ERR_SEND; + } + + return RESULT_OK; +} + +int EBusLoop::recvSlaveAck(unsigned char& recvByte) +{ + ssize_t numRecv; + + // receive ACK + numRecv = m_port->recv(m_recvTimeout); + + if (numRecv > 1) { + L.log(bus, trace, " ERR_EXTRA_DATA: received bytes > sent bytes"); + return RESULT_ERR_EXTRA_DATA; + } + else if (numRecv < 0) { + L.log(bus, trace, " ERR_TIMEOUT: read timeout"); + return RESULT_ERR_TIMEOUT; + } + + recvByte = fetchByte(); + + // is received byte SYN? + if (recvByte == SYN) { + L.log(bus, trace, " ERR_SYN: SYN received"); + return RESULT_ERR_SYN; + } + + return RESULT_OK; +} + +int EBusLoop::recvSlaveData(SymbolString& result) +{ + unsigned char recvByte, calcCrc = 0; + ssize_t numRecv; + size_t NN = 0; + bool updateCrc = true; + int retval = 0; + + for (size_t i = 0, needed = 1; i < needed; i++) { + numRecv = m_port->recv(RECV_TIMEOUT); + if (numRecv < 0) { + L.log(bus, trace, " ERR_TIMEOUT: read timeout"); + return RESULT_ERR_TIMEOUT; + } + + recvByte = fetchByte(); + retval = result.push_back(recvByte, true, updateCrc); + if (retval < 0) + return retval; + + if (retval == RESULT_IN_ESC) + needed++; + else if (result.size() == 1) { // NN received + NN = result[0]; + needed += NN; + } + else if (NN > 0 && result.size() == 1+NN) {// all data received + updateCrc = false; + calcCrc = result.getCRC(); + needed++; + } + } + + if (retval == RESULT_IN_ESC) { + L.log(bus, trace, " ERR_ESC: invalid escape sequence received"); + return RESULT_ERR_ESC; + } + + if (updateCrc == true || calcCrc != result[result.size()-1]) { + L.log(bus, trace, " ERR_CRC: CRC error"); + return RESULT_ERR_CRC; + } + + return RESULT_OK; } -*/ diff --git a/src/ebusd/ebusloop.h b/src/ebusd/ebusloop.h index 245d01f6..d7b4dcdd 100644 --- a/src/ebusd/ebusloop.h +++ b/src/ebusd/ebusloop.h @@ -20,7 +20,6 @@ #ifndef EBUSLOOP_H_ #define EBUSLOOP_H_ -//~ #include "bus.h" #include "commands.h" #include "port.h" #include "dump.h" @@ -28,6 +27,9 @@ #include "wqueue.h" #include "thread.h" +/** the maximum time [us] allowed for retrieving a byte from an addressed slave */ +#define RECV_TIMEOUT 10000 + using namespace libebus; @@ -43,7 +45,6 @@ public: void addBusCommand(BusCommand* busCommand) { m_sendBuffer.add(busCommand); } - //~ void dump(const bool dumpState) { m_bus->setDumpState(dumpState); } void dump(const bool dumpState) { m_dumpState = dumpState; } void newCommands(Commands* commands) { m_commands = commands; } @@ -59,19 +60,26 @@ private: bool m_stop; - SymbolString m_sstr; - - //~ std::string m_deviceName; - //~ bool m_noDeviceCheck; - //~ Bus* m_bus; + bool m_busLocked; + bool m_priorRetry; WQueue m_sendBuffer; - //~ int m_retries; - //~ int m_lookbusretries; - //~ double m_pollInterval; + SymbolString m_sstr; - unsigned char recvByte(); - void analyseCycData(SymbolString data) const; + double m_pollInterval; + long m_recvTimeout; + int m_sendRetries; + int m_lockRetries; + + unsigned char fetchByte(); + void collectCycData(const int numRecv); + void analyseCycData(); + void addPollCommand(); + int acquireBus(); + BusCommand* sendCommand(); + int sendByte(const unsigned char sendByte); + int recvSlaveAck(unsigned char& recvByte); + int recvSlaveData(SymbolString& result); }; diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index cd456d02..7fef5379 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -47,12 +47,12 @@ void define_args() "disable valid ebus device test\n", Appl::type_bool, Appl::opt_none); - A.addItem("p_retries", Appl::Param(2), "r", "retries", - "\tnumber retries send ebus command (2)", + A.addItem("p_sendretries", Appl::Param(2), "s", "sendretries", + "number retries send ebus command (2)", Appl::type_int, Appl::opt_mandatory); - A.addItem("p_lookbusretries", Appl::Param(2), "", "lookbusretries", - "number retries to look ebus (2)", + A.addItem("p_lockretries", Appl::Param(2), "", "lockretries", + "number retries to lock ebus (2)", Appl::type_int, Appl::opt_mandatory); A.addItem("p_recvtimeout", Appl::Param(15000), "", "recvtimeout", diff --git a/src/lib/ebus/buscommand.cpp b/src/lib/ebus/buscommand.cpp index e7c35dd0..ac822f63 100644 --- a/src/lib/ebus/buscommand.cpp +++ b/src/lib/ebus/buscommand.cpp @@ -54,9 +54,9 @@ const std::string BusCommand::getMessageStr() result += "00"; result += m_result.getDataStr(); result += "00"; - } else { - result = "success"; } + else + result = "success"; } else result = "error: "+std::string(getResultCodeCStr()); diff --git a/src/lib/ebus/port.h b/src/lib/ebus/port.h index bb45ca4f..7dc8e53a 100644 --- a/src/lib/ebus/port.h +++ b/src/lib/ebus/port.h @@ -31,6 +31,9 @@ namespace libebus /** available device types. */ enum DeviceType { SERIAL, NETWORK }; +/** max bytes write to bus. */ +#define MAX_WRITE_SIZE 1 + /** max size of receive buffer. */ #define MAX_READ_SIZE 100 @@ -218,7 +221,7 @@ public: * @param nbytes number of bytes to send. * @return number of written bytes or -1 if an error has occured. */ - ssize_t send(const unsigned char* buffer, size_t nbytes) + ssize_t send(const unsigned char* buffer, size_t nbytes = MAX_WRITE_SIZE) { return m_device->sendBytes(buffer, nbytes); } /** diff --git a/src/lib/utils/wqueue.h b/src/lib/utils/wqueue.h index 15cca9a0..0509b87e 100644 --- a/src/lib/utils/wqueue.h +++ b/src/lib/utils/wqueue.h @@ -64,6 +64,20 @@ public: return item; } + T next() + { + pthread_mutex_lock(&m_mutex); + + while (m_queue.size() == 0) + pthread_cond_wait(&m_cond, &m_mutex); + + T item = m_queue.front(); + + pthread_mutex_unlock(&m_mutex); + + return item; + } + int size() { pthread_mutex_lock(&m_mutex); From d53afc87013de779a091f3b74a088cbdeb3c6c93 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 7 Nov 2014 22:36:21 +0100 Subject: [PATCH 11/15] class Bus removed. --- src/lib/ebus/Makefile.am | 2 - src/lib/ebus/bus.cpp | 388 --------------------------------- src/lib/ebus/bus.h | 89 -------- src/lib/ebus/test/Makefile.am | 4 - src/lib/ebus/test/test_bus.cpp | 58 ----- 5 files changed, 541 deletions(-) delete mode 100644 src/lib/ebus/bus.cpp delete mode 100644 src/lib/ebus/bus.h delete mode 100644 src/lib/ebus/test/test_bus.cpp diff --git a/src/lib/ebus/Makefile.am b/src/lib/ebus/Makefile.am index e78d40bc..64fa53d9 100644 --- a/src/lib/ebus/Makefile.am +++ b/src/lib/ebus/Makefile.am @@ -14,8 +14,6 @@ libebus_a_SOURCES = result.cpp \ port.h \ buscommand.cpp \ buscommand.h \ - bus.cpp \ - bus.h \ command.cpp \ command.h \ commands.cpp \ diff --git a/src/lib/ebus/bus.cpp b/src/lib/ebus/bus.cpp deleted file mode 100644 index e12d9ac2..00000000 --- a/src/lib/ebus/bus.cpp +++ /dev/null @@ -1,388 +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/. - */ - -#include "bus.h" -#include -#include - -namespace libebus -{ - - -Bus::Bus(const std::string deviceName, const bool noDeviceCheck, const long recvTimeout, - const std::string dumpFile, const long dumpSize, const bool dumpState) - : m_sstr(), m_recvTimeout(recvTimeout), m_dumpState(dumpState), - m_busLocked(false), m_busPriorRetry(false) -{ - m_port = new Port(deviceName, noDeviceCheck); - m_dump = new Dump(dumpFile, dumpSize); -} - -Bus::~Bus() -{ - if (isConnected() == true) - disconnect(); - - delete m_port; - delete m_dump; -} - -void Bus::printBytes() const -{ - unsigned char byte; - ssize_t bytes_read; - - bytes_read = m_port->recv(0); - - for (int i = 0; i < bytes_read; i++) { - byte = m_port->byte(); - std::cout << std::nouppercase << std::hex << std::setw(2) - << std::setfill('0') << static_cast(byte); - if (byte == SYN) - std::cout << std::endl; - } -} - -int Bus::proceed() -{ - unsigned char byte; - ssize_t nbytes; - - // fetch new message and get bus - if (m_sendBuffer.size() != 0 && m_sstr.size() == 0) { - BusCommand* busCommand = m_sendBuffer.front(); - return getBus(busCommand->getCommand()[0]); - } - - // wait for new data - nbytes = m_port->recv(0); - - if (nbytes < 0) - return RESULT_ERR_DEVICE; - - for (int i = 0; i < nbytes; i++) { - - // fetch next byte - byte = recvByte(); - - // store byte - return proceedCycData(byte); // TODO what if more than one byte was received? - } - - return RESULT_SYN; -} - -int Bus::proceedCycData(const unsigned char byte) -{ - if (byte != SYN) { - m_sstr.push_back(byte, true, false); - if (m_busLocked == true) - m_busLocked = false; - - return RESULT_DATA; - } - - if (byte == SYN && m_sstr.size() != 0) { - // lock bus after SYN-BYTE-SYN Sequence - if (m_sstr.size() == 1 && m_busPriorRetry == false) - m_busLocked = true; - - m_cycBuffer.push(m_sstr); - m_sstr.clear(); - - if (m_busLocked == true) - return RESULT_BUS_LOCKED; - } - - return RESULT_SYN; -} - -SymbolString Bus::getCycData() -{ - SymbolString data; - - if (m_cycBuffer.empty() == false) { - data = m_cycBuffer.front(); - m_cycBuffer.pop(); - } - - return data; -} - -int Bus::getBus(const unsigned char byte_sent) -{ - unsigned char byte_recv; - ssize_t bytes_sent, bytes_recv; - - // send QQ - bytes_sent = m_port->send(&byte_sent, 1); - if (bytes_sent <= 0) - return RESULT_ERR_SEND; - - // receive 1 byte - must be QQ - bytes_recv = m_port->recv(0, 1); - - if (bytes_recv < 0) - return RESULT_ERR_DEVICE; - - // fetch next byte - byte_recv = recvByte(); - - // compare sent and received byte - if (bytes_recv == 1 && byte_sent == byte_recv) { - m_busPriorRetry = false; - return RESULT_BUS_ACQUIRED; - } - - // store byte - int ret = proceedCycData(byte_recv); - if (ret >= 0) - return ret; -// TODO this needs to be re-designed with above proceedCycData() - // compare prior nibble for retry - if (bytes_recv == 1 && (byte_sent & 0x0F) == (byte_recv & 0x0F)) { - m_busPriorRetry = true; - return RESULT_BUS_PRIOR_RETRY; - } - - m_busLocked = true; - return RESULT_ERR_BUS_LOST; -} - -BusCommand* Bus::sendCommand() -{ - unsigned char byte_recv; - ssize_t bytes_recv; - std::string result; - SymbolString slaveData; - int retval = RESULT_OK; - - BusCommand* busCommand = m_sendBuffer.front(); - m_sendBuffer.pop(); - - // send ZZ PB SB NN Dx CRC - SymbolString command = busCommand->getCommand(); - for (size_t i = 1; i < command.size(); i++) { - retval = sendByte(command[i]); - if (retval < 0) - goto on_exit; - } - - // BC -> send SYN - if (busCommand->getType() == broadcast) { - sendByte(SYN); - goto on_exit; - } - - // receive ACK - bytes_recv = m_port->recv(m_recvTimeout); - if (bytes_recv > 1) { - retval = RESULT_ERR_EXTRA_DATA; - goto on_exit; - } else if (bytes_recv < 0) { - retval = RESULT_ERR_TIMEOUT; - goto on_exit; - } - - byte_recv = recvByte(); - - // is received byte SYN? - if (byte_recv == SYN) { - retval = RESULT_ERR_SYN; - goto on_exit; - } - - // is slave ACK negative? - if (byte_recv == NAK) { - - // send QQ ZZ PB SB NN Dx CRC again - for (size_t i = 0; i < command.size(); i++) { - retval = sendByte(command[i]); - if (retval < 0) - goto on_exit; - } - - // receive ACK - bytes_recv = m_port->recv(m_recvTimeout); - if (bytes_recv > 1) { - retval = RESULT_ERR_EXTRA_DATA; - goto on_exit; - } else if (bytes_recv < 0) { - retval = RESULT_ERR_TIMEOUT; - goto on_exit; - } - - byte_recv = recvByte(); - - // is received byte SYN? - if (byte_recv == SYN) { - retval = RESULT_ERR_SYN; - goto on_exit; - } - - // is slave ACK negative? - if (byte_recv == NAK) { - retval = sendByte(SYN); - if (retval == 0) - retval = RESULT_ERR_NAK; - - goto on_exit; - } - } - - // MM -> send SYN - if (busCommand->getType() == masterMaster) { - sendByte(SYN); - goto on_exit; - } - - // receive NN, Dx, CRC - retval = recvSlaveDataAndCRC(slaveData); - - // are calculated and received CRC equal? - if (retval == RESULT_ERR_CRC) { - - // send NAK - retval = sendByte(NAK); - if (retval < 0) - goto on_exit; - - // receive NN, Dx, CRC - slaveData.clear(); - retval = recvSlaveDataAndCRC(slaveData); - - // are calculated and received CRC equal? - if (retval == RESULT_ERR_CRC) { - - // send NAK - retval = sendByte(NAK); - if (retval >= 0) - retval = RESULT_ERR_CRC; - } - } - - if (retval < 0) - goto on_exit; - - // send ACK - retval = sendByte(ACK); - if (retval == -1) { - retval = RESULT_ERR_ACK; - goto on_exit; - } - - // MS -> send SYN - sendByte(SYN); - -on_exit: - - // empty receive buffer - while (m_port->size() != 0) - byte_recv = recvByte(); - - busCommand->setResult(slaveData, retval); - return busCommand; - -} - -BusCommand* Bus::delCommand() -{ - BusCommand* busCommand = m_sendBuffer.front(); - m_sendBuffer.pop(); - - busCommand->setResult(SymbolString(), RESULT_ERR_BUS_LOST); - return busCommand; -} - -int Bus::sendByte(const unsigned char byte_sent) -{ - unsigned char byte_recv; - ssize_t bytes_sent, bytes_recv; - - bytes_sent = m_port->send(&byte_sent, 1); - - // receive 1 byte - must be equal - bytes_recv = m_port->recv(RECV_TIMEOUT); - if (bytes_sent != bytes_recv) - return RESULT_ERR_EXTRA_DATA; - - byte_recv = recvByte(); - - if (byte_sent != byte_recv) - return RESULT_ERR_SEND; - - return RESULT_OK; -} - -unsigned char Bus::recvByte() -{ - unsigned char byte_recv; - - // fetch byte - byte_recv = m_port->byte(); - - if (m_dumpState == true) - m_dump->write((const char*) &byte_recv); - - return byte_recv; -} - -int Bus::recvSlaveDataAndCRC(SymbolString& result) -{ - unsigned char byte_recv, crc_calc = 0; - ssize_t bytes_recv; - size_t NN = 0; - bool updateCrc = true; - int retval = 0; - - for (size_t i = 0, needed = 1; i < needed; i++) { - bytes_recv = m_port->recv(RECV_TIMEOUT, 1); - if (bytes_recv < 0) - return RESULT_ERR_TIMEOUT; - - byte_recv = recvByte(); - retval = result.push_back(byte_recv, true, updateCrc); - if (retval < 0) - return retval; - - if (retval == RESULT_IN_ESC) - needed++; - else if (result.size() == 1) { // NN received - NN = result[0]; - needed += NN; - } - else if (NN > 0 && result.size() == 1+NN) {// all data received - updateCrc = false; - crc_calc = result.getCRC(); - needed++; - } - } - - if (retval == RESULT_IN_ESC) - return RESULT_ERR_ESC; - - if (updateCrc || crc_calc != result[result.size()-1]) - return RESULT_ERR_CRC; - - return RESULT_OK; -} - - -} //namespace - diff --git a/src/lib/ebus/bus.h b/src/lib/ebus/bus.h deleted file mode 100644 index d752dbd7..00000000 --- a/src/lib/ebus/bus.h +++ /dev/null @@ -1,89 +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_BUS_H_ -#define LIBEBUS_BUS_H_ - -#include "symbol.h" -#include "result.h" -#include "port.h" -#include "dump.h" -#include "buscommand.h" -#include -#include -#include -#include - -namespace libebus -{ - - -// the maximum time allowed for retrieving a byte from an addressed slave -#define RECV_TIMEOUT 10000 - -class Bus -{ - -public: - Bus(const std::string deviceName, const bool noDeviceCheck, const long recvTimeout, - const std::string dumpFile, const long dumpSize, const bool dumpState); - ~Bus(); - - void connect() { m_port->open(); } - void disconnect() { if (m_port->isOpen() == true) m_port->close(); } - bool isConnected() { return m_port->isOpen(); } - - void printBytes() const; - - int proceed(); - SymbolString getCycData(); - - void addCommand(BusCommand* busCommand) { m_sendBuffer.push(busCommand); } - - int getBus(const unsigned char byte); - BusCommand* sendCommand(); - BusCommand* delCommand(); - - void setDumpState(const bool dumpState) { m_dumpState = dumpState; } - -private: - Port* m_port; - SymbolString m_sstr; - std::queue m_cycBuffer; - std::queue m_sendBuffer; - - const long m_recvTimeout; - - Dump* m_dump; - bool m_dumpState; - - bool m_busLocked; - bool m_busPriorRetry; - - int proceedCycData(const unsigned char byte); - int sendByte(const unsigned char byte_sent); - unsigned char recvByte(); - int recvSlaveDataAndCRC(SymbolString& result); - -}; - - -} //namespace - -#endif // LIBEBUS_BUS_H_ diff --git a/src/lib/ebus/test/Makefile.am b/src/lib/ebus/test/Makefile.am index 8236c57c..55dff9aa 100644 --- a/src/lib/ebus/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -6,7 +6,6 @@ AM_CXXFLAGS = -fpic \ noinst_PROGRAMS = test_port \ test_symbol \ test_data \ - test_bus \ test_commands \ test_configfile \ test_decode \ @@ -21,9 +20,6 @@ test_symbol_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_data_SOURCES = test_data.cpp test_data_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a -test_bus_SOURCES = test_bus.cpp -test_bus_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a - test_commands_SOURCES = test_commands.cpp test_commands_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a diff --git a/src/lib/ebus/test/test_bus.cpp b/src/lib/ebus/test/test_bus.cpp deleted file mode 100644 index 518ddde3..00000000 --- a/src/lib/ebus/test/test_bus.cpp +++ /dev/null @@ -1,58 +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/. - */ - -#include "bus.h" -#include -#include - -using namespace libebus; - -int main () -{ - Bus bus("/dev/ttyUSB0", true, 15000, "/tmp/dump_bus.bin", 100, false); - - bus.connect(); - - if (bus.isConnected() == true) - std::cout << "connect successful." << std::endl; - - int cout = 0; - - while (cout++ < 1000) { - if (bus.isConnected() == true) { - bus.printBytes(); - } else { - sleep(5); - bus.connect(); - - if (bus.isConnected() == false) - std::cout << "can't open /dev/ttyUSB0" << std::endl; - else - std::cout << "reconnect successful." << std::endl; - } - } - - bus.disconnect(); - - if (bus.isConnected() == false) - std::cout << "disconnect successful." << std::endl; - - return 0; - -} From e6930d333d02be5a180ac7fc921f64b5d9ea0cd1 Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Fri, 7 Nov 2014 23:15:51 +0100 Subject: [PATCH 12/15] missing reset of lockRetries added. --- src/ebusd/ebusloop.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index e429086d..78b015a8 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -128,6 +128,7 @@ void* EBusLoop::run() busCommand->sendSignal(); } + lockRetries = 0; } else { L.log(bus, trace, " acquire bus failed"); @@ -141,8 +142,10 @@ void* EBusLoop::run() lockRetries = 0; } - else + else { lockRetries++; + L.log(bus, trace, " lock retry %d", lockRetries); + } } From e4544a98ade6937f523bef66228d55ba8145a1cf Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Sat, 8 Nov 2014 09:39:07 +0100 Subject: [PATCH 13/15] server command 'raw' - toggle log raw data added; log types of error messages changed from trace to error. --- src/ebusd/baseloop.cpp | 34 ++++++++++++++++++++++------------ src/ebusd/baseloop.h | 24 +++++++++++++----------- src/ebusd/ebusloop.cpp | 34 +++++++++++++++++----------------- src/ebusd/ebusloop.h | 3 ++- 4 files changed, 54 insertions(+), 41 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index b74e34ee..c23607fd 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -292,17 +292,6 @@ std::string BaseLoop::decodeMessage(const std::string& data) break; - case dump: - if (cmd.size() != 2) { - result << "usage: 'dump state' (state: on|off)"; - break; - } - - if (strcasecmp(cmd[1].c_str(), "ON") == 0) m_ebusloop->dump(true); - if (strcasecmp(cmd[1].c_str(), "OFF") == 0) m_ebusloop->dump(false); - result << "done"; - break; - case log: if (cmd.size () != 3 ) { result << "usage: 'log areas area,area,..' (areas: bas|net|bus|cyc|all)" << std::endl @@ -328,6 +317,26 @@ std::string BaseLoop::decodeMessage(const std::string& data) break; + case raw: + if (cmd.size() != 1) { + result << "usage: 'raw'"; + break; + } + + m_ebusloop->raw(); + result << "done"; + break; + + case dump: + if (cmd.size() != 1) { + result << "usage: 'dump'"; + break; + } + + m_ebusloop->dump(); + result << "done"; + break; + case reload: if (cmd.size() != 1) { result << "usage: 'reload'"; @@ -356,9 +365,10 @@ std::string BaseLoop::decodeMessage(const std::string& data) << " set - set ebus values 'set class cmd value'" << std::endl << " cyc - fetch cycle data 'cyc class cmd (sub)'" << std::endl << " hex - send given hex value 'hex type value' (value: ZZPBSBNNDx)" << std::endl << std::endl - << " dump - change dump state 'dump state' (state: on|off)" << std::endl << std::endl << " log - change log areas 'log areas area,area,..' (areas: bas|net|bus|cyc|all)" << std::endl << " - change log level 'log level level' (level: error|event|trace|debug)" << std::endl << std::endl + << " raw - toggle log raw data" << std::endl + << " dump - toggle dump state" << std::endl << std::endl << " reload - reload ebus configuration" << std::endl << std::endl << " stop - stop daemon" << std::endl << " quit - close connection" << std::endl << std::endl diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h index f71649f2..9e68555c 100644 --- a/src/ebusd/baseloop.h +++ b/src/ebusd/baseloop.h @@ -46,16 +46,17 @@ private: WQueue m_queue; enum ClientCommand { - get, // get ebus data - set, // set ebus value - cyc, // fetch cycle data - hex, // send hex value - dump, // change dump state - log, // logger settings - reload, // reload ebus configuration - help, // print commands - notfound - }; + get, // get ebus data + set, // set ebus value + cyc, // fetch cycle data + hex, // send hex value + log, // logger settings + raw, // toggle log raw data + dump, // toggle dump state + reload, // reload ebus configuration + help, // print commands + notfound + }; ClientCommand getCase(const std::string& item) { @@ -63,8 +64,9 @@ private: if (strcasecmp(item.c_str(), "SET") == 0) return set; if (strcasecmp(item.c_str(), "CYC") == 0) return cyc; if (strcasecmp(item.c_str(), "HEX") == 0) return hex; - if (strcasecmp(item.c_str(), "DUMP") == 0) return dump; if (strcasecmp(item.c_str(), "LOG") == 0) return log; + if (strcasecmp(item.c_str(), "RAW") == 0) return raw; + if (strcasecmp(item.c_str(), "DUMP") == 0) return dump; if (strcasecmp(item.c_str(), "RELOAD") == 0) return reload; if (strcasecmp(item.c_str(), "HELP") == 0) return help; diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index 78b015a8..686e73bb 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -247,7 +247,7 @@ void EBusLoop::analyseCycData() tmp += (*m_commands)[index][1]; tmp += " "; tmp += (*m_commands)[index][2]; - L.log(bus, event, " cycle [%d] %s", index, tmp.c_str()); + L.log(bus, event, " cycle [%4d] %s", index, tmp.c_str()); } } @@ -263,7 +263,7 @@ void EBusLoop::addPollCommand() tmp += (*m_commands)[index][1]; tmp += " "; tmp += (*m_commands)[index][2]; - L.log(bus, event, " polling [%d] %s", index, tmp.c_str()); + L.log(bus, event, " polling [%4d] %s", index, tmp.c_str()); std::string ebusCommand(A.getParam("p_address")); ebusCommand += m_commands->getEbusCommand(index); @@ -286,7 +286,7 @@ int EBusLoop::acquireBus() // send QQ numSend = m_port->send(&sendByte); if (numSend <= 0) { - L.log(bus, trace, " ERR_SEND: send error"); + L.log(bus, error, " ERR_SEND: send error"); return RESULT_ERR_SEND; } @@ -294,7 +294,7 @@ int EBusLoop::acquireBus() numRecv = m_port->recv(0); if (numRecv < 0) { - L.log(bus, trace, " ERR_DEVICE: generic device error"); + L.log(bus, error, " ERR_DEVICE: generic device error"); return RESULT_ERR_DEVICE; } @@ -319,15 +319,15 @@ int EBusLoop::acquireBus() return RESULT_BUS_PRIOR_RETRY; } - L.log(bus, trace, " ERR_BUS_LOST: lost bus arbitration"); + L.log(bus, error, " ERR_BUS_LOST: lost bus arbitration"); return RESULT_ERR_BUS_LOST; } // cycle bytes collectCycData(numRecv); - L.log(bus, trace, " ERR_BUS_LOST: lost bus arbitration"); - return RESULT_ERR_BUS_LOST; + L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes"); + return RESULT_ERR_EXTRA_DATA; } BusCommand* EBusLoop::sendCommand() @@ -376,7 +376,7 @@ BusCommand* EBusLoop::sendCommand() // is slave ACK negative? if (recvByte == NAK) { sendByte(SYN); - L.log(bus, trace, " ERR_NAK: NAK received"); + L.log(bus, error, " ERR_NAK: NAK received"); retval = RESULT_ERR_NAK; goto on_exit; } @@ -419,7 +419,7 @@ BusCommand* EBusLoop::sendCommand() // send ACK retval = sendByte(ACK); if (retval == -1) { - L.log(bus, trace, " ERR_ACK: ACK error"); + L.log(bus, error, " ERR_ACK: ACK error"); retval = RESULT_ERR_ACK; goto on_exit; } @@ -453,14 +453,14 @@ int EBusLoop::sendByte(const unsigned char sendByte) numRecv = m_port->recv(RECV_TIMEOUT); if (numSend != numRecv) { - L.log(bus, trace, " ERR_EXTRA_DATA: received bytes > sent bytes"); + L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes"); return RESULT_ERR_EXTRA_DATA; } recvByte = fetchByte(); if (sendByte != recvByte) { - L.log(bus, trace, " ERR_SEND: send error"); + L.log(bus, error, " ERR_SEND: send error"); return RESULT_ERR_SEND; } @@ -475,11 +475,11 @@ int EBusLoop::recvSlaveAck(unsigned char& recvByte) numRecv = m_port->recv(m_recvTimeout); if (numRecv > 1) { - L.log(bus, trace, " ERR_EXTRA_DATA: received bytes > sent bytes"); + L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes"); return RESULT_ERR_EXTRA_DATA; } else if (numRecv < 0) { - L.log(bus, trace, " ERR_TIMEOUT: read timeout"); + L.log(bus, error, " ERR_TIMEOUT: read timeout"); return RESULT_ERR_TIMEOUT; } @@ -487,7 +487,7 @@ int EBusLoop::recvSlaveAck(unsigned char& recvByte) // is received byte SYN? if (recvByte == SYN) { - L.log(bus, trace, " ERR_SYN: SYN received"); + L.log(bus, error, " ERR_SYN: SYN received"); return RESULT_ERR_SYN; } @@ -505,7 +505,7 @@ int EBusLoop::recvSlaveData(SymbolString& result) for (size_t i = 0, needed = 1; i < needed; i++) { numRecv = m_port->recv(RECV_TIMEOUT); if (numRecv < 0) { - L.log(bus, trace, " ERR_TIMEOUT: read timeout"); + L.log(bus, error, " ERR_TIMEOUT: read timeout"); return RESULT_ERR_TIMEOUT; } @@ -528,12 +528,12 @@ int EBusLoop::recvSlaveData(SymbolString& result) } if (retval == RESULT_IN_ESC) { - L.log(bus, trace, " ERR_ESC: invalid escape sequence received"); + L.log(bus, error, " ERR_ESC: invalid escape sequence received"); return RESULT_ERR_ESC; } if (updateCrc == true || calcCrc != result[result.size()-1]) { - L.log(bus, trace, " ERR_CRC: CRC error"); + L.log(bus, error, " ERR_CRC: CRC error"); return RESULT_ERR_CRC; } diff --git a/src/ebusd/ebusloop.h b/src/ebusd/ebusloop.h index d7b4dcdd..599afc69 100644 --- a/src/ebusd/ebusloop.h +++ b/src/ebusd/ebusloop.h @@ -45,7 +45,8 @@ public: void addBusCommand(BusCommand* busCommand) { m_sendBuffer.add(busCommand); } - void dump(const bool dumpState) { m_dumpState = dumpState; } + void dump() { m_dumpState == true ? m_dumpState = false : m_dumpState = true ; } + void raw() { m_logRawData == true ? m_logRawData = false : m_logRawData = true ; } void newCommands(Commands* commands) { m_commands = commands; } From ca6c6c04bb7d65e6cb5588692788db0b3a4adeac Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Sat, 8 Nov 2014 11:37:44 +0100 Subject: [PATCH 14/15] daemon option --lockcounter added; m_busLocked replaced with m_lockCounter. --- src/ebusd/ebusloop.cpp | 47 +++++++++++++++++++++--------------------- src/ebusd/ebusloop.h | 2 +- src/ebusd/main.cpp | 4 ++++ src/lib/ebus/port.cpp | 2 +- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index 686e73bb..a2881117 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -25,7 +25,7 @@ extern LogInstance& L; extern Appl& A; EBusLoop::EBusLoop(Commands* commands) - : m_commands(commands), m_stop(false), m_busLocked(false), m_priorRetry(false) + : m_commands(commands), m_stop(false), m_lockCounter(0), m_priorRetry(false) { m_port = new Port(A.getParam("p_device"), A.getParam("p_nodevicecheck")); m_port->open(); @@ -70,7 +70,7 @@ void* EBusLoop::run() if (m_port->isOpen() == true) { ssize_t numBytes; - // add poll command - timer reached + // add poll command if (m_commands->sizePolDB() > 0) { // check polling delta time(&pollEnd); @@ -95,7 +95,7 @@ void* EBusLoop::run() collectCycData(numBytes); // send command - if (m_sstr.size() == 0 && m_busLocked == false && m_sendBuffer.size() > 0) { + if (m_sstr.size() == 0 && m_lockCounter == 0 && m_sendBuffer.size() > 0) { // acquire Bus int busResult = acquireBus(); @@ -129,9 +129,11 @@ void* EBusLoop::run() } lockRetries = 0; + m_lockCounter = A.getParam("p_lockcounter"); } - else { + else if (busResult == RESULT_ERR_BUS_LOST) { L.log(bus, trace, " acquire bus failed"); + if (lockRetries >= m_lockRetries) { L.log(bus, event, " lock bus failed"); BusCommand* busCommand = m_sendBuffer.remove(); @@ -147,6 +149,7 @@ void* EBusLoop::run() L.log(bus, trace, " lock retry %d", lockRetries); } + m_lockCounter = A.getParam("p_lockcounter"); } } @@ -198,32 +201,30 @@ void EBusLoop::collectCycData(const int numRecv) // fetch byte unsigned char byte = fetchByte(); - // collect cycle data - if (byte != SYN) - m_sstr.push_back(byte, true, false); + if (byte == SYN) { - // unlock bus - if (byte == SYN && m_busLocked == true) { - m_busLocked = false; - L.log(bus, trace, " bus unlocked"); - } + // analyse cycle data + if (m_sstr.size() > 0) { - // analyse cycle data - if (byte == SYN && m_sstr.size() > 0) { + analyseCycData(); - analyseCycData(); + if (m_sstr.size() == 1 && m_lockCounter == 0 && m_priorRetry == false) + m_lockCounter++; - if (m_sstr.size() == 1) { - if (m_priorRetry == true) - m_priorRetry = false; - else { - m_busLocked = true; - L.log(bus, trace, " bus locked"); - } + else if (m_lockCounter > 0) + m_lockCounter--; + + m_sstr.clear(); } - m_sstr.clear(); + else if (m_lockCounter > 0) + m_lockCounter--; + } + + // collect cycle data + else + m_sstr.push_back(byte, true, false); } } diff --git a/src/ebusd/ebusloop.h b/src/ebusd/ebusloop.h index 599afc69..1605451e 100644 --- a/src/ebusd/ebusloop.h +++ b/src/ebusd/ebusloop.h @@ -61,7 +61,7 @@ private: bool m_stop; - bool m_busLocked; + int m_lockCounter; bool m_priorRetry; WQueue m_sendBuffer; diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 7fef5379..459c5579 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -55,6 +55,10 @@ void define_args() "number retries to lock ebus (2)", Appl::type_int, Appl::opt_mandatory); + A.addItem("p_lockcounter", Appl::Param(5), "", "lockcounter", + "number of SYN to unlock send function (5)", + Appl::type_int, Appl::opt_mandatory); + A.addItem("p_recvtimeout", Appl::Param(15000), "", "recvtimeout", "receive timeout in 'us' (15000)\n", Appl::type_long, Appl::opt_mandatory); diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index 1951ed8a..c815182b 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -60,7 +60,7 @@ bool Device::isValid() ssize_t Device::sendBytes(const unsigned char* buffer, size_t nbytes) { if (isValid() == false) - return -1; + return -1; // TODO RESULT_ERR_DEVICE // write bytes to device return write(m_fd, buffer, nbytes); From 14d632683b684467a193bfdea92ecf1faa9aafab Mon Sep 17 00:00:00 2001 From: Roland Jax Date: Sat, 8 Nov 2014 12:15:31 +0100 Subject: [PATCH 15/15] Commands::getEbusCommand expanded for cycle messages to check 'QQ' byte too. --- src/ebusd/baseloop.cpp | 4 ++-- src/ebusd/ebusloop.cpp | 2 +- src/lib/ebus/commands.cpp | 19 ++++++++++++------- src/lib/ebus/commands.h | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index c23607fd..bf97f169 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -149,7 +149,7 @@ std::string BaseLoop::decodeMessage(const std::string& data) } std::string ebusCommand(A.getParam("p_address")); - ebusCommand += m_commands->getEbusCommand(index); + ebusCommand += m_commands->getEbusCommand(index, false); std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); BusCommand* busCommand = new BusCommand(ebusCommand, false); @@ -190,7 +190,7 @@ std::string BaseLoop::decodeMessage(const std::string& data) if (index >= 0) { std::string ebusCommand(A.getParam("p_address")); - ebusCommand += m_commands->getEbusCommand(index); + ebusCommand += m_commands->getEbusCommand(index, false); // encode data Command* command = new Command(index, (*m_commands)[index], cmd[3]); diff --git a/src/ebusd/ebusloop.cpp b/src/ebusd/ebusloop.cpp index a2881117..79f0d778 100644 --- a/src/ebusd/ebusloop.cpp +++ b/src/ebusd/ebusloop.cpp @@ -267,7 +267,7 @@ void EBusLoop::addPollCommand() L.log(bus, event, " polling [%4d] %s", index, tmp.c_str()); std::string ebusCommand(A.getParam("p_address")); - ebusCommand += m_commands->getEbusCommand(index); + ebusCommand += m_commands->getEbusCommand(index, false); std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); BusCommand* busCommand = new BusCommand(ebusCommand, true); diff --git a/src/lib/ebus/commands.cpp b/src/lib/ebus/commands.cpp index 97146ce2..cee9ad91 100644 --- a/src/lib/ebus/commands.cpp +++ b/src/lib/ebus/commands.cpp @@ -127,15 +127,20 @@ int Commands::findCommand(const std::string& data) const return -1; } -std::string Commands::getEbusCommand(const int index) const +std::string Commands::getEbusCommand(const int index, const bool cycle) const { cmd_t command = m_cmdDB.at(index); - std::string cmd(command[5]); - cmd += command[6]; + std::string cmd; std::stringstream sstr; + + if (cycle == true) + cmd += command[4]; // QQ + + cmd += command[5]; // ZZ + cmd += command[6]; // PBSB sstr << std::setw(2) << std::hex << std::setfill('0') << command[7]; - cmd += sstr.str(); - cmd += command[8]; + cmd += sstr.str(); // NN + cmd += command[8]; // Dx return cmd; } @@ -158,7 +163,7 @@ int Commands::storeCycData(const std::string& data) const // walk through commands for (; iter != m_cycDB.end(); iter++) { - std::string command = getEbusCommand(iter->first); + std::string command = getEbusCommand(iter->first, true); // skip wrong search string length if (command.length() > search.length()) @@ -211,7 +216,7 @@ void Commands::storePolData(const std::string& data) const // walk through commands for (; iter != m_polDB.end(); iter++) { - std::string command = getEbusCommand(iter->first); + std::string command = getEbusCommand(iter->first, false); // skip wrong search string length if (command.length() > search.length()) diff --git a/src/lib/ebus/commands.h b/src/lib/ebus/commands.h index 121587a0..09c96a89 100644 --- a/src/lib/ebus/commands.h +++ b/src/lib/ebus/commands.h @@ -56,7 +56,7 @@ public: std::string getCmdType(const int index) const { return std::string(m_cmdDB.at(index)[0]); } std::string getEbusType(const int index) const { return std::string(m_cmdDB.at(index)[4]); } - std::string getEbusCommand(const int index) const; + std::string getEbusCommand(const int index, const bool cycle) const; int storeCycData(const std::string& data) const; std::string getCycData(int index) const;