file struturce changed.

This commit is contained in:
Roland Jax
2014-11-06 16:08:11 +01:00
parent 727bf600da
commit 793c64d922
56 changed files with 67 additions and 67 deletions
+33
View File
@@ -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
+388
View File
@@ -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
+89
View File
@@ -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_
+69
View File
@@ -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
+70
View File
@@ -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_
+345
View File
@@ -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
+69
View File
@@ -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_
+246
View File
@@ -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
+81
View File
@@ -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_
+137
View File
@@ -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
+150
View File
@@ -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_
+599
View File
@@ -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
+313
View File
@@ -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_
+352
View File
@@ -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
+291
View File
@@ -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_
+53
View File
@@ -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
+73
View File
@@ -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_
+369
View File
@@ -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
+291
View File
@@ -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_
+262
View File
@@ -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
+264
View File
@@ -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_
+43
View File
@@ -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
+59
View File
@@ -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_
+193
View File
@@ -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
+145
View File
@@ -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_
+41
View File
@@ -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
+4
View File
@@ -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;-;-;;;;;;;;;;;;;;;;;;;;;;;;
1 # 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
2 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
3 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
4 s vwxmk DesiredTemp Solltemperatur 50 B509 4 0E3200 1 - sd 1 d1c 1.0 °C - -
+58
View File
@@ -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;
}
+86
View File
@@ -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;
}
+48
View File
@@ -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;
}
+110
View File
@@ -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;
}
+310
View File
@@ -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;
}
+311
View File
@@ -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;
}
+60
View File
@@ -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;
}
+71
View File
@@ -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;
}
+21
View File
@@ -0,0 +1,21 @@
AM_CXXFLAGS = -fpic \
-Wall \
-Wextra
noinst_LIBRARIES = libutils.a
libutils_a_SOURCES = wqueue.h \
notify.h \
appl.cpp \
appl.h \
daemon.cpp \
daemon.h \
logger.cpp \
logger.h \
thread.cpp \
thread.h \
tcpsocket.cpp \
tcpsocket.h
distclean-local:
-rm -f Makefile.in
+221
View File
@@ -0,0 +1,221 @@
/*
* 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 "appl.h"
#include <iostream>
#include <iomanip>
#include <cstdlib>
Appl& Appl::Instance()
{
static Appl instance;
return instance;
}
Appl::~Appl()
{
m_args.clear();
m_params.clear();
}
void Appl::addArgs(const std::string argTxt, const int argNum)
{
m_argTxt = argTxt;
m_argNum = argNum;
}
void Appl::addItem(const char* name, Param param, const char* shortname,
const char* longname, const char* description,
Datatype datatype, Optiontype optiontype)
{
if (strlen(name) != 0)
m_params[name] = param;
if (strlen(longname) != 0) {
Arg arg;
arg.name = name;
arg.shortname = shortname;
arg.longname = longname;
arg.description = description;
arg.datatype = datatype;
arg.optiontype = optiontype;
m_args.push_back(arg);
}
}
void Appl::printArgs()
{
std::cerr << std::endl << "Usage:" << std::endl << " "
<< m_argv[0].substr(m_argv[0].find_last_of("/\\") + 1) << " [OPTIONS...]" ;
if (m_argTxt.size() != 0)
std::cerr << " " << m_argTxt;
std::cerr << std::endl << std::endl << "Options:" << std::endl << std::endl;
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
const char* c = (strlen(a_it->shortname) == 1) ? a_it->shortname : " ";
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
<< " | --" << a_it->longname
<< "\t" << a_it->description
<< std::endl;
}
std::cerr << std::endl;
}
bool Appl::parseArgs(int argc, char* argv[])
{
std::vector<std::string> _argv(argv, argv + argc);
m_argc = argc;
m_argv = _argv;
for (size_t i = 1; i < m_argc; i++) {
// find option with long format '--'
if (m_argv[i].rfind("--") == 0 && m_argv[i].size() > 2) {
// is next item an added argument?
if (i+1 < m_argc && m_argv[i+1].rfind("-", 0) == std::string::npos) {
if (checkArg(m_argv[i].substr(2), m_argv[i+1]) == false)
return false;
} else {
if (checkArg(m_argv[i].substr(2), "") == false)
return false;
}
// find option with short format '-'
} else if (m_argv[i].rfind("-") == 0 && m_argv[i].size() > 1) {
// walk through all characters
for (size_t j = 1; j < m_argv[i].size(); j++) {
// only last charater could have an argument
if (i+1 < m_argc && m_argv[i+1].rfind("-", 0) == std::string::npos
&& j+1 == m_argv[i].size()) {
if (checkArg(m_argv[i].substr(j,1), m_argv[i+1]) == false)
return false;
} else {
if (checkArg(m_argv[i].substr(j,1), "") == false)
return false;
}
}
}
}
// check args
if (m_argNum > 0) {
if (m_argc < (m_argNum + 1))
return false;
for (size_t i = 1; i < m_argc; i++) {
if (m_argv[i].rfind("-", 0) != std::string::npos) {
i++;
continue;
}
m_argValues.push_back(m_argv[i]);
}
if (m_argValues.size() < m_argNum)
return false;
}
return true;
}
void Appl::printSettings()
{
std::cerr << std::endl << "Settings:" << std::endl;
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
const char* c = (strlen(a_it->shortname) == 1) ? a_it->shortname : " ";
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
<< " | --" << a_it->longname
<< " = ";
if (a_it->datatype == type_bool) {
if (getParam<bool>(a_it->name) == true)
std::cerr << "yes" << std::endl;
else
std::cerr << "no" << std::endl;
}
else if (a_it->datatype == type_int) {
std::cerr << getParam<int>(a_it->name) << std::endl;
}
else if (a_it->datatype == type_long) {
std::cerr << getParam<long>(a_it->name) << std::endl;
}
else if (a_it->datatype == type_float) {
std::cerr << getParam<float>(a_it->name) << std::endl;
}
else if (a_it->datatype == type_string) {
std::cerr << getParam<const char*>(a_it->name) << std::endl;
}
}
std::cerr << std::endl;
}
bool Appl::checkArg(const std::string& name, const std::string& arg)
{
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
if (a_it->shortname == name || a_it->longname == name) {
if (a_it->optiontype == opt_mandatory && arg.size() == 0) {
std::cerr << std::endl << "option requires an argument '"
<< name << "'" << std::endl;
return false;
}
if ((a_it->optiontype == opt_optional && arg.size() != 0)
|| a_it->optiontype != opt_optional)
addParam(a_it->name, arg, a_it->datatype);
return true;
}
}
std::cerr << m_argv[0].substr(2) << ": Unknown Option -- " << name << std::endl;
return false;
}
void Appl::addParam(const char* name, const std::string arg, Datatype datatype)
{
switch (datatype) {
case type_bool:
m_params[name] = true;
break;
case type_int:
m_params[name] = strtol(arg.c_str(), NULL, 10);
break;
case type_long:
m_params[name] = strtol(arg.c_str(), NULL, 10);
break;
case type_float:
m_params[name] = static_cast<float>(strtod(arg.c_str(), NULL));
break;
case type_string:
m_params[name] = arg.c_str();
break;
default:
break;
}
}
+112
View File
@@ -0,0 +1,112 @@
/*
* 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 LIBCORE_APPL_H_
#define LIBCORE_APPL_H_
#include <string>
#include <cstring>
#include <map>
#include <vector>
class Appl
{
private:
struct Option;
public:
enum Datatype { type_none, type_bool, type_int, type_long, type_float, type_string };
enum Optiontype { opt_none, opt_optional, opt_mandatory };
union Param {
bool b;
int i;
long l;
float f;
const char* c;
Param() { memset(this, 0, sizeof(Param)); }
Param(bool _b) : b(_b) {}
Param(int _i) : i(_i) {}
Param(long _l) : l(_l) {}
Param(float _f) : f(_f) {}
Param(const char* _c) : c(_c) {}
};
template <typename T>
T getParam(const char* name)
{
p_it = m_params.find(name);
return (reinterpret_cast<T&>(p_it->second));
}
static Appl& Instance();
~Appl();
void addArgs(const std::string argTxt, const int argNum);
size_t numArg() const { return m_argValues.size(); }
std::string getArg(const int argNum) const { return m_argValues[argNum]; }
void addItem(const char* name, Param param, const char* shortname,
const char* longname, const char* description,
Datatype datatype, Optiontype optiontype);
void printArgs();
bool parseArgs(int argc, char* argv[]);
void printSettings();
private:
Appl() {}
Appl(const Appl&);
Appl& operator= (const Appl&);
struct Arg {
const char* name;
const char* shortname;
const char* longname;
const char* description;
Datatype datatype;
Optiontype optiontype;
};
size_t m_argc;
std::vector<std::string> m_argv;
std::vector<Arg> m_args;
std::vector<Arg>::const_iterator a_it;
std::map<const char*, Param> m_params;
std::map<const char*, Param>::iterator p_it;
std::string m_argTxt;
size_t m_argNum;
std::vector<std::string> m_argValues;
bool checkArg(const std::string& name, const std::string& arg);
void addParam(const char* name, Param param) { m_params[name] = param; }
void addParam(const char* name, const std::string arg, Datatype datatype);
};
#endif // LIBCORE_APPL_H_
+117
View File
@@ -0,0 +1,117 @@
/*
* 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 "daemon.h"
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
Daemon& Daemon::Instance()
{
static Daemon instance;
return instance;
}
void Daemon::run(const char* file)
{
m_status = false;
m_pidfile = file;
m_pidfd = 0;
pid_t pid;
// fork off the parent process
pid = fork();
if (pid < 0) {
std::cerr << "daemon fork() failed." << std::endl;
exit(EXIT_FAILURE);
}
// If we got a good PID, then we can exit the parent process
if (pid > 0) {
// printf("Child process created: %d\n", pid);
exit(EXIT_SUCCESS);
}
// At this point we are executing as the child process
// Set file permissions 750
umask(027);
// Create a new SID for the child process and
// detach the process from the parent (normally a shell)
if (setsid() < 0) {
std::cerr << "daemon setsid() failed." << std::endl;
exit(EXIT_FAILURE);
}
// Change the current working directory. This prevents the current
// directory from being locked; hence not being able to remove it.
if (chdir("/tmp") < 0) { //DAEMON_WORKDIR
std::cerr << "daemon chdir() failed." << std::endl;
exit(EXIT_FAILURE);
}
// Close stdin, stdout and stderr
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// write pidfile and try to lock it
if (pidfile_open() == false) {
std::cerr << "can't open pidfile: %s" << m_pidfile << std::endl;
exit(EXIT_FAILURE);
}
m_status = true;
}
bool Daemon::pidfile_open()
{
char pid[10];
m_pidfd = open(m_pidfile, O_RDWR|O_CREAT, 0600);
if (m_pidfd < 0)
return false;
if (lockf(m_pidfd, F_TLOCK, 0) < 0)
return false;
sprintf(pid, "%d\n", getpid());
if (write(m_pidfd, pid, strlen(pid)) < 0)
return false;
return true;
}
bool Daemon::pidfile_close()
{
if (close(m_pidfd) < 0)
return false;
if (remove(m_pidfile) < 0)
return false;
return true;
}
+48
View File
@@ -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/.
*/
#ifndef LIBCORE_DAEMON_H_
#define LIBCORE_DAEMON_H_
class Daemon
{
public:
static Daemon& Instance();
~Daemon() {}
void run(const char* file);
void stop() { pidfile_close(); }
bool status() { return m_status; }
private:
bool m_status;
const char* m_pidfile;
int m_pidfd;
Daemon() {}
Daemon(const Daemon&);
Daemon& operator= (const Daemon&);
bool pidfile_open();
bool pidfile_close();
};
#endif // LIBCORE_DAEMON_H_
+236
View File
@@ -0,0 +1,236 @@
/*
* 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 "logger.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <sys/time.h>
#include <unistd.h>
static const char* AreaNames[Size_of_Areas] = { "bas", "net", "bus" };
static const char* LevelNames[Size_of_Level] = { "error", "event", "trace", "debug" };
int calcAreas(const std::string areas)
{
int m_areas = 0;
// prepare data
std::string token;
std::istringstream stream(areas);
std::vector<std::string> cmd;
while (std::getline(stream, token, ',') != 0)
cmd.push_back(token);
for (std::vector<std::string>::iterator it = cmd.begin() ; it != cmd.end(); ++it)
for (int i = 0; i < Size_of_Areas; i++) {
if (strcasecmp("ALL", it->c_str()) == 0)
return (pow(2, (int)Size_of_Areas) - 1);
if (strcasecmp(AreaNames[i], it->c_str()) == 0)
m_areas += pow(2, i);
}
return m_areas;
}
int calcLevel(const std::string level)
{
int m_level = event;
for (int i = 0; i < Size_of_Level; i++)
if (strcasecmp(LevelNames[i], level.c_str()) == 0)
return i;
return m_level;
}
LogMessage::LogMessage(const int area, const int level, const std::string text, const Status status)
: m_area(area), m_level(level), m_text(text), m_status(status)
{
char time[24];
struct timeval tv;
struct timezone tz;
struct tm* tm;
gettimeofday(&tv, &tz);
tm = localtime(&tv.tv_sec);
sprintf(&time[0], "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec/1000);
m_time = std::string(time);
}
void LogSink::addMessage(const LogMessage& message)
{
LogMessage* tmp = new LogMessage(LogMessage(message));
m_queue.add((tmp));
}
void* LogSink::run()
{
while (1) {
LogMessage* message = m_queue.remove();
if (message->getStatus() == LogMessage::End) {
delete message;
while (m_queue.size() == true) {
LogMessage* message = m_queue.remove();
write(*message);
delete message;
}
return NULL;
}
write(*message);
delete message;
}
return NULL;
}
int LogConsole::m_numInstance = 0;
void LogConsole::write(const LogMessage& message) const
{
std::cout << message.getTime() << " ["
<< AreaNames[(int)log2(message.getArea())] << " "
<< LevelNames[message.getLevel()] << "] "
<< message.getText() << std::endl;
}
int LogFile::m_numInstance = 0;
void LogFile::write(const LogMessage& message) const
{
std::fstream file(m_filename.c_str(), std::ios::out | std::ios::app);
if (file.is_open() == true) {
file << message.getTime() << " ["
<< AreaNames[(int)log2(message.getArea())] << " "
<< LevelNames[message.getLevel()] << "] "
<< message.getText() << std::endl;
file.close();
}
}
LogInstance& LogInstance::Instance()
{
static LogInstance instance;
return (instance);
}
LogInstance::~LogInstance()
{
while (m_sinks.empty() == false)
*this -= *(m_sinks.begin());
}
LogInstance& LogInstance::operator+= (LogSink* sink)
{
sinkCI_t itEnd = m_sinks.end();
sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink);
if (it == itEnd)
m_sinks.push_back(sink);
return (*this);
}
LogInstance& LogInstance::operator-= (const LogSink* sink)
{
sinkCI_t itEnd = m_sinks.end();
sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink);
if (it == itEnd)
return (*this);
m_sinks.erase(it);
delete (sink);
return (*this);
}
void LogInstance::log(const int area, const int level, const std::string& data, ...)
{
if (m_running == true) {
char* tmp;
va_list ap;
va_start(ap, data);
if (vasprintf(&tmp, data.c_str(), ap) != -1) {
std::string buffer(tmp);
m_messages.add(new LogMessage(LogMessage(area, level, buffer, LogMessage::Run)));
}
va_end(ap);
free(tmp);
}
}
void* LogInstance::run()
{
m_running = true;
while (m_running == true) {
LogMessage* message = m_messages.remove();
sinkCI_t iter = m_sinks.begin();
for (; iter != m_sinks.end(); ++iter) {
if (*iter != 0) {
if (((*iter)->getAreas() & message->getArea()
&& (*iter)->getLevel() >= message->getLevel())
&& message->getStatus() == LogMessage::Run) {
(*iter)->addMessage(*message);
} else if (message->getStatus() == LogMessage::End) {
(*iter)->addMessage(*message);
m_running = false;
}
}
}
delete message;
}
return NULL;
}
void LogInstance::stop()
{
m_messages.add(new LogMessage(LogMessage(bas, error, "", LogMessage::End)));
usleep(100000);
}
+181
View File
@@ -0,0 +1,181 @@
/*
* 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 LIBCORE_LOGGER_H_
#define LIBCORE_LOGGER_H_
#include "wqueue.h"
#include "thread.h"
#include <string>
#include <functional>
#include <algorithm>
#include <vector>
#include <cstdarg>
enum Areas { bas=1, net=2, bus=4, all=7, Size_of_Areas=3 };
enum Level { error=0, event, trace, debug, Size_of_Level };
int calcAreas(const std::string areas);
int calcLevel(const std::string level);
class LogMessage
{
public:
enum Status { Run, End };
LogMessage(const int area, const int level, const std::string text, const Status status);
~LogMessage() {}
LogMessage(const LogMessage& src)
: m_area(src.m_area), m_level(src.m_level), m_text(src.m_text),
m_status(src.m_status), m_time(src.m_time) {}
void operator= (const LogMessage& src)
{ m_area = src.m_area; m_level = src.m_level; m_text = src.m_text;
m_status = src.m_status; m_time = src.m_time; }
int getArea() const { return (m_area); }
int getLevel() const { return(m_level); }
std::string getText() const { return (m_text.c_str()); }
Status getStatus() const { return (m_status); }
std::string getTime() const { return (m_time.c_str()); }
private:
int m_area;
int m_level;
std::string m_text;
Status m_status;
std::string m_time;
};
enum Type { Console, Logfile };
class LogSink : public Thread
{
public:
LogSink(const int areas, const int level, const Type type, const char* name)
: m_areas(areas), m_level(level), m_type(type), m_name(name) {}
virtual ~LogSink() {}
void addMessage(const LogMessage& message);
void* run();
int getAreas() const { return (m_areas); }
void setAreas(const int& areas) { m_areas = areas; }
int getLevel() const { return (m_level); }
void setLevel(const int& level) { m_level = level; }
Type getType() const { return (m_type); }
const char* getName() const { return (m_name.c_str()); }
protected:
WQueue<LogMessage*> m_queue;
private:
int m_areas;
int m_level;
Type m_type;
std::string m_name;
virtual void write(const LogMessage& message) const = 0;
};
class LogConsole : public LogSink
{
public:
LogConsole(const int areas, const int level, const char* name)
: LogSink(areas, level, Console, name), m_instance(++m_numInstance)
{ this->start(name); }
~LogConsole() {}
private:
const int m_instance;
static int m_numInstance;
void write(const LogMessage& message) const;
};
class LogFile : public LogSink
{
public:
LogFile(const int areas, const int level, const char* name, const char* filename)
: LogSink(areas, level, Logfile, name), m_filename(filename), m_instance(++m_numInstance)
{ this->start(name); }
~LogFile() {}
private:
std::string m_filename;
const int m_instance;
static int m_numInstance;
void write(const LogMessage& message) const;
};
class LogInstance : public Thread
{
public:
static LogInstance& Instance();
~LogInstance();
LogInstance& operator+= (LogSink* sink);
LogInstance& operator-= (const LogSink* sink);
void log(const int area, const int level, const std::string& text, ...);
int getNumberOfSinks() const { return(m_sinks.size()); }
LogSink* getSink(const int Index) const { return(m_sinks[Index]); }
void* run();
void stop();
private:
LogInstance() {}
LogInstance(const LogInstance&);
LogInstance& operator= (const LogInstance&);
typedef std::vector<LogSink*> sink_t;
typedef std::vector<LogSink*>::iterator sinkCI_t;
sink_t m_sinks;
WQueue<LogMessage*> m_messages;
bool m_running;
};
#endif // LIBCORE_LOGGER_H_
+56
View File
@@ -0,0 +1,56 @@
/*
* 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 LIBCORE_NOTIFY_H_
#define LIBCORE_NOTIFY_H_
#include <unistd.h>
#include <fcntl.h>
class Notify
{
public:
Notify()
{
int pipefd[2];
int ret = pipe(pipefd);
if (ret == 0) {
m_recvfd = pipefd[0];
m_sendfd = pipefd[1];
fcntl(m_sendfd, F_SETFL, O_NONBLOCK);
}
}
virtual ~Notify() { close(m_sendfd); close(m_recvfd); }
int notifyFD() const { return m_recvfd; }
int notify() const { return write(m_sendfd,"1",1); }
private:
int m_recvfd;
int m_sendfd;
};
#endif // LIBCORE_NOTIFY_H_
+133
View File
@@ -0,0 +1,133 @@
/*
* 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 "tcpsocket.h"
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
TCPSocket::TCPSocket(int sfd, struct sockaddr_in* address) : m_sfd(sfd)
{
char ip[17];
inet_ntop(AF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip)-1);
m_ip = ip;
m_port = ntohs(address->sin_port);
}
bool TCPSocket::isValid()
{
if (fcntl(m_sfd, F_GETFL) == -1)
return false;
else
return true;
}
TCPSocket* TCPClient::connect(const std::string& server, const int& port)
{
struct sockaddr_in address;
int ret;
memset((char*) &address, 0, sizeof(address));
if (inet_addr(server.c_str()) == INADDR_NONE) {
struct hostent* he;
he = gethostbyname(server.c_str());
if (he == NULL)
return NULL;
memcpy(&address.sin_addr, he->h_addr_list[0], he->h_length);
} else {
ret = inet_aton(server.c_str(), &address.sin_addr);
if (ret == 0)
return NULL;
}
address.sin_family = AF_INET;
address.sin_port = htons(port);
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
return NULL;
ret = ::connect(sfd, (struct sockaddr*) &address, sizeof(address));
if (ret < 0)
return NULL;
return new TCPSocket(sfd, &address);
}
int TCPServer::start()
{
if (m_listening == true)
return 0;
m_lfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(m_port);
if (m_address.size() > 0)
inet_pton(AF_INET, m_address.c_str(), &(address.sin_addr));
else
address.sin_addr.s_addr = INADDR_ANY;
int optval = 1;
setsockopt(m_lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
int result = bind(m_lfd, (struct sockaddr*) &address, sizeof(address));
if (result != 0)
return result;
result = listen(m_lfd, 5);
if (result != 0)
return result;
m_listening = true;
return result;
}
TCPSocket* TCPServer::newSocket()
{
if (m_listening == false)
return NULL;
struct sockaddr_in address;
socklen_t len = sizeof(address);
memset(&address, 0, sizeof(address));
int sfd = accept(m_lfd, (struct sockaddr*) &address, &len);
if (sfd < 0)
return NULL;
return new TCPSocket(sfd, &address);
}
+88
View File
@@ -0,0 +1,88 @@
/*
* 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 LIBCORE_TCPSOCKET_H_
#define LIBCORE_TCPSOCKET_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string>
class TCPSocket
{
public:
friend class TCPClient;
friend class TCPServer;
~TCPSocket() { close(m_sfd); }
ssize_t recv(char* buffer, size_t len) { return read(m_sfd, buffer, len); }
ssize_t send(const char* buffer, size_t len) { return write(m_sfd, buffer, len); }
int getPort() const { return m_port; }
std::string getIP() const { return m_ip; }
int getFD() const { return m_sfd; }
bool isValid();
private:
int m_sfd;
int m_port;
std::string m_ip;
TCPSocket(int sfd, struct sockaddr_in* address);
};
class TCPClient
{
public:
TCPSocket* connect(const std::string& server, const int& port);
private:
};
class TCPServer
{
public:
TCPServer(const int port, const std::string address)
: m_lfd(0), m_port(port), m_address(address), m_listening(false) {}
~TCPServer() { if (m_lfd > 0) {close(m_lfd);} }
int start();
TCPSocket* newSocket();
int getFD() const { return m_lfd; }
private:
int m_lfd;
int m_port;
std::string m_address;
bool m_listening;
};
#endif // LIBCORE_TCPSOCKET_H_
+78
View File
@@ -0,0 +1,78 @@
/*
* 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 "thread.h"
static void* runThread(void* arg)
{
return ((Thread *)arg)->run();
}
Thread::~Thread()
{
if (m_running == true && m_detached == false)
pthread_detach(m_threadid);
if (m_running == true)
pthread_cancel(m_threadid);
}
int Thread::start(const char* name)
{
int result = pthread_create(&m_threadid, NULL, runThread, this);
if (result == 0) {
pthread_setname_np(m_threadid, name);
m_running = true;
}
return result;
}
int Thread::join()
{
int result = -1;
if (m_running == true) {
result = pthread_join(m_threadid, NULL);
if (result == 0)
m_detached = false;
}
return result;
}
int Thread::detach()
{
int result = -1;
if (m_running == true && m_detached == false) {
result = pthread_detach(m_threadid);
if (result == 0)
m_detached = true;
}
return result;
}
+46
View File
@@ -0,0 +1,46 @@
/*
* 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 LIBCORE_THREAD_H_
#define LIBCORE_THREAD_H_
#include <pthread.h>
class Thread
{
public:
Thread() : m_threadid(0), m_running(false), m_detached(false) {}
virtual ~Thread();
int start(const char* name);
int join();
int detach();
pthread_t self() {return m_threadid; }
virtual void* run() = 0;
private:
pthread_t m_threadid;
bool m_running;
bool m_detached;
};
#endif // LIBCORE_THREAD_H_
+85
View File
@@ -0,0 +1,85 @@
/*
* 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 LIBCORE_WQUEUE_H_
#define LIBCORE_WQUEUE_H_
#include <list>
#include <pthread.h>
template <typename T> class WQueue
{
public:
WQueue()
{
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}
~WQueue()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
void add(T item)
{
pthread_mutex_lock(&m_mutex);
m_queue.push_back(item);
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
T remove()
{
pthread_mutex_lock(&m_mutex);
while (m_queue.size() == 0)
pthread_cond_wait(&m_cond, &m_mutex);
T item = m_queue.front();
m_queue.pop_front();
pthread_mutex_unlock(&m_mutex);
return item;
}
int size()
{
pthread_mutex_lock(&m_mutex);
int size = m_queue.size();
pthread_mutex_unlock(&m_mutex);
return size;
}
private:
std::list<T> m_queue;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
#endif // LIBCORE_WQUEUE_H_