libebus project merged into ebusd project.

This commit is contained in:
Roland Jax
2014-10-27 22:28:22 +01:00
parent 809f674ea7
commit 0827c62f3f
60 changed files with 4872 additions and 49 deletions
+19
View File
@@ -0,0 +1,19 @@
AM_CXXFLAGS = -fpic \
-Wall \
-Wextra
noinst_LIBRARIES = libebus.a
libebus_a_SOURCES = result.cpp \
symbol.cpp \
port.cpp \
bus.cpp \
command.cpp \
commands.cpp \
configfile.cpp \
dump.cpp \
decode.cpp \
encode.cpp
distclean-local:
-rm -f Makefile.in
+473
View File
@@ -0,0 +1,473 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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 "bus.h"
#include <iostream>
#include <iomanip>
namespace libebus
{
BusCommand::BusCommand(const std::string commandStr, const bool isPoll)
: m_isPoll(isPoll), m_command(commandStr), m_resultCode(RESULT_OK)
{
unsigned char dstAddress = m_command[1];
if (dstAddress == BROADCAST)
m_type = broadcast;
else if (isMaster(dstAddress) == true)
m_type = masterMaster;
else
m_type = masterSlave;
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}
BusCommand::~BusCommand()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
const char* BusCommand::getResultCodeCStr()
{
return libebus::getResultCodeCStr(m_resultCode);
}
const std::string BusCommand::getMessageStr()
{
std::string result;
if (m_resultCode >= 0) {
if (m_type == masterSlave) {
result = m_command.getDataStr(true);
result += "00";
result += m_result.getDataStr();
result += "00";
} else {
result = "success";
}
}
else
result = "error";
return result;
}
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_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<unsigned>(byte);
if (byte == SYN)
std::cout << std::endl;
}
}
int Bus::proceed()
{
unsigned char byte_recv;
ssize_t bytes_recv;
// 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
bytes_recv = m_port->recv(0);
if (bytes_recv < 0)
return RESULT_ERR_DEVICE;
for (int i = 0; i < bytes_recv; i++) {
// fetch next byte
byte_recv = recvByte();
// store byte
return proceedCycData(byte_recv); // 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_unescape(byte, m_previousEscape, 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)
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 = SymbolString();
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;
ssize_t bytes_recv;
bool previousEscape = false;
// 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) {
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;
}
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)
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)
return RESULT_ERR_CRC;
return RESULT_OK;
}
} //namespace
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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/.
*/
#ifndef LIBEBUS_BUS_H_
#define LIBEBUS_BUS_H_
#include "symbol.h"
#include "result.h"
#include "port.h"
#include "dump.h"
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <queue>
namespace libebus
{
// the maximum time allowed for retrieving a byte from an addressed slave
#define RECV_TIMEOUT 10000
enum CommandType { invalid, broadcast, masterMaster, masterSlave };
class BusCommand
{
public:
BusCommand(const std::string commandStr, 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; }
const std::string getMessageStr();
void waitSignal() { pthread_cond_wait(&m_cond, &m_mutex); } // TODO timeout
void sendSignal() { pthread_cond_signal(&m_cond); }
private:
CommandType m_type;
bool m_isPoll;
SymbolString m_command;
SymbolString m_result;
int m_resultCode;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
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;
bool m_previousEscape;
SymbolString m_sstr;
std::queue<SymbolString> m_cycBuffer;
std::queue<BusCommand*> 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_
+345
View File
@@ -0,0 +1,345 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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 "command.h"
#include "decode.h"
#include "encode.h"
#include <iostream>
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstring>
namespace libebus
{
std::string Command::calcData()
{
// encode - only first entry will be encoded
// ToDo: if more parts are needed, they will be implemented
encode(m_data, m_command[13], m_command[14]);
if (m_error.length() > 0)
m_result = m_error;
return m_result;
}
std::string Command::calcResult(const cmd_t& cmd)
{
int elements = strtol(m_command[9].c_str(), NULL, 10);
if (cmd.size() > 3) {
bool found = false;
for (size_t i = 3; i < cmd.size(); i++) {
int j;
for (j = 0; j < elements; j++) {
if (m_command[10 + j*8] == cmd[i]) {
found = true;
break;
}
}
if (found == true) {
found = false;
// decode
calcSub(m_command[11 + j*8], m_command[12 + j*8],
m_command[13 + j*8], m_command[14 + j*8]);
}
}
} else {
for (int j = 0; j < elements; j++) {
// decode
calcSub(m_command[11 + j*8], m_command[12 + j*8],
m_command[13 + j*8], m_command[14 + j*8]);
}
}
if (m_error.length() > 0)
m_result = m_error;
return m_result;
}
void Command::calcSub(const std::string& part, const std::string& position,
const std::string& type, const std::string& factor)
{
std::string data;
// Master Data
if (strcasecmp(part.c_str(), "MD") == 0) {
// QQ ZZ PB SB NN
int md_pos = 10;
int md_len = strtol(m_command[7].c_str(), NULL, 10)*2;
data = m_data.substr(md_pos, md_len);
}
// Slave Acknowledge
else if (strcasecmp(part.c_str(), "SA") == 0) {
// QQ ZZ PB SB NN + Dx + CRC
int sa_pos = 10 + (strtol(m_command[7].c_str(), NULL, 10)*2) + 2;
int sa_len = 2;
data = m_data.substr(sa_pos, sa_len);
}
// Slave Data
else if (strcasecmp(part.c_str(), "SD") == 0) {
// QQ ZZ PB SB NN + Dx + CRC ACK NN
int sd_pos = 10 + (strtol(m_command[7].c_str(), NULL, 10)*2) + 6;
int sd_len = m_data.length() - (10 + (strtol(m_command[7].c_str(), NULL, 10)*2) + 6) - 4;
data = m_data.substr(sd_pos, sd_len);
}
// Master Acknowledge
else if (strcasecmp(part.c_str(), "MA") == 0) {
// QQ ZZ PB SB NN + Dx + CRC ACK NN + Dx
int ma_pos = m_data.length() - 2;
int ma_len = 2;
data = m_data.substr(ma_pos, ma_len);
}
decode(data, position, type, factor);
}
void Command::decode(const std::string& data, const std::string& position,
const std::string& type, const std::string& factor)
{
std::ostringstream result, value;
Decode* help = NULL;
// prepare position
std::string token;
std::istringstream stream(position);
std::vector<int> pos;
while (std::getline(stream, token, ',') != 0)
pos.push_back(strtol(token.c_str(), NULL, 10));
if (strcasecmp(type.c_str(), "HEX") == 0) {
if (pos.size() <= 1 || pos[1] < pos[0])
pos[1] = pos[0];
value << data.substr((pos[0]-1)*2, (pos[1]-pos[0]+1)*2);
help = new DecodeHEX(value.str());
}
else if (strcasecmp(type.c_str(), "UCH") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeUCH(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "SCH") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeSCH(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "UIN") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2);
help = new DecodeUIN(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "SIN") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2);
help = new DecodeSIN(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "ULG") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2)
<< data.substr((pos[2]-1)*2, 2) << data.substr((pos[3]-1)*2, 2);
help = new DecodeULG(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "SLG") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2)
<< data.substr((pos[2]-1)*2, 2) << data.substr((pos[3]-1)*2, 2);
help = new DecodeSLG(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "FLT") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2);
help = new DecodeFLT(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "STR") == 0) {
if (pos.size() <= 1 || pos[1] < pos[0])
pos[1] = pos[0];
value << data.substr((pos[0]-1)*2, (pos[1]-pos[0]+1)*2);
help = new DecodeSTR(value.str());
}
else if (strcasecmp(type.c_str(), "BCD") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeBCD(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "D1B") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeD1B(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "D1C") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeD1C(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "D2B") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2);
help = new DecodeD2B(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "D2C") == 0) {
value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2);
help = new DecodeD2C(value.str(), factor);
}
else if (strcasecmp(type.c_str(), "BDA") == 0) {
value << data.substr((pos[0]-1)*2, 2)
<< data.substr((pos[1]-1)*2, 2)
<< data.substr((pos[2]-1)*2, 2);
help = new DecodeBDA(value.str());
}
else if (strcasecmp(type.c_str(), "HDA") == 0) {
value << data.substr((pos[0]-1)*2, 2)
<< data.substr((pos[1]-1)*2, 2)
<< data.substr((pos[2]-1)*2, 2);
help = new DecodeHDA(value.str());
}
else if (strcasecmp(type.c_str(), "BTI") == 0) {
value << data.substr((pos[0]-1)*2, 2)
<< data.substr((pos[1]-1)*2, 2)
<< data.substr((pos[2]-1)*2, 2);
help = new DecodeBTI(value.str());
}
else if (strcasecmp(type.c_str(), "HTI") == 0) {
value << data.substr((pos[0]-1)*2, 2)
<< data.substr((pos[1]-1)*2, 2)
<< data.substr((pos[2]-1)*2, 2);
help = new DecodeHTI(value.str());
}
else if (strcasecmp(type.c_str(), "BDY") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeBDY(value.str());
}
else if (strcasecmp(type.c_str(), "HDY") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeHDY(value.str());
}
else if (strcasecmp(type.c_str(), "TTM") == 0) {
value << data.substr((pos[0]-1)*2, 2);
help = new DecodeTTM(value.str());
}
if (help == NULL) {
result << "type '" << type.c_str() << "' not implemented!";
m_error = result.str();
} else {
result << help->decode();
if (m_result.length() > 0)
m_result += " ";
m_result += result.str();
}
delete help;
}
void Command::encode(const std::string& data, const std::string& type,
const std::string& factor)
{
std::ostringstream result;
Encode* help = NULL;
if (strcasecmp(type.c_str(), "HEX") == 0) {
help = new EncodeHEX(data);
}
else if (strcasecmp(type.c_str(), "UCH") == 0) {
help = new EncodeUCH(data, factor);
}
else if (strcasecmp(type.c_str(), "SCH") == 0) {
help = new EncodeSCH(data, factor);
}
else if (strcasecmp(type.c_str(), "UIN") == 0) {
help = new EncodeUIN(data, factor);
}
else if (strcasecmp(type.c_str(), "SIN") == 0) {
help = new EncodeSIN(data, factor);
}
else if (strcasecmp(type.c_str(), "ULG") == 0) {
help = new EncodeULG(data, factor);
}
else if (strcasecmp(type.c_str(), "SLG") == 0) {
help = new EncodeSLG(data, factor);
}
else if (strcasecmp(type.c_str(), "FLT") == 0) {
help = new EncodeSLG(data, factor);
}
else if (strcasecmp(type.c_str(), "STR") == 0) {
help = new EncodeSTR(data);
}
else if (strcasecmp(type.c_str(), "BCD") == 0) {
help = new EncodeBCD(data, factor);
}
else if (strcasecmp(type.c_str(), "D1B") == 0) {
help = new EncodeD1B(data, factor);
}
else if (strcasecmp(type.c_str(), "D1C") == 0) {
help = new EncodeD1C(data, factor);
}
else if (strcasecmp(type.c_str(), "D2B") == 0) {
help = new EncodeD2B(data, factor);
}
else if (strcasecmp(type.c_str(), "D2C") == 0) {
help = new EncodeD2C(data, factor);
}
else if (strcasecmp(type.c_str(), "BDA") == 0) {
help = new EncodeBDA(data);
}
else if (strcasecmp(type.c_str(), "HDA") == 0) {
help = new EncodeHDA(data);
}
else if (strcasecmp(type.c_str(), "BTI") == 0) {
help = new EncodeBTI(data);
}
else if (strcasecmp(type.c_str(), "HTI") == 0) {
help = new EncodeHTI(data);
}
else if (strcasecmp(type.c_str(), "BDY") == 0) {
help = new EncodeBDY(data);
}
else if (strcasecmp(type.c_str(), "HDY") == 0) {
help = new EncodeHDY(data);
}
else if (strcasecmp(type.c_str(), "TTM") == 0) {
help = new EncodeTTM(data);
}
if (help == NULL) {
result << "type '" << type.c_str() << "' not implemented!";
m_error = result.str();
} else {
result << help->encode();
if (m_result.length() > 0)
m_result += " ";
m_result += result.str();
}
delete help;
}
} //namespace
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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/.
*/
#ifndef LIBEBUS_COMMAND_H_
#define LIBEBUS_COMMAND_H_
#include <string>
#include <vector>
namespace libebus
{
typedef std::vector<std::string> cmd_t;
typedef cmd_t::const_iterator cmdCI_t;
class Command
{
public:
Command(int index, cmd_t command) : m_index(index), m_command(command) {}
Command(int index, cmd_t command, std::string data)
: m_index(index), m_command(command), m_data(data) {}
cmd_t getCommand() const { return m_command; }
void setData(const std::string& data) { m_data = data; }
std::string getData() const { return m_data; }
std::string calcData();
std::string calcResult(const cmd_t& cmd);
private:
int m_index;
cmd_t m_command;
std::string m_data;
std::string m_result;
std::string m_error;
void calcSub(const std::string& part, const std::string& position,
const std::string& type, const std::string& factor);
void decode(const std::string& data, const std::string& position,
const std::string& type, const std::string& factor);
void encode(const std::string& data, const std::string& type,
const std::string& factor);
};
} //namespace
#endif // LIBEBUS_COMMAND_H_
+246
View File
@@ -0,0 +1,246 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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 "commands.h"
#include <iostream>
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstring>
namespace libebus
{
Commands::~Commands()
{
for (mapCI_t iter = m_polDB.begin(); iter != m_polDB.end(); ++iter)
delete iter->second;
m_polDB.clear();
for (mapCI_t iter = m_cycDB.begin(); iter != m_cycDB.end(); ++iter)
delete iter->second;
m_cycDB.clear();
m_cmdDB.clear();
}
void Commands::addCommand(const cmd_t& command)
{
m_cmdDB.push_back(command);
if (strcasecmp(command[0].c_str(),"C") == 0) {
Command* cmd = new Command(m_cmdDB.size()-1, command);
m_cycDB.insert(pair_t(m_cmdDB.size()-1, cmd));
}
if (strcasecmp(command[0].c_str(),"P") == 0) {
Command* cmd = new Command(m_cmdDB.size()-1, command);
m_polDB.insert(pair_t(m_cmdDB.size()-1, cmd));
}
}
void Commands::printCommands() const
{
if (m_cmdDB.size() == 0)
return;
for (cmdDBCI_t i = m_cmdDB.begin(); i != m_cmdDB.end(); i++) {
printCommand(*i);
std::cout << std::endl;
}
}
int Commands::findCommand(const std::string& data) const
{
// no commands definend
if (m_cmdDB.size() == 0)
return -2;
// preapre string for searching command
std::string token;
std::istringstream isstr(data);
std::vector<std::string> cmd;
// split stream
while (std::getline(isstr, token, ' ') != 0)
cmd.push_back(token);
std::size_t index;
cmdDBCI_t i = m_cmdDB.begin();
// walk through commands - GET
if (strcasecmp(cmd[0].c_str(), "GET") == 0) {
for (index = 0; i != m_cmdDB.end(); i++, index++) {
// empty line
if ((*i).size() == 0)
continue;
if (((strcasecmp((*i)[0].c_str(), "R") == 0)
|| (strcasecmp((*i)[0].c_str(), "P") == 0))
&& (strcasecmp((*i)[1].c_str(), cmd[1].c_str()) == 0)
&& (strcasecmp((*i)[2].c_str(), cmd[2].c_str()) == 0))
return index;
}
// walk through commands - SET, CYC
} else {
// correct type
if (strcasecmp(cmd[0].c_str(), "SET") == 0)
cmd[0] = "W";
else if (strcasecmp(cmd[0].c_str(), "CYC") == 0)
cmd[0] = "C";
for (index = 0; i != m_cmdDB.end(); i++, index++) {
// empty line
if ((*i).size() == 0)
continue;
if (strcasecmp((*i)[0].c_str(), cmd[0].c_str()) == 0 &&
strcasecmp((*i)[1].c_str(), cmd[1].c_str()) == 0 &&
strcasecmp((*i)[2].c_str(), cmd[2].c_str()) == 0)
return index;
}
}
// command not found
return -1;
}
std::string Commands::getEbusCommand(const int index) const
{
cmd_t command = m_cmdDB.at(index);
std::string cmd(command[5]);
cmd += command[6];
std::stringstream sstr;
sstr << std::setw(2) << std::hex << std::setfill('0') << command[7];
cmd += sstr.str();
cmd += command[8];
return cmd;
}
int Commands::storeCycData(const std::string& data) const
{
// no commands defined
if (m_cycDB.size() == 0)
return -2;
// search skipped - string too short
if (data.length() < 10)
return -3;
// prepare string for searching command
std::string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2));
mapCI_t iter = m_cycDB.begin();
// walk through commands
for (; iter != m_cycDB.end(); iter++) {
std::string command = getEbusCommand(iter->first);
// skip wrong search string length
if (command.length() > search.length())
continue;
if (strcasecmp(command.c_str(), search.substr(0,command.length()).c_str()) == 0) {
iter->second->setData(data);
return iter->first;
}
}
// command not found
return -1;
}
std::string Commands::getCycData(int index) const
{
mapCI_t iter = m_cycDB.find(index);
if (iter != m_cycDB.end())
return iter->second->getData();
else
return "";
}
int Commands::nextPolCommand()
{
size_t index = 0;
m_polIndex++;
if (m_polIndex == m_polDB.size())
m_polIndex = 0;
mapCI_t iter = m_polDB.begin();
for (; iter != m_polDB.end(); iter++, index++)
if (index == m_polIndex)
return iter->first;
return -1;
}
void Commands::storePolData(const std::string& data) const
{
// prepare string for searching command
std::string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2));
mapCI_t iter = m_polDB.begin();
// walk through commands
for (; iter != m_polDB.end(); iter++) {
std::string command = getEbusCommand(iter->first);
// skip wrong search string length
if (command.length() > search.length())
continue;
if (strcasecmp(command.c_str(), search.substr(0,command.length()).c_str()) == 0)
iter->second->setData(data);
}
}
std::string Commands::getPolData(int index) const
{
mapCI_t iter = m_polDB.find(index);
if (iter != m_polDB.end())
return iter->second->getData();
else
return "";
}
void Commands::printCommand(const cmd_t& command) const
{
if (command.size() == 0)
return;
for (cmdCI_t i = command.begin(); i != command.end(); i++)
std::cout << *i << ';';
}
} //namespace
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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/.
*/
#ifndef LIBEBUS_COMMANDS_H_
#define LIBEBUS_COMMANDS_H_
#include "command.h"
#include <string>
#include <vector>
#include <map>
namespace libebus
{
typedef std::vector<cmd_t> cmdDB_t;
typedef cmdDB_t::const_iterator cmdDBCI_t;
typedef std::map<int, Command*> map_t;
typedef map_t::const_iterator mapCI_t;
typedef std::pair<int, Command*> pair_t;
class Commands
{
public:
Commands() : m_polIndex(-1) {}
~Commands();
void addCommand(const cmd_t& command);
void printCommands() const;
std::size_t sizeCmdDB() const { return m_cmdDB.size(); }
std::size_t sizeCycDB() const { return m_cycDB.size(); }
std::size_t sizePolDB() const { return m_polDB.size(); }
cmd_t const& operator[](const std::size_t& index) const { return m_cmdDB[index]; }
int findCommand(const std::string& data) const;
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;
int storeCycData(const std::string& data) const;
std::string getCycData(int index) const;
int nextPolCommand();
void storePolData(const std::string& data) const;
std::string getPolData(int index) const;
private:
cmdDB_t m_cmdDB;
map_t m_cycDB;
map_t m_polDB;
size_t m_polIndex;
void printCommand(const cmd_t& command) const;
};
} //namespace
#endif // LIBEBUS_COMMANDS_H_
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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 "configfile.h"
#include <sstream>
#include <fstream>
#include <dirent.h>
namespace libebus
{
void ConfigFileCSV::readFile(std::istream& is, Commands& commands)
{
std::string line;
// read lines
while (std::getline(is, line) != 0) {
cmd_t row;
std::string column;
std::istringstream isstr(line);
// walk through columns
while (std::getline(isstr, column, ';') != 0)
row.push_back(column);
// skip empty and commented rows
if (row.empty() == true || row[0][0] == '#')
continue;
commands.addCommand(row);
}
};
void ConfigFileXML::readFile(std::istream& is, Commands& commands)
{
; // ToDo: Implamantion for xml files
}
ConfigCommands::ConfigCommands(const std::string path, const FileType type)
{
m_path = path;
m_configfile = NULL;
setType(type);
addFiles(m_path, m_extension);
}
void ConfigCommands::setType(const FileType type)
{
if (m_configfile != NULL)
delete m_configfile;
switch (type) {
case CSV:
m_configfile = new ConfigFileCSV();
m_extension = "csv";
break;
case XML:
m_configfile = new ConfigFileXML();
m_extension = "xml";
break;
};
};
Commands* ConfigCommands::getCommands()
{
Commands* commands = new Commands();
std::vector<std::string>::const_iterator i = m_files.begin();
for(; i != m_files.end(); i++) {
std::fstream file((*i).c_str(), std::ios::in);
if(file.is_open() == true) {
m_configfile->readFile(file, *commands);
file.close();
}
}
return commands;
};
void ConfigCommands::addFiles(const std::string path, const std::string extension)
{
DIR* dir = opendir(path.c_str());
if (dir == NULL)
return;
dirent* d = readdir(dir);
while (d != NULL) {
if (d->d_type == DT_DIR) {
std::string fn = d->d_name;
if (fn != "." && fn != "..") {
const std::string p = path + "/" + d->d_name;
addFiles(p, extension);
}
} else if (d->d_type == DT_REG) {
std::string fn = d->d_name;
if (fn.find(extension, (fn.length() - extension.length())) != std::string::npos) {
const std::string p = path + "/" + d->d_name;
m_files.push_back(p);
}
}
d = readdir(dir);
}
closedir(dir);
};
} //namespace
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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/.
*/
#ifndef LIBEBUS_CONFIGFILE_H_
#define LIBEBUS_CONFIGFILE_H_
#include "commands.h"
#include <string>
#include <vector>
namespace libebus
{
enum FileType { CSV, XML };
class ConfigFile
{
public:
virtual ~ConfigFile() {}
virtual void readFile(std::istream& is, Commands& commands) = 0;
};
class ConfigFileCSV : public ConfigFile
{
public:
~ConfigFileCSV() {}
void readFile(std::istream& is, Commands& commands);
};
class ConfigFileXML : public ConfigFile
{
public:
~ConfigFileXML() {}
void readFile(std::istream& is, Commands& commands);
};
class ConfigCommands
{
public:
ConfigCommands(const std::string path, const FileType type);
~ConfigCommands() { delete m_configfile; }
void setType(const FileType type);
Commands* getCommands();
private:
ConfigFile* m_configfile;
std::string m_path;
std::string m_extension;
std::vector<std::string> m_files;
void addFiles(const std::string path, const std::string extension);
};
} //namespace
#endif // LIBEBUS_CONFIGFILE_H_
+353
View File
@@ -0,0 +1,353 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
* crc calculations from http://www.mikrocontroller.net/topic/75698
*
* 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 "decode.h"
#include <cstdlib>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
namespace libebus
{
Decode::Decode(const std::string& data, const std::string& factor)
: m_data(data)
{
if ((factor.find_first_not_of("0123456789.") == std::string::npos) == true)
m_factor = static_cast<float>(strtod(factor.c_str(), NULL));
else
m_factor = 1.0;
}
std::string DecodeHEX::decode()
{
std::ostringstream result;
for (size_t i = 0; i < m_data.length()/2; i++)
result << m_data.substr(i*2, 2) << " ";
return result.str().substr(0, result.str().length()-1);
}
std::string DecodeUCH::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
unsigned short x;
ss >> x;
std::ostringstream result;
result << std::setprecision(3) << std::fixed << static_cast<float>(x * m_factor);
return result.str();
}
std::string DecodeSCH::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
unsigned short x;
ss >> x;
std::ostringstream result;
if ((x & 0x80) == 0x80)
result << std::setprecision(3) << std::fixed
<< static_cast<float>(static_cast<short>(- ( ((unsigned char) (~ x)) + 1) ) * m_factor);
else
result << std::setprecision(3) << std::fixed
<< static_cast<float>(static_cast<short>(x) * m_factor);
return result.str();
}
std::string DecodeUIN::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
unsigned short x;
ss >> x;
std::ostringstream result;
result << std::setprecision(3) << std::fixed << static_cast<float>(x * m_factor);
return result.str();
}
std::string DecodeSIN::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
unsigned short x;
ss >> x;
std::ostringstream result;
result << std::setprecision(3) << std::fixed << static_cast<float>(static_cast<short>(x) * m_factor);
return result.str();
}
std::string DecodeULG::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
unsigned int x;
ss >> x;
std::ostringstream result;
result << std::setprecision(3) << std::fixed << static_cast<float>(x * m_factor);
return result.str();
}
std::string DecodeSLG::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
unsigned int x;
ss >> x;
std::ostringstream result;
result << std::setprecision(3) << std::fixed <<static_cast<float>(static_cast<int>(x) * m_factor);
return result.str();
}
std::string DecodeFLT::decode()
{
std::stringstream ss;
ss << std::hex << m_data;
short x;
ss >> x;
std::ostringstream result;
result << std::setprecision(3) << std::fixed << static_cast<float>(x / 1000.0 * m_factor);
return result.str();
}
std::string DecodeSTR::decode()
{
std::ostringstream result;
for (size_t i = 0; i <= m_data.length()/2; i++) {
char tmp = static_cast<char>(strtol(m_data.substr(i*2, 2).c_str(), NULL, 16));
if (tmp == 0x00) tmp = 0x20;
result << tmp;
}
return result.str().substr(0, result.str().length()-1);
}
std::string DecodeBCD::decode()
{
std::ostringstream result;
unsigned char src = strtol(m_data.c_str(), NULL, 16);
if ((src & 0x0F) > 0x09 || ((src >> 4) & 0x0F) > 0x09)
result << static_cast<short>(0xFF);
else
result << static_cast<short>(( ( ((src & 0xF0) >> 4) * 10) + (src & 0x0F) ) * m_factor);
return result.str();
}
std::string DecodeD1B::decode()
{
std::ostringstream result;
unsigned char src = strtol(m_data.c_str(), NULL, 16);
if ((src & 0x80) == 0x80)
result << static_cast<short>((- ( ((unsigned char) (~ src)) + 1) ) * m_factor);
else
result << static_cast<short>(src * m_factor);
return result.str();
}
std::string DecodeD1C::decode()
{
std::ostringstream result;
unsigned char src = strtol(m_data.c_str(), NULL, 16);
if (src > 0xC8)
result << static_cast<float>(0xFF);
else
result << static_cast<float>((src / 2.0) * m_factor);
return result.str();
}
std::string DecodeD2B::decode()
{
std::ostringstream result;
unsigned char src_lsb = static_cast<char>(strtol(m_data.substr(0, 2).c_str(), NULL, 16));
unsigned char src_msb = static_cast<char>(strtol(m_data.substr(2, 2).c_str(), NULL, 16));
if ((src_msb & 0x80) == 0x80)
result << static_cast<float>
((- ( ((unsigned char) (~ src_msb)) +
( ( ((unsigned char) (~ src_lsb)) + 1) / 256.0) ) ) * m_factor);
else
result << static_cast<float>((src_msb + (src_lsb / 256.0)) * m_factor);
return result.str();
}
std::string DecodeD2C::decode()
{
std::ostringstream result;
unsigned char src_lsb = static_cast<char>(strtol(m_data.substr(0, 2).c_str(), NULL, 16));
unsigned char src_msb = static_cast<char>(strtol(m_data.substr(2, 2).c_str(), NULL, 16));
if ((src_msb & 0x80) == 0x80)
result << static_cast<float>
((- ( ( ( ((unsigned char) (~ src_msb)) * 16.0) ) +
( ( ((unsigned char) (~ src_lsb)) & 0xF0) >> 4) +
( ( ( ((unsigned char) (~ src_lsb)) & 0x0F) +1 ) / 16.0) ) ) * m_factor);
else
result << static_cast<float>(( (src_msb * 16.0) + ((src_lsb & 0xF0) >> 4) +
((src_lsb & 0x0F) / 16.0) ) * m_factor);
return result.str();
}
std::string DecodeBDA::decode()
{
std::ostringstream result;
Decode* decode;
short array[3];
for (int i = 0; i < 3; i++) {
decode = new DecodeBCD(m_data.substr(i*2, 2), "1.0");
array[i] = static_cast<short>(strtol(decode->decode().c_str(), NULL, 10));
delete decode;
}
result << std::setw(2) << std::setfill('0') << array[0] << "."
<< std::setw(2) << std::setfill('0') << array[1] << "."
<< array[2] + 2000;
return result.str();
}
std::string DecodeHDA::decode()
{
std::ostringstream result;
short dd = static_cast<short>(strtol(m_data.substr(0, 2).c_str(), NULL, 16));
short mm = static_cast<short>(strtol(m_data.substr(2, 2).c_str(), NULL, 16));
short yy = static_cast<short>(strtol(m_data.substr(4, 2).c_str(), NULL, 16));
result << std::setw(2) << std::setfill('0') << dd << "."
<< std::setw(2) << std::setfill('0') << mm << "."
<< yy + 2000;
return result.str();
}
std::string DecodeBTI::decode()
{
std::ostringstream result;
Decode* decode;
short array[3];
for (int i = 0; i < 3; i++) {
decode = new DecodeBCD(m_data.substr(i*2, 2), "1.0");
array[i] = static_cast<short>(strtol(decode->decode().c_str(), NULL, 10));
delete decode;
}
result << std::setw(2) << std::setfill('0') << array[0] << ":"
<< std::setw(2) << std::setfill('0') << array[1] << ":"
<< std::setw(2) << std::setfill('0') << array[2];
return result.str();
}
std::string DecodeHTI::decode()
{
std::ostringstream result;
short hh = static_cast<short>(strtol(m_data.substr(0, 2).c_str(), NULL, 16));
short mm = static_cast<short>(strtol(m_data.substr(2, 2).c_str(), NULL, 16));
short ss = static_cast<short>(strtol(m_data.substr(4, 2).c_str(), NULL, 16));
result << std::setw(2) << std::setfill('0') << hh << ":"
<< std::setw(2) << std::setfill('0') << mm << ":"
<< std::setw(2) << std::setfill('0') << ss;
return result.str();
}
std::string DecodeBDY::decode()
{
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"};
std::ostringstream result;
short day = static_cast<short>(strtol(m_data.c_str(), NULL, 16));
if (day < 0 || day > 6)
day = 7;
result << days[day];
return result.str();
}
std::string DecodeHDY::decode()
{
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"};
std::ostringstream result;
short day = static_cast<short>(strtol(m_data.c_str(), NULL, 16)) - 1;
if (day < 0 || day > 6)
day = 7;
result << days[day];
return result.str();
}
std::string DecodeTTM::decode()
{
std::ostringstream result;
short hh = static_cast<short>(strtol(m_data.c_str(), NULL, 16)) / 6;
short mm = static_cast<short>(strtol(m_data.c_str(), NULL, 16)) % 6 * 10;
result << std::setw(2) << std::setfill('0') << hh << ":"
<< std::setw(2) << std::setfill('0') << mm;
return result.str();
}
} //namespace
+292
View File
@@ -0,0 +1,292 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
* crc calculations from http://www.mikrocontroller.net/topic/75698
*
* 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/.
*/
#ifndef LIBEBUS_DECODE_H_
#define LIBEBUS_DECODE_H_
#include <string>
namespace libebus
{
class Decode
{
public:
Decode(const std::string& data, const std::string& factor = "");
virtual ~Decode() {}
virtual std::string decode() = 0;
protected:
std::string m_data;
float m_factor;
};
class DecodeHEX : public Decode
{
public:
DecodeHEX(const std::string& data) : Decode(data) {}
~DecodeHEX() {}
std::string decode();
};
class DecodeUCH : public Decode
{
public:
DecodeUCH(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeUCH() {}
std::string decode();
};
class DecodeSCH : public Decode
{
public:
DecodeSCH(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeSCH() {}
std::string decode();
};
class DecodeUIN : public Decode
{
public:
DecodeUIN(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeUIN() {}
std::string decode();
};
class DecodeSIN : public Decode
{
public:
DecodeSIN(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeSIN() {}
std::string decode();
};
class DecodeULG : public Decode
{
public:
DecodeULG(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeULG() {}
std::string decode();
};
class DecodeSLG : public Decode
{
public:
DecodeSLG(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeSLG() {}
std::string decode();
};
class DecodeFLT : public Decode
{
public:
DecodeFLT(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeFLT() {}
std::string decode();
};
class DecodeSTR : public Decode
{
public:
DecodeSTR(std::string data) : Decode(data) {}
~DecodeSTR() {}
std::string decode();
};
class DecodeBCD : public Decode
{
public:
DecodeBCD(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeBCD() {}
std::string decode();
};
class DecodeD1B : public Decode
{
public:
DecodeD1B(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeD1B() {}
std::string decode();
};
class DecodeD1C : public Decode
{
public:
DecodeD1C(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeD1C() {}
std::string decode();
};
class DecodeD2B : public Decode
{
public:
DecodeD2B(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeD2B() {}
std::string decode();
};
class DecodeD2C : public Decode
{
public:
DecodeD2C(const std::string& data, const std::string& factor)
: Decode(data, factor) {}
~DecodeD2C() {}
std::string decode();
};
class DecodeBDA : public Decode
{
public:
DecodeBDA(const std::string& data) : Decode(data) {}
~DecodeBDA() {}
std::string decode();
};
class DecodeHDA : public Decode
{
public:
DecodeHDA(const std::string& data) : Decode(data) {}
~DecodeHDA() {}
std::string decode();
};
class DecodeBTI : public Decode
{
public:
DecodeBTI(const std::string& data) : Decode(data) {}
~DecodeBTI() {}
std::string decode();
};
class DecodeHTI : public Decode
{
public:
DecodeHTI(const std::string& data) : Decode(data) {}
~DecodeHTI() {}
std::string decode();
};
class DecodeBDY : public Decode
{
public:
DecodeBDY(const std::string& data) : Decode(data) {}
~DecodeBDY() {}
std::string decode();
};
class DecodeHDY : public Decode
{
public:
DecodeHDY(const std::string& data) : Decode(data) {}
~DecodeHDY() {}
std::string decode();
};
class DecodeTTM : public Decode
{
public:
DecodeTTM(const std::string& data) : Decode(data) {}
~DecodeTTM() {}
std::string decode();
};
} //namespace
#endif // LIBEBUS_DECODE_H_
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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 "dump.h"
#include <fstream>
#include <cstdio>
namespace libebus
{
int Dump::write(const char* byte)
{
int ret = 0;
std::ofstream fs(m_filename.c_str(), std::ios::out | std::ios::binary | std::ios::app);
if (fs == 0)
return -1;
fs.write(byte, 1);
if (fs.tellp() >= m_filesize * 1024) {
std::string oldfile;
oldfile += m_filename;
oldfile += ".old";
ret = rename(m_filename.c_str(), oldfile.c_str());
}
fs.close();
return ret;
}
} //namespace
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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/.
*/
#ifndef LIBEBUS_DUMP_H_
#define LIBEBUS_DUMP_H_
#include <string>
namespace libebus
{
class Dump
{
public:
Dump(std::string filename, long filesize)
: m_filename(filename), m_filesize(filesize) {}
int write(const char* byte);
void setFilename(const std::string& filename) { m_filename = filename; }
void setFilesize(const long filesize) { m_filesize = filesize; }
private:
std::string m_filename;
long m_filesize;
};
} //namespace
#endif // LIBEBUS_DUMP_H_
+370
View File
@@ -0,0 +1,370 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
* crc calculations from http://www.mikrocontroller.net/topic/75698
*
* 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 "encode.h"
#include <cstdlib>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
namespace libebus
{
Encode::Encode(const std::string& data, const std::string& factor)
: m_data(data)
{
if ((factor.find_first_not_of("0123456789.") == std::string::npos) == true)
m_factor = static_cast<float>(strtod(factor.c_str(), NULL));
else
m_factor = 1.0;
}
std::string EncodeHEX::encode()
{
m_data.erase(std::remove_if(m_data.begin(), m_data.end(), isspace), m_data.end());
return m_data;
}
std::string EncodeUCH::encode()
{
std::ostringstream result;
unsigned short src = static_cast<unsigned short>(strtod(m_data.c_str(), NULL) / m_factor);
result << std::setw(2) << std::hex << std::setfill('0') << src;
return result.str().substr(result.str().length()-2,2);
}
std::string EncodeSCH::encode()
{
std::ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -127 || src > 127)
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0x80);
else
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(src);
return result.str().substr(result.str().length()-2,2);
}
std::string EncodeUIN::encode()
{
std::ostringstream result;
unsigned short src = static_cast<unsigned short>(strtod(m_data.c_str(), NULL) / m_factor);
result << std::setw(4) << std::hex << std::setfill('0') << src;
return result.str().substr(2,2) + result.str().substr(0,2);
}
std::string EncodeSIN::encode()
{
std::ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
result << std::setw(4) << std::hex << std::setfill('0') << src;
return result.str().substr(2,2) + result.str().substr(0,2);
}
std::string EncodeULG::encode()
{
std::ostringstream result;
unsigned long src = static_cast<unsigned long>(strtod(m_data.c_str(), NULL) / m_factor);
result << std::setw(8) << std::hex << std::setfill('0') << src;
return result.str().substr(6,2) + result.str().substr(4,2) +
result.str().substr(2,2) + result.str().substr(0,2);
}
std::string EncodeSLG::encode()
{
std::ostringstream result;
int src = static_cast<int>(strtod(m_data.c_str(), NULL) / m_factor);
result << std::setw(8) << std::hex << std::setfill('0') << src;
return result.str().substr(6,2) + result.str().substr(4,2) +
result.str().substr(2,2) + result.str().substr(0,2);
}
std::string EncodeFLT::encode()
{
std::ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) * 1000.0 / m_factor);
result << std::setw(4) << std::hex << std::setfill('0') << src;
return result.str().substr(2,2) + result.str().substr(0,2);
}
std::string EncodeSTR::encode()
{
std::ostringstream result;
for (size_t i = 0; i < m_data.length(); i++)
result << std::setw(2) << std::hex << std::setfill('0') << static_cast<short>(m_data[i]);
return result.str();
}
std::string EncodeBCD::encode()
{
std::ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
if (src > 99)
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0xFF);
else
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>( ((src / 10) << 4) | (src % 10) );
return result.str().substr(result.str().length()-2,2);
}
std::string EncodeD1B::encode()
{
std::ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -127 || src > 127)
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0x80);
else
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(src);
return result.str().substr(result.str().length()-2,2);
}
std::string EncodeD1C::encode()
{
std::ostringstream result;
float src = static_cast<float>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < 0.0 || src > 100.0)
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0xFF);
else
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(src * 2.0);
return result.str();
}
std::string EncodeD2B::encode()
{
std::ostringstream result;
float src = static_cast<float>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -127.999 || src > 127.999) {
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0x80)
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0x00);
} else {
unsigned char tgt_lsb = static_cast<unsigned>((src - ((short) src)) * 256.0);
unsigned char tgt_msb;
if (src < 0.0 && tgt_lsb != 0x00)
tgt_msb = static_cast<unsigned>((short) src - 1);
else
tgt_msb = static_cast<unsigned>((short) src);
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(tgt_msb)
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(tgt_lsb);
}
return result.str();
}
std::string EncodeD2C::encode()
{
std::ostringstream result;
float src = static_cast<float>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -2047.999 || src > 2047.999) {
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0x80)
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(0x00);
} else {
unsigned char tgt_lsb = static_cast<unsigned>(
((unsigned char) ( ((short) src) % 16) << 4) +
((unsigned char) ( (src - ((short) src)) * 16.0)) );
unsigned char tgt_msb;
if (src < 0.0 && tgt_lsb != 0x00)
tgt_msb = static_cast<unsigned>((short) (src / 16.0) - 1);
else
tgt_msb = static_cast<unsigned>((short) src / 16.0);
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(tgt_msb)
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<unsigned>(tgt_lsb);
}
return result.str();
}
std::string EncodeBDA::encode()
{
// prepare data
std::string token;
std::istringstream stream(m_data);
std::vector<std::string> data;
while (std::getline(stream, token, '.') != 0)
data.push_back(token);
std::ostringstream result;
result << std::setw(2) << std::dec << std::setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< std::setw(2) << std::dec << std::setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< std::setw(2) << std::dec << std::setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL) - 2000);
return result.str();
}
std::string EncodeHDA::encode()
{
// prepare data
std::string token;
std::istringstream stream(m_data);
std::vector<std::string> data;
while (std::getline(stream, token, '.') != 0)
data.push_back(token);
std::ostringstream result;
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL) - 2000);
return result.str();
}
std::string EncodeBTI::encode()
{
// prepare data
std::string token;
std::istringstream stream(m_data);
std::vector<std::string> data;
while (std::getline(stream, token, ':') != 0)
data.push_back(token);
std::ostringstream result;
result << std::setw(2) << std::dec << std::setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< std::setw(2) << std::dec << std::setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< std::setw(2) << std::dec << std::setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL));
return result.str();
}
std::string EncodeHTI::encode()
{
// prepare data
std::string token;
std::istringstream stream(m_data);
std::vector<std::string> data;
while (std::getline(stream, token, ':') != 0)
data.push_back(token);
std::ostringstream result;
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL));
return result.str();
}
std::string EncodeBDY::encode()
{
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"};
short day = 7;
for (short i = 0; i < 7; i++)
if (strcasecmp(days[i], m_data.c_str()) == 0)
day = i;
std::ostringstream result;
result << std::setw(2) << std::hex << std::setfill('0') << day;
return result.str();
}
std::string EncodeHDY::encode()
{
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"};
short day = 8;
for (short i = 0; i < 7; i++)
if (strcasecmp(days[i], m_data.c_str()) == 0)
day = i + 1;
std::ostringstream result;
result << std::setw(2) << std::hex << std::setfill('0') << day;
return result.str();
}
std::string EncodeTTM::encode()
{
// prepare data
std::string token;
std::istringstream stream(m_data);
std::vector<std::string> data;
while (std::getline(stream, token, ':') != 0)
data.push_back(token);
std::ostringstream result;
result << std::setw(2) << std::hex << std::setfill('0')
<< static_cast<short>( (strtod(data[0].c_str(), NULL) * 6)
+ (strtod(data[1].c_str(), NULL) / 10) );
return result.str();
}
} //namespace
+292
View File
@@ -0,0 +1,292 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
* crc calculations from http://www.mikrocontroller.net/topic/75698
*
* 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/.
*/
#ifndef LIBEBUS_ENCODE_H_
#define LIBEBUS_ENCODE_H_
#include <string>
namespace libebus
{
class Encode
{
public:
Encode(const std::string& data, const std::string& factor = "");
virtual ~Encode() {}
virtual std::string encode() = 0;
protected:
std::string m_data;
float m_factor;
};
class EncodeHEX : public Encode
{
public:
EncodeHEX(const std::string& data) : Encode(data) {}
~EncodeHEX() {}
std::string encode();
};
class EncodeUCH : public Encode
{
public:
EncodeUCH(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeUCH() {}
std::string encode();
};
class EncodeSCH : public Encode
{
public:
EncodeSCH(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeSCH() {}
std::string encode();
};
class EncodeUIN : public Encode
{
public:
EncodeUIN(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeUIN() {}
std::string encode();
};
class EncodeSIN : public Encode
{
public:
EncodeSIN(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeSIN() {}
std::string encode();
};
class EncodeULG : public Encode
{
public:
EncodeULG(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeULG() {}
std::string encode();
};
class EncodeSLG : public Encode
{
public:
EncodeSLG(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeSLG() {}
std::string encode();
};
class EncodeFLT : public Encode
{
public:
EncodeFLT(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeFLT() {}
std::string encode();
};
class EncodeSTR : public Encode
{
public:
EncodeSTR(const std::string& data) : Encode(data) {}
~EncodeSTR() {}
std::string encode();
};
class EncodeBCD : public Encode
{
public:
EncodeBCD(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeBCD() {}
std::string encode();
};
class EncodeD1B : public Encode
{
public:
EncodeD1B(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeD1B() {}
std::string encode();
};
class EncodeD1C : public Encode
{
public:
EncodeD1C(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeD1C() {}
std::string encode();
};
class EncodeD2B : public Encode
{
public:
EncodeD2B(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeD2B() {}
std::string encode();
};
class EncodeD2C : public Encode
{
public:
EncodeD2C(const std::string& data, const std::string& factor)
: Encode(data, factor) {}
~EncodeD2C() {}
std::string encode();
};
class EncodeBDA : public Encode
{
public:
EncodeBDA(const std::string& data) : Encode(data) {}
~EncodeBDA() {}
std::string encode();
};
class EncodeHDA : public Encode
{
public:
EncodeHDA(const std::string& data) : Encode(data) {}
~EncodeHDA() {}
std::string encode();
};
class EncodeBTI : public Encode
{
public:
EncodeBTI(const std::string& data) : Encode(data) {}
~EncodeBTI() {}
std::string encode();
};
class EncodeHTI : public Encode
{
public:
EncodeHTI(const std::string& data) : Encode(data) {}
~EncodeHTI() {}
std::string encode();
};
class EncodeBDY : public Encode
{
public:
EncodeBDY(const std::string& data) : Encode(data) {}
~EncodeBDY() {}
std::string encode();
};
class EncodeHDY : public Encode
{
public:
EncodeHDY(const std::string& data) : Encode(data) {}
~EncodeHDY() {}
std::string encode();
};
class EncodeTTM : public Encode
{
public:
EncodeTTM(const std::string& data) : Encode(data) {}
~EncodeTTM() {}
std::string encode();
};
} //namespace
#endif // LIBEBUS_ENCODE_H_
+264
View File
@@ -0,0 +1,264 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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 "port.h"
#include <cstdlib>
#include <cstring>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
namespace libebus
{
bool Device::isOpen()
{
if (isValid() == false)
m_open = false;
return m_open;
}
bool Device::isValid()
{
if (m_noDeviceCheck == false) {
int port;
if (ioctl(m_fd, TIOCMGET, &port) == -1) {
closeDevice();
m_open = false;
return false;
}
}
return true;
}
ssize_t Device::sendBytes(const unsigned char* buffer, size_t nbytes)
{
if (isValid() == false)
return -1;
// write bytes to device
return write(m_fd, buffer, nbytes);
}
ssize_t Device::recvBytes(const long timeout, size_t maxCount)
{
if (isValid() == false)
return -1; // TODO RESULT_ERR_DEVICE
if (timeout > 0) {
fd_set readfds;
struct timeval tdiff;
// set select timeout
tdiff.tv_sec = 0;
tdiff.tv_usec = timeout;
FD_ZERO(&readfds);
FD_SET(m_fd, &readfds);
if (select(m_fd + 1, &readfds, NULL, NULL, &tdiff) != 1)
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);
for (int i = 0; i < bytes_read; i++)
m_recvBuffer.push(m_buffer[i]);
return bytes_read;
}
unsigned char Device::getByte()
{
unsigned char byte;
if (m_recvBuffer.empty() == false) {
byte = m_recvBuffer.front();
m_recvBuffer.pop();
return byte;
}
return 0;
}
void DeviceSerial::openDevice(const std::string deviceName, const bool noDeviceCheck)
{
m_noDeviceCheck = noDeviceCheck;
termios newSettings;
m_open = false;
// open file descriptor from serial device
m_fd = open(deviceName.c_str(), O_RDWR | O_NOCTTY);
if (m_fd < 0)
return;
// save current settings of serial device
tcgetattr(m_fd, &m_oldSettings);
memset(&newSettings, '\0', sizeof(newSettings));
newSettings.c_cflag |= (B2400 | CS8 | CLOCAL | CREAD);
newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
newSettings.c_iflag |= IGNPAR;
newSettings.c_oflag &= ~OPOST;
newSettings.c_cc[VMIN] = 1;
newSettings.c_cc[VTIME] = 0;
// empty device buffer
tcflush(m_fd, TCIOFLUSH);
// activate new settings of serial device
tcsetattr(m_fd, TCSANOW, &newSettings);
// set serial device into blocking mode
fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL) & ~O_NONBLOCK);
m_open = true;
}
void DeviceSerial::closeDevice()
{
if (m_open == true) {
// empty device buffer
tcflush(m_fd, TCIOFLUSH);
// activate old settings of serial device
tcsetattr(m_fd, TCSANOW, &m_oldSettings);
// close file descriptor from serial device
close(m_fd);
m_fd = -1;
m_open = false;
}
}
void DeviceNetwork::openDevice(const std::string deviceName, const bool noDeviceCheck)
{
m_noDeviceCheck = noDeviceCheck;
struct sockaddr_in sock;
char* hostport;
int ret;
m_open = false;
memset((char*) &sock, 0, sizeof(sock));
hostport = strdup(deviceName.c_str());
char* host = strtok(hostport, ":");
char* port = strtok(NULL, ":");
if (inet_addr(host) == INADDR_NONE) {
struct hostent* he;
he = gethostbyname(host);
if (he == NULL)
return;
memcpy(&sock.sin_addr, he->h_addr_list[0], he->h_length);
} else {
ret = inet_aton(host, &sock.sin_addr);
if (ret == 0)
return;
}
sock.sin_family = AF_INET;
sock.sin_port = htons(strtol(port, NULL, 10));
m_fd = socket(AF_INET, SOCK_STREAM, 0);
if (m_fd < 0)
return;
ret = connect(m_fd, (struct sockaddr*) &sock, sizeof(sock));
if (ret < 0)
return;
free(hostport);
m_open = true;
}
void DeviceNetwork::closeDevice()
{
if (m_open == true) {
// close file descriptor from network device
close(m_fd);
m_fd = -1;
m_open = false;
}
}
Port::Port(const std::string deviceName, const bool noDeviceCheck)
: m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck)
{
m_device = NULL;
if (strchr(deviceName.c_str(), '/') == NULL &&
strchr(deviceName.c_str(), ':') != NULL)
setType(NETWORK);
else
setType(SERIAL);
}
void Port::setType(const DeviceType type)
{
if (m_device != NULL)
delete m_device;
switch (type) {
case SERIAL:
m_device = new DeviceSerial();
break;
case NETWORK:
m_device = new DeviceNetwork();
break;
};
};
} //namespace
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (C) Roland Jax 2014 <roland.jax@liwest.at>
*
* 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/.
*/
#ifndef LIBEBUS_PORT_H_
#define LIBEBUS_PORT_H_
#include <string>
#include <queue>
#include <termios.h>
#include <unistd.h>
namespace libebus
{
enum DeviceType { SERIAL, NETWORK };
#define MAX_READ_SIZE 100
class Device
{
public:
Device() : m_fd(-1), m_open(false), m_noDeviceCheck(false) {}
virtual ~Device() {}
virtual void openDevice(const std::string deviceName, const bool noDeviceCheck) = 0;
virtual void closeDevice() = 0;
bool isOpen();
ssize_t sendBytes(const unsigned char* buffer, size_t nbytes);
ssize_t recvBytes(const long timeout, size_t maxCount);
unsigned char getByte();
ssize_t sizeRecvBuffer() const { return m_recvBuffer.size(); }
protected:
int m_fd;
bool m_open;
bool m_noDeviceCheck;
std::queue<unsigned char> m_recvBuffer;
unsigned char m_buffer[MAX_READ_SIZE];
private:
bool isValid();
};
class DeviceSerial : public Device
{
public:
~DeviceSerial() { closeDevice(); }
void openDevice(const std::string deviceName, const bool noDeviceCheck);
void closeDevice();
private:
termios m_oldSettings;
};
class DeviceNetwork : public Device
{
public:
~DeviceNetwork() { closeDevice(); }
void openDevice(const std::string deviceName, const bool noDeviceCheck);
void closeDevice();
private:
};
class Port
{
public:
Port(const std::string deviceName, const bool noDeviceCheck);
~Port() { delete m_device; }
void open() { m_device->openDevice(m_deviceName, m_noDeviceCheck); }
void close() { m_device->closeDevice(); }
bool isOpen() { return m_device->isOpen(); }
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); }
unsigned char byte() { return m_device->getByte(); }
ssize_t size() const { return m_device->sizeRecvBuffer(); }
private:
std::string m_deviceName;
Device* m_device;
bool m_noDeviceCheck;
void setType(const DeviceType type);
};
} //namespace
#endif // LIBEBUS_PORT_H_
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (C) John Baier 2014 <john@johnm.de>
*
* 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 "result.h"
namespace libebus
{
const char* getResultCodeCStr(int resultCode) {
switch (resultCode) {
case RESULT_ERR_SEND: return "ERR_SEND: send error";
case RESULT_ERR_EXTRA_DATA: return "ERR_EXTRA_DATA: received bytes > sent bytes";
case RESULT_ERR_NAK: return "ERR_NAK: NAK received";
case RESULT_ERR_CRC: return "ERR_CRC: CRC error";
case RESULT_ERR_ACK: return "ERR_ACK: ACK error";
case RESULT_ERR_TIMEOUT: return "ERR_TIMEOUT: read timeout";
case RESULT_ERR_SYN: return "ERR_SYN: SYN received";
case RESULT_ERR_BUS_LOST: return "ERR_BUS_LOST: lost bus arbitration";
case RESULT_ERR_ESC: return "ERR_ESC: invalid escape sequence received";
case RESULT_ERR_INVALID_ARG: return "ERR_INVALID_ARG: invalid argument specified";
case RESULT_ERR_DEVICE: return "ERR_DEVICE: generic device error";
default: return "success";
}
}
} //namespace
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) John Baier 2014 <john@johnm.de>
*
* 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/.
*/
#ifndef LIBEBUS_RESULT_H_
#define LIBEBUS_RESULT_H_
namespace libebus
{
static const int RESULT_OK = 0;
static const int RESULT_BUS_ACQUIRED = 1; // bus successfully acquired
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_ERR_SEND = -1; // send error
static const int RESULT_ERR_EXTRA_DATA = -2; // received bytes > sent bytes
static const int RESULT_ERR_NAK = -3; // NAK received
static const int RESULT_ERR_CRC = -4; // CRC error
static const int RESULT_ERR_ACK = -5; // ACK error
static const int RESULT_ERR_TIMEOUT = -6; // read timeout
static const int RESULT_ERR_SYN = -7; // SYN received
static const int RESULT_ERR_BUS_LOST = -8; // arbitration lost
static const int RESULT_ERR_ESC = -9; // invalid escape sequence received
static const int RESULT_ERR_INVALID_ARG = -10; // invalid argument
static const int RESULT_ERR_DEVICE = -11; // generic device error (usually fatal)
/**
* @brief Return the string corresponding to the result code.
* @param resultCode the result code (see RESULT_ constants).
* @return the string corresponding to the result code.
*/
const char* getResultCodeCStr(int resultCode);
} //namespace
#endif // LIBEBUS_RESULT_H_
+176
View File
@@ -0,0 +1,176 @@
/*
* Copyright (C) John Baier 2014 <john@johnm.de>
*
* 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 "symbol.h"
#include <iostream>
#include <iomanip>
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[]
{
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,
0x64, 0xff, 0xc9, 0x52, 0xa5, 0x3e, 0x08, 0x93, 0x7d, 0xe6, 0xd0, 0x4b, 0xbc, 0x27, 0x11, 0x8a,
0x56, 0xcd, 0xfb, 0x60, 0x97, 0x0c, 0x3a, 0xa1, 0x4f, 0xd4, 0xe2, 0x79, 0x8e, 0x15, 0x23, 0xb8,
0xc8, 0x53, 0x65, 0xfe, 0x09, 0x92, 0xa4, 0x3f, 0xd1, 0x4a, 0x7c, 0xe7, 0x10, 0x8b, 0xbd, 0x26,
0xfa, 0x61, 0x57, 0xcc, 0x3b, 0xa0, 0x96, 0x0d, 0xe3, 0x78, 0x4e, 0xd5, 0x22, 0xb9, 0x8f, 0x14,
0xac, 0x37, 0x01, 0x9a, 0x6d, 0xf6, 0xc0, 0x5b, 0xb5, 0x2e, 0x18, 0x83, 0x74, 0xef, 0xd9, 0x42,
0x9e, 0x05, 0x33, 0xa8, 0x5f, 0xc4, 0xf2, 0x69, 0x87, 0x1c, 0x2a, 0xb1, 0x46, 0xdd, 0xeb, 0x70,
0x0b, 0x90, 0xa6, 0x3d, 0xca, 0x51, 0x67, 0xfc, 0x12, 0x89, 0xbf, 0x24, 0xd3, 0x48, 0x7e, 0xe5,
0x39, 0xa2, 0x94, 0x0f, 0xf8, 0x63, 0x55, 0xce, 0x20, 0xbb, 0x8d, 0x16, 0xe1, 0x7a, 0x4c, 0xd7,
0x6f, 0xf4, 0xc2, 0x59, 0xae, 0x35, 0x03, 0x98, 0x76, 0xed, 0xdb, 0x40, 0xb7, 0x2c, 0x1a, 0x81,
0x5d, 0xc6, 0xf0, 0x6b, 0x9c, 0x07, 0x31, 0xaa, 0x44, 0xdf, 0xe9, 0x72, 0x85, 0x1e, 0x28, 0xb3,
0xc3, 0x58, 0x6e, 0xf5, 0x02, 0x99, 0xaf, 0x34, 0xda, 0x41, 0x77, 0xec, 0x1b, 0x80, 0xb6, 0x2d,
0xf1, 0x6a, 0x5c, 0xc7, 0x30, 0xab, 0x9d, 0x06, 0xe8, 0x73, 0x45, 0xde, 0x29, 0xb2, 0x84, 0x1f,
0xa7, 0x3c, 0x0a, 0x91, 0x66, 0xfd, 0xcb, 0x50, 0xbe, 0x25, 0x13, 0x88, 0x7f, 0xe4, 0xd2, 0x49,
0x95, 0x0e, 0x38, 0xa3, 0x54, 0xcf, 0xf9, 0x62, 0x8c, 0x17, 0x21, 0xba, 0x4d, 0xd6, 0xe0, 0x7b,
};
SymbolString::SymbolString(const std::string str)
: 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);
}
// add CRC + escape
push_back_escape(m_crc, false);
}
SymbolString::SymbolString(const std::string str, bool escaped)
: 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);
}
}
const std::string SymbolString::getDataStr(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) {
if (value == 0x00) {
sstr << "a9"; // ESC
}
else if (value == 0x01) {
sstr << "aa"; // SYN
}
else {
sstr << "XX"; // invalid escape sequence
}
previousEscape = false;
}
else if (unescape == true && value == ESC) {
previousEscape = true; // escape sequence not yet finished
}
else {
sstr << std::nouppercase << std::setw(2) << std::hex
<< std::setfill('0') << static_cast<unsigned>(value);
}
}
return sstr.str();
}
void SymbolString::push_back_escape(const unsigned char value, bool updateCRC)
{
if (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 {
m_data.push_back(value);
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;
}
if (value == 0x01) {
m_data.push_back(SYN);
previousEscape = false;
return SYN;
}
return 0; // invalid escape sequence
}
if (value == ESC) {
previousEscape = true;
return 1; // escape sequence not yet finished
}
m_data.push_back(value);
return value;
}
void SymbolString::addCRC(const unsigned char value) {
m_crc = CRC_LOOKUP_TABLE[m_crc]^value;
}
bool isMaster(unsigned char addr) {
unsigned char addrHi = (addr & 0xF0) >> 4;
unsigned char addrLo = (addr & 0x0F);
return ((addrHi == 0x0) || (addrHi == 0x1) || (addrHi == 0x3) || (addrHi == 0x7) || (addrHi == 0xF))
&& ((addrLo == 0x0) || (addrLo == 0x1) || (addrLo == 0x3) || (addrLo == 0x7) || (addrLo == 0xF));
}
} //namespace
+148
View File
@@ -0,0 +1,148 @@
/*
* Copyright (C) John Baier 2014 <john@johnm.de>
*
* 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/.
*/
#ifndef LIBEBUS_SYMBOL_H_
#define LIBEBUS_SYMBOL_H_
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <queue>
namespace libebus
{
static const unsigned char ESC = 0xA9; // escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA
static const unsigned char SYN = 0xAA; // synchronization symbol
static const unsigned char ACK = 0x00; // positive acknowledge
static const unsigned char NAK = 0xFF; // negative acknowledge
static const unsigned char BROADCAST = 0xFE; // the broadcast destination address
/**
* @brief A string of bus symbols.
*/
class SymbolString
{
public:
/**
* @brief Creates a new empty SymbolString.
*/
SymbolString() : m_crc(0) {}
/**
* @brief Creates a new escaped SymbolString 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.
* @param str the hex string.
*/
SymbolString(const std::string str, bool escaped);
/**
* @brief Returns the symbols as hex string.
* @param escaped whether to unescape the symbols.
* @return the symbols as hex string.
*/
const std::string getDataStr(bool unescape=false);
/**
* @brief Returns 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.
*/
unsigned char at(const size_t index) { return m_data.at(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]; }
/**
* @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) const { return m_data[index]; }
/**
* @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.
* @param value the symbol to append.
* @param updateCrc whether to update the calculated CRC in @a m_crc.
*/
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);
/**
* @brief Returns the number of symbols in this symbol string.
* @return the number of available symbols.
*/
size_t size() const { return m_data.size(); }
/**
* @brief Returns the calculated CRC.
* @return the calculated CRC.
*/
unsigned char getCRC() const { return m_crc; }
/**
* @brief Clears the symbols.
*/
void clear() { m_crc=0; m_data.clear(); }
private:
/**
* @brief Updates the calculated CRC in @a m_crc by adding a value.
* @param value the (escaped) value to add to the calculated CRC in @a m_crc.
*/
void addCRC(const unsigned char value);
/**
* @brief the string of bus symbols.
*/
std::vector<unsigned char> m_data;
/**
* @brief the calculated CRC.
*/
unsigned char m_crc;
};
/**
* Returns whether the address is one of the 25 master addresses.
* @param addr the address to check.
* @return <code>true</code> if the specified address is a master address.
*/
bool isMaster(unsigned char addr);
} //namespace
#endif // LIBEBUS_SYMBOL_H_