file struturce changed.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
AM_CXXFLAGS = -fpic \
|
||||
-Wall \
|
||||
-Wextra
|
||||
|
||||
noinst_LIBRARIES = libebus.a
|
||||
|
||||
libebus_a_SOURCES = result.cpp \
|
||||
result.h \
|
||||
symbol.cpp \
|
||||
symbol.h \
|
||||
data.cpp \
|
||||
data.h \
|
||||
port.cpp \
|
||||
port.h \
|
||||
buscommand.cpp \
|
||||
buscommand.h \
|
||||
bus.cpp \
|
||||
bus.h \
|
||||
command.cpp \
|
||||
command.h \
|
||||
commands.cpp \
|
||||
commands.h \
|
||||
configfile.cpp \
|
||||
configfile.h \
|
||||
dump.cpp \
|
||||
dump.h \
|
||||
decode.cpp \
|
||||
decode.h \
|
||||
encode.cpp \
|
||||
encode.h
|
||||
|
||||
distclean-local:
|
||||
-rm -f Makefile.in
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
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<unsigned>(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
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 <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
|
||||
|
||||
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<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_
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "buscommand.h"
|
||||
|
||||
namespace libebus
|
||||
{
|
||||
|
||||
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];
|
||||
|
||||
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 std::string BusCommand::getMessageStr()
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (m_resultCode >= 0) {
|
||||
if (m_type == masterSlave) {
|
||||
result = m_command.getDataStr();
|
||||
result += "00";
|
||||
result += m_result.getDataStr();
|
||||
result += "00";
|
||||
} else {
|
||||
result = "success";
|
||||
}
|
||||
}
|
||||
else
|
||||
result = "error: "+std::string(getResultCodeCStr());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_BUSCOMMAND_H_
|
||||
#define LIBEBUS_BUSCOMMAND_H_
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
|
||||
|
||||
namespace libebus
|
||||
{
|
||||
|
||||
|
||||
enum CommandType { invalid, broadcast, masterMaster, masterSlave };
|
||||
|
||||
class BusCommand
|
||||
{
|
||||
|
||||
public:
|
||||
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; }
|
||||
SymbolString getResult() const { return m_result; }
|
||||
|
||||
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); }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
#endif // LIBEBUS_BUSCOMMAND_H_
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "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
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_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_
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "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
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_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_
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "configfile.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <dirent.h>
|
||||
|
||||
namespace libebus
|
||||
{
|
||||
|
||||
|
||||
void ConfigFileCSV::parse(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::parse(std::istream& is, Commands& commands)
|
||||
{
|
||||
; // ToDo: Implementation 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->parse(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
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_CONFIGFILE_H_
|
||||
#define LIBEBUS_CONFIGFILE_H_
|
||||
|
||||
#include "commands.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace libebus
|
||||
{
|
||||
|
||||
/** available file endings / types. */
|
||||
enum FileType { CSV, XML };
|
||||
|
||||
/**
|
||||
* @brief Base class for config files.
|
||||
*/
|
||||
class ConfigFile
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~ConfigFile() {}
|
||||
|
||||
/**
|
||||
* @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() {}
|
||||
|
||||
/**
|
||||
* @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() {}
|
||||
|
||||
/**
|
||||
* @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<std::string> 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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
#endif // LIBEBUS_CONFIGFILE_H_
|
||||
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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 <iostream>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
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<std::string>::iterator& it, const std::vector<std::string>::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<unsigned int, std::string> 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<float>(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<unsigned int, std::string>::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<sizeof(dayNames)/sizeof(dayNames[0]); i++)
|
||||
values[dataType.minValueOrLength + i] = dayNames[i];
|
||||
}
|
||||
return new ValueListDataField(name, partType, offset, length, dataType, unit, comment, values);
|
||||
case bt_number:
|
||||
if (values.empty() || (dataType.flags&LST) == 0)
|
||||
return new NumberDataField(name, partType, offset, length, dataType, unit, comment, factor);
|
||||
return new ValueListDataField(name, partType, offset, length, dataType, unit, comment, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL; // TODO error code: invalid type definition
|
||||
}
|
||||
|
||||
const std::string DataField::read(SymbolString& masterData, SymbolString& slaveData, bool verbose)
|
||||
{
|
||||
SymbolString& input = m_partType == pt_masterData ? masterData : slaveData;
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
break;
|
||||
case pt_slaveData:
|
||||
break;
|
||||
default:
|
||||
return "invalid part type";
|
||||
}
|
||||
std::ostringstream output;
|
||||
if (verbose)
|
||||
output << m_name << "=";
|
||||
|
||||
if (readSymbols(input, output) == false)
|
||||
return "unable to parse";
|
||||
|
||||
if (verbose && m_unit.length() > 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<unsigned>(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<unsigned>(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<unsigned>(ch/6) << ":"
|
||||
<< std::setw(2) << std::setfill('0') << static_cast<unsigned>((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<unsigned>(ch);
|
||||
break;
|
||||
default:
|
||||
if (ch < 0x20)
|
||||
ch = m_dataType.replacement;
|
||||
output << static_cast<char>(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<unsigned>(value);
|
||||
else
|
||||
output << std::setprecision(3) << std::fixed << static_cast<float>(value * m_factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
signedValue = (int)value;
|
||||
}
|
||||
|
||||
if (m_factor == 1.0)
|
||||
output << static_cast<int>(signedValue);
|
||||
else
|
||||
output << std::setprecision(3) << std::fixed << static_cast<float>(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<unsigned int, std::string>::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<unsigned int, std::string>::iterator it = m_values.begin(); it != m_values.end(); it++)
|
||||
if (it->second.compare(str) == 0)
|
||||
return writeRawValue(it->first, output);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
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<std::string>::iterator& it, const std::vector<std::string>::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<unsigned int, std::string> 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<unsigned int, std::string> m_values;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
#endif // LIBEBUS_DATA_H_
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "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
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_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_
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "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
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_DUMP_H_
|
||||
#define LIBEBUS_DUMP_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
#endif // LIBEBUS_DUMP_H_
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "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
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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_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_
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "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
|
||||
}
|
||||
|
||||
if (maxCount > sizeof(m_buffer))
|
||||
maxCount = sizeof(m_buffer);
|
||||
|
||||
// read bytes from device
|
||||
ssize_t nbytes = read(m_fd, m_buffer, maxCount);
|
||||
|
||||
for (int i = 0; i < nbytes; i++)
|
||||
m_recvBuffer.push(m_buffer[i]);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_PORT_H_
|
||||
#define LIBEBUS_PORT_H_
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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<unsigned char> 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); }
|
||||
|
||||
/**
|
||||
* @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;
|
||||
/** the 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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} //namespace
|
||||
|
||||
#endif // LIBEBUS_PORT_H_
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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 "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
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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_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_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
|
||||
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_
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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 "symbol.h"
|
||||
#include "result.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_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); // TODO check
|
||||
push_back((unsigned char)value, false, true);
|
||||
}
|
||||
// add CRC + escape
|
||||
push_back(m_crc, false, false);
|
||||
}
|
||||
|
||||
SymbolString::SymbolString(const std::string str, bool isEscaped)
|
||||
: m_unescapeState(1), m_crc(0)
|
||||
{
|
||||
// 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); // TODO check
|
||||
push_back((unsigned char)value, isEscaped, false);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string SymbolString::getDataStr(const bool unescape)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
bool previousEscape = false;
|
||||
|
||||
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
|
||||
else if (value == 0x01)
|
||||
sstr << "aa"; // SYN
|
||||
else
|
||||
sstr << "XX"; // invalid escape sequence
|
||||
|
||||
previousEscape = false;
|
||||
}
|
||||
else if (m_unescapeState == 0 && 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();
|
||||
}
|
||||
|
||||
int SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC)
|
||||
{
|
||||
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 (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 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);
|
||||
|
||||
if (value == 0x00) {
|
||||
m_data.push_back(ESC);
|
||||
m_unescapeState = 1;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (value == 0x01) {
|
||||
m_data.push_back(SYN);
|
||||
m_unescapeState = 1;
|
||||
return RESULT_OK;
|
||||
}
|
||||
return RESULT_ERR_ESC; // invalid escape sequence
|
||||
}
|
||||
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 RESULT_OK;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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_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 escaped or unescaped bus symbols.
|
||||
*/
|
||||
class SymbolString
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a new unescaped empty instance.
|
||||
* @param escaped whether to create an escaped instance.
|
||||
*/
|
||||
SymbolString() : m_unescapeState(1), m_crc(0) {}
|
||||
/**
|
||||
* @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 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, const bool isEscaped);
|
||||
/**
|
||||
* @brief Returns the symbols as hex string.
|
||||
* @param unescape whether to unescape an escaped instance.
|
||||
* @return the symbols as hex string.
|
||||
*/
|
||||
const std::string getDataStr(const bool unescape=true);
|
||||
/**
|
||||
* @brief Returns a reference to the symbol at the specified index.
|
||||
* @param index the index of the symbol to return.
|
||||
* @return the reference to the symbol at the specified 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.
|
||||
*/
|
||||
const unsigned char& operator[](const size_t index) const { return m_data[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).
|
||||
*/
|
||||
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.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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_data.clear(); m_unescapeState = m_unescapeState==0 ? 0 : 1; m_crc = 0; }
|
||||
|
||||
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 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.
|
||||
*/
|
||||
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_
|
||||
@@ -0,0 +1,41 @@
|
||||
AM_CXXFLAGS = -fpic \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-I$(top_srcdir)/src/lib/ebus
|
||||
|
||||
noinst_PROGRAMS = test_port \
|
||||
test_symbol \
|
||||
test_data \
|
||||
test_bus \
|
||||
test_commands \
|
||||
test_configfile \
|
||||
test_decode \
|
||||
test_encode
|
||||
|
||||
test_port_SOURCES = test_port.cpp
|
||||
test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a
|
||||
|
||||
test_symbol_SOURCES = test_symbol.cpp
|
||||
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
|
||||
|
||||
test_configfile_SOURCES = test_configfile.cpp
|
||||
test_configfile_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a
|
||||
|
||||
test_decode_SOURCES = test_decode.cpp
|
||||
test_decode_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a
|
||||
|
||||
test_encode_SOURCES = test_encode.cpp
|
||||
test_encode_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a
|
||||
|
||||
distclean-local:
|
||||
-rm -f Makefile.in
|
||||
-rm -rf .libs
|
||||
@@ -0,0 +1,4 @@
|
||||
# type;class;cmd;comment;QQ;ZZ;PBSB;NN;D1D2D3;elements;sub;part;position;datatype;factor;unit;valid;comment;sub;part;position;datatype;factor;unit;valid;comment;sub;part;position;datatype;factor;unit;valid;comment;sub;part;position;datatype;factor;unit;valid;comment
|
||||
c;broad;date_time_temp;Datum, Uhrzeit und Aussentempertur;;FE;0700;9;-;4;temp;md;1,2;d2b;1.0;°C;-;Temperatur;day;md;8;bdy;-;-;-;Wochentag;date;md;6,7,9;bda;-;-;-;Datum;time;md;5,4,3;bti;-;-;-;Uhrzeit
|
||||
g;ci;Password;Kennwort;;15;B509;3;0D2C00;4;pin1;sd;1;uch;-;-;-;Pin 1;pin2;sd;2;uch;-;-;-;Pin 2;pin3;sd;3;uch;-;-;-;Pin 3;pin4;sd;4;uch;-;-;-;Pin 4
|
||||
s;vwxmk;DesiredTemp;Solltemperatur;;50;B509;4;0E3200;1;-;sd;1;d1c;1.0;°C;-;-;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "configfile.h"
|
||||
#include "commands.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace libebus;
|
||||
|
||||
// will be part of cfg csv class
|
||||
void readCSV(std::istream& is, Commands& commands){
|
||||
std::string line;
|
||||
|
||||
// read lines
|
||||
while (std::getline(is, line) != 0) {
|
||||
std::vector<std::string> row;
|
||||
std::string column;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
std::istringstream stream(line);
|
||||
|
||||
// walk through columns
|
||||
while (std::getline(stream, column, ';') != 0) {
|
||||
row.push_back(column);
|
||||
count++;
|
||||
}
|
||||
|
||||
commands.addCommand(row);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Commands* commands = ConfigCommands("test", CSV).getCommands();
|
||||
std::cout << "Commands: " << commands->sizeCmdDB() << std::endl;
|
||||
|
||||
//~ std::string data("g ci password pin1");
|
||||
std::string data("s vwxmk DesiredTemp");
|
||||
|
||||
int index = commands->findCommand(data);
|
||||
std::cout << "found at index: " << index << std::endl;
|
||||
|
||||
// prepare data
|
||||
std::string token;
|
||||
std::istringstream stream(data);
|
||||
std::vector<std::string> cmd;
|
||||
|
||||
// split stream
|
||||
while (std::getline(stream, token, ' ') != 0)
|
||||
cmd.push_back(token);
|
||||
|
||||
//~ Command* command = new Command(index, (*commands)[index], "ff15b509030d2c0035000401000000cf00");
|
||||
Command* command = new Command(index, (*commands)[index], "19.0");
|
||||
|
||||
//~ std::string result = command->calcResult(cmd);
|
||||
std::string result = command->calcData();
|
||||
std::cout << "result: " << result << std::endl;
|
||||
|
||||
delete command;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "configfile.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace libebus;
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
std::string dir("test");
|
||||
ConfigCommands config(dir, CSV);
|
||||
|
||||
Commands* commands = config.getCommands();
|
||||
|
||||
std::cout << "size: " << commands->sizeCmdDB() << std::endl;
|
||||
|
||||
commands->findCommand("g ci Password");
|
||||
|
||||
std::cout << (*commands)[0][0] << std::endl;
|
||||
|
||||
delete commands;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@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 "data.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
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<std::string> entries;
|
||||
|
||||
while (std::getline(isstr, item, ';') != 0)
|
||||
entries.push_back(item);
|
||||
|
||||
std::vector<std::string>::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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "decode.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
using namespace libebus;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
Decode* help_dec = NULL;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// HEX
|
||||
{
|
||||
const char* hex[] = {"53706569636865722020"};
|
||||
for (size_t i = 0; i < sizeof(hex)/sizeof(hex[0]); i++) {
|
||||
help_dec = new DecodeHEX(hex[i]);
|
||||
std::cout << "DecodeHEX: " << std::setw(20) << hex[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// UCH
|
||||
{
|
||||
const char* uch[] = {"00", "01", "7f", "80", "fe", "ff", "a1"};
|
||||
for (size_t i = 0; i < sizeof(uch)/sizeof(uch[0]); i++) {
|
||||
help_dec = new DecodeUCH(uch[i], "1.0");
|
||||
std::cout << "DecodeUCH: " << std::setw(20) << uch[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// SCH
|
||||
{
|
||||
const char* sch[] = {"00", "01", "7f", "80", "fe", "ff", "a1"};
|
||||
for (size_t i = 0; i < sizeof(sch)/sizeof(sch[0]); i++) {
|
||||
help_dec = new DecodeSCH(sch[i], "1.0");
|
||||
std::cout << "DecodeSCH: " << std::setw(20) << sch[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// UIN
|
||||
{
|
||||
const char* uin[] = {"0000", "0001", "7fff", "8000", "fffe", "ffff", "a1b2"};
|
||||
for (size_t i = 0; i < sizeof(uin)/sizeof(uin[0]); i++) {
|
||||
help_dec = new DecodeUIN(uin[i], "1.0");
|
||||
std::cout << "DecodeUIN: " << std::setw(20) << uin[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// SIN
|
||||
{
|
||||
const char* sin[] = {"0000", "0001", "7fff", "8000", "fffe", "ffff", "a1b2"};
|
||||
for (size_t i = 0; i < sizeof(sin)/sizeof(sin[0]); i++) {
|
||||
help_dec = new DecodeSIN(sin[i], "1.0");
|
||||
std::cout << "DecodeSIN: " << std::setw(20) << sin[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// ULG
|
||||
{
|
||||
const char* ulg[] = {"00000000", "00000001", "7fffffff", "80000000", "fffffffe", "ffffffff", "a1b2c3d4"};
|
||||
for (size_t i = 0; i < sizeof(ulg)/sizeof(ulg[0]); i++) {
|
||||
help_dec = new DecodeULG(ulg[i], "1.0");
|
||||
std::cout << "DecodeULG: " << std::setw(20) << ulg[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// SLG
|
||||
{
|
||||
const char* slg[] = {"00000000", "00000001", "7fffffff", "80000000", "fffffffe", "ffffffff", "a1b2c3d4"};
|
||||
for (size_t i = 0; i < sizeof(slg)/sizeof(slg[0]); i++) {
|
||||
help_dec = new DecodeSLG(slg[i], "1.0");
|
||||
std::cout << "DecodeSLG: " << std::setw(20) << slg[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// FLT
|
||||
{
|
||||
const char* flt[] = {"0000", "081b", "2532", "2689", "0851"};
|
||||
for (size_t i = 0; i < sizeof(flt)/sizeof(flt[0]); i++) {
|
||||
help_dec = new DecodeFLT(flt[i], "1.0");
|
||||
std::cout << "DecodeFLT: " << std::setw(20) << flt[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// STR
|
||||
{
|
||||
const char* str[] = {"53706569636865722020", "5644363030" };
|
||||
for (size_t i = 0; i < sizeof(str)/sizeof(str[0]); i++) {
|
||||
help_dec = new DecodeSTR(str[i]);
|
||||
std::cout << "DecodeSTR: " << std::setw(20) << str[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BCD
|
||||
{
|
||||
const char* bcd[] = {"00", "01", "02", "03", "12", "99"};
|
||||
for (size_t i = 0; i < sizeof(bcd)/sizeof(bcd[0]); i++) {
|
||||
help_dec = new DecodeBCD(bcd[i], "1.0");
|
||||
std::cout << "DecodeBCD: " << std::setw(20) << bcd[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D1B
|
||||
{
|
||||
const char* d1b[] = {"00", "01", "7f", "81", "80"};
|
||||
for (size_t i = 0; i < sizeof(d1b)/sizeof(d1b[0]); i++) {
|
||||
help_dec = new DecodeD1B(d1b[i], "1.0");
|
||||
std::cout << "DecodeD1B: " << std::setw(20) << d1b[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D1C
|
||||
{
|
||||
const char* d1c[] = {"00", "64", "c8"};
|
||||
for (size_t i = 0; i < sizeof(d1c)/sizeof(d1c[0]); i++) {
|
||||
help_dec = new DecodeD1C(d1c[i], "1.0");
|
||||
std::cout << "DecodeD1C: " << std::setw(20) << d1c[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D2B
|
||||
{
|
||||
const char* d2b[] = {"0000", "0100", "ffff", "00ff", "0080", "0180", "ff7f"};
|
||||
for (size_t i = 0; i < sizeof(d2b)/sizeof(d2b[0]); i++) {
|
||||
help_dec = new DecodeD2B(d2b[i], "1.0");
|
||||
std::cout << "DecodeD2B: " << std::setw(20) << d2b[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D2C
|
||||
{
|
||||
const char* d2c[] = {"0000", "0100", "ffff", "f0ff", "0080", "0180", "ff7f"};
|
||||
for (size_t i = 0; i < sizeof(d2c)/sizeof(d2c[0]); i++) {
|
||||
help_dec = new DecodeD2C(d2c[i], "1.0");
|
||||
std::cout << "DecodeD2C: " << std::setw(20) << d2c[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BDA
|
||||
{
|
||||
const char* bda[] = {"171113", "220901"};
|
||||
for (size_t i = 0; i < sizeof(bda)/sizeof(bda[0]); i++) {
|
||||
help_dec = new DecodeBDA(bda[i]);
|
||||
std::cout << "DecodeBDA: " << std::setw(20) << bda[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// HDA
|
||||
{
|
||||
const char* hda[] = {"010101", "1f0c1b"};
|
||||
for (size_t i = 0; i < sizeof(hda)/sizeof(hda[0]); i++) {
|
||||
help_dec = new DecodeHDA(hda[i]);
|
||||
std::cout << "DecodeHDA: " << std::setw(20) << hda[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BTI
|
||||
{
|
||||
const char* bti[] = {"010101", "174209", "235959"};
|
||||
for (size_t i = 0; i < sizeof(bti)/sizeof(bti[0]); i++) {
|
||||
help_dec = new DecodeBTI(bti[i]);
|
||||
std::cout << "DecodeBTI: " << std::setw(20) << bti[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// HTI
|
||||
{
|
||||
const char* hti[] = {"010101", "112a09", "173b3b"};
|
||||
for (size_t i = 0; i < sizeof(hti)/sizeof(hti[0]); i++) {
|
||||
help_dec = new DecodeHTI(hti[i]);
|
||||
std::cout << "DecodeHTI: " << std::setw(20) << hti[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BDY
|
||||
{
|
||||
const char* bdy[] = {"01", "03", "06", "07"};
|
||||
for (size_t i = 0; i < sizeof(bdy)/sizeof(bdy[0]); i++) {
|
||||
help_dec = new DecodeBDY(bdy[i]);
|
||||
std::cout << "DecodeBDY: " << std::setw(20) << bdy[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// HDY
|
||||
{
|
||||
const char* hdy[] = {"01", "03", "07", "08"};
|
||||
for (size_t i = 0; i < sizeof(hdy)/sizeof(hdy[0]); i++) {
|
||||
help_dec = new DecodeHDY(hdy[i]);
|
||||
std::cout << "DecodeHDY: " << std::setw(20) << hdy[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// TTM
|
||||
{
|
||||
const char* ttm[] = {"00", "23", "4f", "90"};
|
||||
for (size_t i = 0; i < sizeof(ttm)/sizeof(ttm[0]); i++) {
|
||||
help_dec = new DecodeTTM(ttm[i]);
|
||||
std::cout << "DecodeTTM: " << std::setw(20) << ttm[i] << " = " << help_dec->decode() << std::endl;
|
||||
|
||||
delete help_dec;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "encode.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
using namespace libebus;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
Encode* help_enc = NULL;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
// HEX
|
||||
{
|
||||
const char* hex[] = {"53 70 65 69 63 68 65 72 20 20"};
|
||||
for (size_t i = 0; i < sizeof(hex)/sizeof(hex[0]); i++) {
|
||||
help_enc = new EncodeHEX(hex[i]);
|
||||
std::cout << "EncodeHEX: " << std::setw(20) << hex[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// UCH
|
||||
{
|
||||
const char* uch[] = {"0", "1", "127", "128", "254", "255", "161"};
|
||||
for (size_t i = 0; i < sizeof(uch)/sizeof(uch[0]); i++) {
|
||||
help_enc = new EncodeUCH(uch[i], "1.0");
|
||||
std::cout << "EncodeUCH: " << std::setw(20) << uch[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// SCH
|
||||
{
|
||||
const char* sch[] = {"0", "1", "127", "-128", "-2", "-1", "-95"};
|
||||
for (size_t i = 0; i < sizeof(sch)/sizeof(sch[0]); i++) {
|
||||
help_enc = new EncodeSCH(sch[i], "1.0");
|
||||
std::cout << "EncodeSCH: " << std::setw(20) << sch[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// UIN
|
||||
{
|
||||
const char* uin[] = {"0", "1", "32767", "32768", "65534", "65535", "41394"};
|
||||
for (size_t i = 0; i < sizeof(uin)/sizeof(uin[0]); i++) {
|
||||
help_enc = new EncodeUIN(uin[i], "1.0");
|
||||
std::cout << "EncodeUIN: " << std::setw(20) << uin[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// SIN
|
||||
{
|
||||
const char* sin[] = {"0", "1", "32767", "-32768", "-2", "-1", "-24142"};
|
||||
for (size_t i = 0; i < sizeof(sin)/sizeof(sin[0]); i++) {
|
||||
help_enc = new EncodeSIN(sin[i], "1.0");
|
||||
std::cout << "EncodeSIN: " << std::setw(20) << sin[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// ULG
|
||||
{
|
||||
const char* ulg[] = {"0", "1", "2147483647", "2147483648", "4294967294", "4294967295", "2712847316"};
|
||||
for (size_t i = 0; i < sizeof(ulg)/sizeof(ulg[0]); i++) {
|
||||
help_enc = new EncodeULG(ulg[i], "1.0");
|
||||
std::cout << "EncodeULG: " << std::setw(20) << ulg[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// SLG
|
||||
{
|
||||
const char* slg[] = {"0", "1", "2147483647", "-2147483648", "-2", "-1", "-1582119980"};
|
||||
for (size_t i = 0; i < sizeof(slg)/sizeof(slg[0]); i++) {
|
||||
help_enc = new EncodeSLG(slg[i], "1.0");
|
||||
std::cout << "EncodeSLG: " << std::setw(20) << slg[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// FLT
|
||||
{
|
||||
const char* flt[] = {"0.000", "2.075", "9.522", "9.865", "2.129"};
|
||||
for (size_t i = 0; i < sizeof(flt)/sizeof(flt[0]); i++) {
|
||||
help_enc = new EncodeFLT(flt[i], "1.0");
|
||||
std::cout << "EncodeFLT: " << std::setw(20) << flt[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// STR
|
||||
{
|
||||
const char* str[] = {"Speicher ", "VD600" };
|
||||
for (size_t i = 0; i < sizeof(str)/sizeof(str[0]); i++) {
|
||||
help_enc = new EncodeSTR(str[i]);
|
||||
std::cout << "EncodeSTR: " << std::setw(20) << str[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BCD
|
||||
{
|
||||
const char* bcd[] = {"0", "1", "2", "3", "12", "99"};
|
||||
for (size_t i = 0; i < sizeof(bcd)/sizeof(bcd[0]); i++) {
|
||||
help_enc = new EncodeBCD(bcd[i], "1.0");
|
||||
std::cout << "EncodeBCD: " << std::setw(20) << bcd[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D1B
|
||||
{
|
||||
const char* d1b[] = {"00", "01", "127", "-127", "-128"};
|
||||
for (size_t i = 0; i < sizeof(d1b)/sizeof(d1b[0]); i++) {
|
||||
help_enc = new EncodeD1B(d1b[i], "1.0");
|
||||
std::cout << "EncodeD1B: " << std::setw(20) << d1b[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D1C
|
||||
{
|
||||
const char* d1c[] = {"0", "50", "100"};
|
||||
for (size_t i = 0; i < sizeof(d1c)/sizeof(d1c[0]); i++) {
|
||||
help_enc = new EncodeD1C(d1c[i], "1.0");
|
||||
std::cout << "EncodeD1C: " << std::setw(20) << d1c[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D2B
|
||||
{
|
||||
const char* d2b[] = {"0", "0.00390625", "-0.00390625", "-1", "-128", "-127.99609375", "127.99609375"};
|
||||
for (size_t i = 0; i < sizeof(d2b)/sizeof(d2b[0]); i++) {
|
||||
help_enc = new EncodeD2B(d2b[i], "1.0");
|
||||
std::cout << "EncodeD2B: " << std::setw(20) << d2b[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// D2C
|
||||
{
|
||||
const char* d2c[] = {"0", "0.0625", "-0.0625", "-1", "-2048", "-2047.9375", "2047.9375"};
|
||||
for (size_t i = 0; i < sizeof(d2c)/sizeof(d2c[0]); i++) {
|
||||
help_enc = new EncodeD2C(d2c[i], "1.0");
|
||||
std::cout << "EncodeD2C: " << std::setw(20) << d2c[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BDA
|
||||
{
|
||||
const char* bda[] = {"17.11.2013", "22.09.2001"};
|
||||
for (size_t i = 0; i < sizeof(bda)/sizeof(bda[0]); i++) {
|
||||
help_enc = new EncodeBDA(bda[i]);
|
||||
std::cout << "EncodeBDA: " << std::setw(20) << bda[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// HDA
|
||||
{
|
||||
const char* hda[] = {"01.01.2001", "31.12.2027"};
|
||||
for (size_t i = 0; i < sizeof(hda)/sizeof(hda[0]); i++) {
|
||||
help_enc = new EncodeHDA(hda[i]);
|
||||
std::cout << "EncodeHDA: " << std::setw(20) << hda[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BTI
|
||||
{
|
||||
const char* bti[] = {"01:01:01", "17:42:09", "23:59:59"};
|
||||
for (size_t i = 0; i < sizeof(bti)/sizeof(bti[0]); i++) {
|
||||
help_enc = new EncodeBTI(bti[i]);
|
||||
std::cout << "EncodeBTI: " << std::setw(20) << bti[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// HTI
|
||||
{
|
||||
const char* hti[] = {"01:01:01", "17:42:09", "23:59:59"};
|
||||
for (size_t i = 0; i < sizeof(hti)/sizeof(hti[0]); i++) {
|
||||
help_enc = new EncodeHTI(hti[i]);
|
||||
std::cout << "EncodeHTI: " << std::setw(20) << hti[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// BDY
|
||||
{
|
||||
const char* bdy[] = {"Tue", "Thu", "Sun", "Err"};
|
||||
for (size_t i = 0; i < sizeof(bdy)/sizeof(bdy[0]); i++) {
|
||||
help_enc = new EncodeBDY(bdy[i]);
|
||||
std::cout << "EncodeBDY: " << std::setw(20) << bdy[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
// HDY
|
||||
{
|
||||
const char* hdy[] = {"Mon", "Wed", "Sun", "Err"};
|
||||
for (size_t i = 0; i < sizeof(hdy)/sizeof(hdy[0]); i++) {
|
||||
help_enc = new EncodeHDY(hdy[i]);
|
||||
std::cout << "EncodeHDY: " << std::setw(20) << hdy[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// TTM
|
||||
{
|
||||
const char* ttm[] = {"00:00", "05:50", "13:10", "24:00"};
|
||||
for (size_t i = 0; i < sizeof(ttm)/sizeof(ttm[0]); i++) {
|
||||
help_enc = new EncodeTTM(ttm[i]);
|
||||
std::cout << "EncodeTTM: " << std::setw(20) << ttm[i] << " = " << help_enc->encode() << std::endl;
|
||||
|
||||
delete help_enc;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 "port.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace libebus;
|
||||
|
||||
int main ()
|
||||
{
|
||||
std::string dev("/dev/ttyUSB20");
|
||||
Port port(dev, true);
|
||||
|
||||
port.open();
|
||||
|
||||
if(port.isOpen() == true)
|
||||
std::cout << "openPort successful." << std::endl;
|
||||
|
||||
int count = 0;
|
||||
|
||||
while (1) {
|
||||
ssize_t bytes_read;
|
||||
unsigned char byte = 0;
|
||||
bytes_read = port.recv(0);
|
||||
|
||||
for (int i = 0; i < bytes_read; i++)
|
||||
byte = port.byte();
|
||||
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<unsigned>(byte) << std::endl;
|
||||
|
||||
bytes_read = 0;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
port.close();
|
||||
|
||||
if(port.isOpen() == false)
|
||||
std::cout << "closePort successful." << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) John Baier 2014 <ebusd@johnm.de>
|
||||
*
|
||||
* 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 "symbol.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace libebus;
|
||||
|
||||
int main ()
|
||||
{
|
||||
SymbolString sstr = SymbolString("10feb5050427a915aa");
|
||||
|
||||
std::string gotStr = sstr.getDataStr(false), expectStr = "10feb5050427a90015a90177";
|
||||
|
||||
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
|
||||
std::cout << "ctor escaped successful." << std::endl;
|
||||
else
|
||||
std::cout << "ctor escaped invalid: got " << gotStr
|
||||
<< ", expected " << expectStr << std::endl;
|
||||
|
||||
unsigned char gotCrc = sstr.getCRC(), expectCrc = 0x77;
|
||||
|
||||
if (gotCrc == expectCrc)
|
||||
std::cout << "CRC successful." << std::endl;
|
||||
else
|
||||
std::cout << "CRC invalid: got 0x"
|
||||
<< std::nouppercase << std::setw(2) << std::hex
|
||||
<< std::setfill('0') << static_cast<unsigned>(gotCrc)
|
||||
<< ", expected 0x"
|
||||
<< std::nouppercase << std::setw(2) << std::hex
|
||||
<< std::setfill('0') << static_cast<unsigned>(expectCrc)
|
||||
<< std::endl;
|
||||
|
||||
gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa77";
|
||||
|
||||
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
|
||||
std::cout << "unescape successful." << std::endl;
|
||||
else
|
||||
std::cout << "unescape invalid: got " << gotStr
|
||||
<< ", expected " << expectStr << std::endl;
|
||||
|
||||
sstr = SymbolString("10feb5050427a90015a90177", true);
|
||||
|
||||
gotStr = sstr.getDataStr();
|
||||
|
||||
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
|
||||
std::cout << "ctor unescaped successful." << std::endl;
|
||||
else
|
||||
std::cout << "ctor unescaped invalid: got " << gotStr
|
||||
<< ", expected " << expectStr << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user