Merge pull request #18 from john30/master; first version supporting get, set, and cyc again.

This commit is contained in:
Roland Jax
2014-12-07 12:00:03 +01:00
parent 4bd18de1e5
commit 3b3a5f2e07
49 changed files with 2536 additions and 4884 deletions
Regular → Executable
+4 -11
View File
@@ -1,6 +1,7 @@
AM_CXXFLAGS = -fpic \
-Wall \
-Wextra
-Wextra \
-I$(top_srcdir)/src/lib/utils
noinst_LIBRARIES = libebus.a
@@ -12,16 +13,8 @@ libebus_a_SOURCES = result.cpp \
data.h \
port.cpp \
port.h \
command.cpp \
command.h \
commands.cpp \
commands.h \
configfile.cpp \
configfile.h \
decode.cpp \
decode.h \
encode.cpp \
encode.h
message.cpp \
message.h
distclean-local:
-rm -f Makefile.in
-338
View File
@@ -1,338 +0,0 @@
/*
* 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>
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;
}
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 string& part, const string& position,
const string& type, const string& factor)
{
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 string& data, const string& position,
const string& type, const string& factor)
{
ostringstream result, value;
Decode* help = NULL;
// prepare position
string token;
istringstream stream(position);
vector<int> pos;
while (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 string& data, const string& type,
const string& factor)
{
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;
}
-64
View File
@@ -1,64 +0,0 @@
/*
* 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>
using namespace std;
typedef vector<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, string data)
: m_index(index), m_command(command), m_data(data) {}
cmd_t getCommand() const { return m_command; }
void setData(const string& data) { m_data = data; }
string getData() const { return m_data; }
string calcData();
string calcResult(const cmd_t& cmd);
private:
int m_index;
cmd_t m_command;
string m_data;
string m_result;
string m_error;
void calcSub(const string& part, const string& position,
const string& type, const string& factor);
void decode(const string& data, const string& position,
const string& type, const string& factor);
void encode(const string& data, const string& type,
const string& factor);
};
#endif // LIBEBUS_COMMAND_H_
-260
View File
@@ -1,260 +0,0 @@
/*
* 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>
using namespace std;
Commands::~Commands()
{
for (mapCI_t iter = m_pollDB.begin(); iter != m_pollDB.end(); ++iter)
delete iter->second;
m_pollDB.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_pollDB.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);
cout << endl;
}
}
int Commands::findCommand(const string& data) const
{
// no commands definend
if (m_cmdDB.size() == 0)
return -2;
// preapre string for searching command
string token;
istringstream isstr(data);
vector<string> cmd;
// split stream
while (getline(isstr, token, ' ') != 0)
cmd.push_back(token);
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;
}
string Commands::getBusCommand(const int index) const
{
cmd_t command = m_cmdDB.at(index);
string cmd;
stringstream sstr;
if (strcasecmp(command[0].c_str(), "C") == 0)
cmd += command[4]; // QQ
cmd += command[5]; // ZZ
cmd += command[6]; // PBSB
sstr << setw(2) << hex << setfill('0') << command[7];
cmd += sstr.str(); // NN
cmd += command[8]; // Dx
return cmd;
}
int Commands::storeCycData(const 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
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++) {
string command = getBusCommand(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;
}
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::nextPollCommand()
{
size_t index = 0;
m_pollIndex++;
if (m_pollIndex == m_pollDB.size())
m_pollIndex = 0;
mapCI_t iter = m_pollDB.begin();
for (; iter != m_pollDB.end(); iter++, index++)
if (index == m_pollIndex)
return iter->first;
return -1;
}
void Commands::storePollData(const string& data) const
{
// prepare string for searching command
string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2));
mapCI_t iter = m_pollDB.begin();
// walk through commands
for (; iter != m_pollDB.end(); iter++) {
string command = getBusCommand(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);
}
}
string Commands::getPollData(const int index) const
{
mapCI_t iter = m_pollDB.find(index);
if (iter != m_pollDB.end())
return iter->second->getData();
else
return "";
}
void Commands::storeScanData(const string& data)
{
vector<string>::const_iterator iter = m_scanDB.begin();
bool found = false;
// walk through scan data
for (; iter != m_scanDB.end(); iter++)
if (data == (*iter))
found = true;
if (found == false)
m_scanDB.push_back(data);
}
void Commands::printCommand(const cmd_t& command) const
{
if (command.size() == 0)
return;
for (cmdCI_t i = command.begin(); i != command.end(); i++)
cout << *i << ';';
}
-81
View File
@@ -1,81 +0,0 @@
/*
* 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>
using namespace std;
typedef vector<cmd_t> cmdDB_t;
typedef cmdDB_t::const_iterator cmdDBCI_t;
typedef map<int, Command*> map_t;
typedef map_t::const_iterator mapCI_t;
typedef pair<int, Command*> pair_t;
class Commands
{
public:
Commands() : m_pollIndex(-1) {}
~Commands();
void addCommand(const cmd_t& command);
void printCommands() const;
size_t sizeCmdDB() const { return m_cmdDB.size(); }
size_t sizeCycDB() const { return m_cycDB.size(); }
size_t sizePollDB() const { return m_pollDB.size(); }
size_t sizeScanDB() const { return m_scanDB.size(); }
cmd_t const& operator[](const size_t& index) const { return m_cmdDB[index]; }
int findCommand(const string& data) const;
string getCmdType(const int index) const { return string(m_cmdDB.at(index)[0]); }
string getBusCommand(const int index) const;
int storeCycData(const string& data) const;
string getCycData(int index) const;
int nextPollCommand();
void storePollData(const string& data) const;
string getPollData(const int index) const;
void storeScanData(const string& data);
string getScanData(const int index) const { return m_scanDB[index]; }
private:
cmdDB_t m_cmdDB;
map_t m_cycDB;
map_t m_pollDB;
size_t m_pollIndex;
vector<string> m_scanDB;
void printCommand(const cmd_t& command) const;
};
#endif // LIBEBUS_COMMANDS_H_
-121
View File
@@ -1,121 +0,0 @@
/*
* 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>
using namespace std;
void ConfigFileCSV::parse(istream& is, Commands& commands)
{
string line;
// read lines
while (getline(is, line) != 0) {
cmd_t row;
string column;
istringstream isstr(line);
// walk through columns
while (getline(isstr, column, ';') != 0)
row.push_back(column);
// skip empty and commented rows
if (row.empty() == true || row[0][0] == '#')
continue;
commands.addCommand(row);
}
};
ConfigCommands::ConfigCommands(const 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 ft_csv:
m_configfile = new ConfigFileCSV();
m_extension = "csv";
break;
};
};
Commands* ConfigCommands::getCommands()
{
Commands* commands = new Commands();
vector<string>::const_iterator i = m_files.begin();
for(; i != m_files.end(); i++) {
fstream file((*i).c_str(), ios::in);
if(file.is_open() == true) {
m_configfile->parse(file, *commands);
file.close();
}
}
return commands;
};
void ConfigCommands::addFiles(const string path, const 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) {
string fn = d->d_name;
if (fn != "." && fn != "..") {
const string p = path + "/" + d->d_name;
addFiles(p, extension);
}
} else if (d->d_type == DT_REG) {
string fn = d->d_name;
if (fn.find(extension, (fn.length() - extension.length())) != string::npos) {
const string p = path + "/" + d->d_name;
m_files.push_back(p);
}
}
d = readdir(dir);
}
closedir(dir);
};
-132
View File
@@ -1,132 +0,0 @@
/*
* 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>
using namespace std;
/** \file configfile.h */
/** available file endings / types. */
enum FileType {
ft_csv /*!< CSV */
};
/**
* @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(istream& is, Commands& commands) = 0;
};
/**
* @brief derived 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(istream& is, Commands& commands);
};
/**
* @brief class to parse configuration files and store into commands instance.
*/
class ConfigCommands
{
public:
/**
* @brief set file type and add recursive files from given path.
* @param path to configuration files.
* @param type to parse.
*/
ConfigCommands(const string path, const FileType type);
/**
* @brief destructor.
*/
~ConfigCommands() { delete m_configfile; }
/**
* @brief setter for file type.
* @param type 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 */
string m_path;
/** valid file extension */
string m_extension;
/** vector of configuration files */
vector<string> m_files;
/**
* @brief parse path for given file extension.
* @param path to configuration files.
* @param extension with file type.
*/
void addFiles(const string path, const string extension);
};
#endif // LIBEBUS_CONFIGFILE_H_
+284 -141
View File
@@ -38,6 +38,8 @@ static const dataType_t dataTypes[] = {
{"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x01 - Sun=0x07))
{"HDA", 24, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) // TODO remove duplicate of BDA
{"BTI", 24, bt_tim, BCD|REV, 0, 8, 8, 0, 0}, // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
{"HTI", 24, bt_tim, 0, 0, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
{"VTI", 24, bt_tim, REV, 0x63, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
{"HTM", 16, bt_tim, 0, 0, 5, 5, 0, 0}, // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
{"TTM", 8, bt_tim, 0, 0x90, 5, 5, 0, 0}, // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
{"BDY", 8, bt_num, DAY|LST, 0x07, 0, 6, 1, 0}, // weekday, "Mon" - "Sun" (0x00 - 0x06) [ebus type]
@@ -68,7 +70,6 @@ static const dataType_t dataTypes[] = {
/** the week day names. */
static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
#define FIELD_SEPARATOR ';'
#define VALUE_SEPARATOR ','
#define LENGTH_SEPARATOR ':'
#define NULL_VALUE "-"
@@ -80,12 +81,12 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
unsigned int ret = strtoul(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_ARG; // invalid value
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (ret < minValue || ret > maxValue) {
result = RESULT_ERR_INVALID_ARG; // invalid value
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL)
@@ -95,23 +96,50 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
return ret;
}
void printErrorPos(vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, char separator)
{
cout << "Erroneous item is here:" << endl;
bool first = true;
int cnt = 0;
if (pos > begin)
pos--;
while (begin != end) {
if (first == true)
first = false;
else {
cout << separator;
if (begin <= pos) {
cnt++;
}
}
if (begin < pos) {
cnt += (*begin).length();
}
cout << (*begin++);
}
cout << endl;
cout << setw(cnt) << " " << setw(0) << "^" << endl;
}
result_t DataField::create(vector<string>::iterator& it,
const vector<string>::iterator end,
const map< string, DataField*> templates,
DataFieldTemplates* templates,
DataField*& returnField, const bool isSetMessage,
const unsigned char dstAddress)
{
vector<SingleDataField*> fields;
string firstName, firstComment;
result_t result = RESULT_OK;
while (it != end && result == RESULT_OK) {
if (it == end)
return RESULT_ERR_EOF;
do {
string unit, comment;
PartType partType;
unsigned int divisor = 0;
const bool isTemplate = dstAddress == SYN;
string token;
if (it == end)
break;
// name;part;type[:len][;[divisor|values][;[unit][;[comment]]]]
const string name = *it++;
@@ -126,10 +154,7 @@ result_t DataField::create(vector<string>::iterator& it,
firstName = name;
firstComment = comment;
}
if (isTemplate == false && strcasecmp(partStr, "I") == 0) {
partType = pt_masterDataID;
}
else if (dstAddress == BROADCAST || isMaster(dstAddress)
if (dstAddress == BROADCAST || isMaster(dstAddress) == true
|| (isTemplate == false && isSetMessage == true && partStr[0] == 0)
|| strcasecmp(partStr, "M") == 0) { // master data
partType = pt_masterData;
@@ -142,14 +167,14 @@ result_t DataField::create(vector<string>::iterator& it,
partType = pt_any;
}
else {
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_INVALID_PART;
break;
}
string typeStr = *it++;
if (typeStr.empty() == true) {
if (name.empty() == false || partStr[0] != 0)
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_MISSING_TYPE;
break;
}
@@ -157,11 +182,8 @@ result_t DataField::create(vector<string>::iterator& it,
if (it != end) {
string divisorStr = *it++;
if (divisorStr.empty() == false) {
if (divisorStr.find('=') == string::npos) {
if (divisorStr.find('=') == string::npos)
divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result);
if (result != RESULT_OK)
break;
}
else {
istringstream stream(divisorStr);
while (getline(stream, token, VALUE_SEPARATOR) != 0) {
@@ -169,15 +191,15 @@ result_t DataField::create(vector<string>::iterator& it,
char* strEnd = NULL;
unsigned int id = strtoul(str, &strEnd, 10);
if (strEnd == NULL || strEnd == str || *strEnd != '=') {
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_INVALID_LIST;
break;
}
values[id] = string(strEnd + 1);
}
if (result != RESULT_OK)
break;
}
if (result != RESULT_OK)
break;
}
}
@@ -202,22 +224,21 @@ result_t DataField::create(vector<string>::iterator& it,
if (pos == string::npos) {
length = 0;
// check for reference(s) to templates
if (templates.empty() == false) {
if (templates != NULL) {
istringstream stream(typeStr);
bool found = false;
string lengthStr;
while (getline(stream, token, VALUE_SEPARATOR) != 0) {
map<string, DataField*>::const_iterator ref = templates.find(token);
if (ref == templates.end()) {
while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) {
DataField* templ = templates->get(token);
if (templ == NULL) {
if (found == false)
break; // fallback to direct definition
result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition
break;
result = RESULT_ERR_NOTFOUND; // cannot mix reference and direct definition
}
else {
found = true;
result = templ->derive("", "", "", partType, divisor, values, fields);
}
found = true;
result = ref->second->derive(name, comment, unit, partType, divisor, values, fields);
if (result != RESULT_OK)
break;
}
if (result != RESULT_OK)
break;
@@ -246,7 +267,7 @@ result_t DataField::create(vector<string>::iterator& it,
bitCount = 1; // default count: 1 bit
}
else if (length > bitCount) {
result = RESULT_ERR_INVALID_ARG; // invalid length
result = RESULT_ERR_OUT_OF_RANGE; // invalid length
break;
}
else {
@@ -261,7 +282,7 @@ result_t DataField::create(vector<string>::iterator& it,
useLength = length;
}
else {
result = RESULT_ERR_INVALID_ARG; // invalid length
result = RESULT_ERR_OUT_OF_RANGE; // invalid length
break;
}
}
@@ -293,7 +314,7 @@ result_t DataField::create(vector<string>::iterator& it,
}
if (values.begin()->first < dataType.minValueOrLength
|| values.rbegin()->first > dataType.maxValueOrLength) {
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_OUT_OF_RANGE;
break;
}
@@ -305,14 +326,16 @@ result_t DataField::create(vector<string>::iterator& it,
if (add != NULL)
fields.push_back(add);
else if (result == RESULT_OK)
result = RESULT_ERR_INVALID_ARG; // type not found
}
result = RESULT_ERR_NOTFOUND; // type not found
} while (it != end && result == RESULT_OK);
if (fields.empty() == true || result != RESULT_OK) {
while (fields.empty() == false) {
while (fields.empty() == false) { // cleanup already created fields
delete fields.back();
fields.pop_back();
}
return result == RESULT_OK ? RESULT_ERR_INVALID_ARG :result;
return result == RESULT_OK ? RESULT_ERR_INVALID_ARG : result;
}
if (fields.size() == 1)
@@ -324,37 +347,49 @@ result_t DataField::create(vector<string>::iterator& it,
}
result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
ostringstream& output,
void SingleDataField::dump(ostream& output)
{
output << m_name << FIELD_SEPARATOR;
if (m_partType == pt_masterData)
output << "m";
else if (m_partType == pt_slaveData)
output << "s";
output << FIELD_SEPARATOR << m_dataType.name;
}
result_t SingleDataField::read(const PartType partType,
SymbolString& data, unsigned char offset,
ostringstream& output, bool leadingSeparator,
bool verbose, char separator)
{
SymbolString& input = m_partType != pt_slaveData ? masterData : slaveData;
unsigned char offset;
if (partType != m_partType)
return RESULT_OK;
switch (m_partType)
{
case pt_masterData:
case pt_masterDataID:
offset = 5 + masterOffset; // skip QQ ZZ PB SB NN
offset += 5; // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
offset = 1 + slaveOffset; // skip NN
offset += 1; // skip NN
break;
default:
return RESULT_ERR_INVALID_ARG; // invalid part type
return RESULT_ERR_INVALID_PART;
}
if (isIgnored() == true) {
if (offset + m_length > input.size()) {
return RESULT_ERR_INVALID_ARG;
if (offset + m_length > data.size()) {
return RESULT_ERR_INVALID_POS;
}
return RESULT_OK;
}
if (leadingSeparator == true)
output << separator;
if (verbose == true)
output << m_name << "=";
result_t result = readSymbols(input, offset, output);
result_t result = readSymbols(data, offset, output);
if (result != RESULT_OK)
return result;
@@ -367,25 +402,24 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff
}
result_t SingleDataField::write(istringstream& input,
SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
char separator)
const PartType partType, SymbolString& data,
unsigned char offset, char separator)
{
SymbolString& output = m_partType != pt_slaveData ? masterData : slaveData;
unsigned char offset;
if (partType != m_partType)
return RESULT_OK;
switch (m_partType)
{
case pt_masterData:
case pt_masterDataID:
offset = 5 + masterOffset; // skip QQ ZZ PB SB NN
offset += 5; // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
offset = 1 + slaveOffset; // skip NN
offset += 1; // skip NN
break;
default:
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_INVALID_PART;
}
return writeSymbols(input, offset, output);
return writeSymbols(input, offset, data);
}
@@ -395,7 +429,7 @@ result_t StringDataField::derive(string name, string comment,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (divisor != 0 || values.empty() == false)
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field
if (name.empty() == true)
@@ -410,6 +444,15 @@ result_t StringDataField::derive(string name, string comment,
return RESULT_OK;
}
void StringDataField::dump(ostream& output)
{
SingleDataField::dump(output);
if ((m_dataType.flags & ADJ) != 0)
output << ":" << static_cast<unsigned>(m_length);
output << FIELD_SEPARATOR << FIELD_SEPARATOR; // no value list, no divisor
output << m_unit << FIELD_SEPARATOR << m_comment << FIELD_SEPARATOR;
}
result_t StringDataField::readSymbols(SymbolString& input,
unsigned char baseOffset, ostringstream& output)
{
@@ -418,7 +461,7 @@ result_t StringDataField::readSymbols(SymbolString& input,
unsigned char ch, last = 0;
if (baseOffset + m_length > input.size()) {
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_INVALID_POS;
}
if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first)
@@ -430,9 +473,9 @@ result_t StringDataField::readSymbols(SymbolString& input,
if (m_length == 4 && i == 2 && m_dataType.type == bt_dat)
continue; // skip weekday in between
ch = input[baseOffset + offset];
if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat || (m_dataType.type == bt_tim && m_length > 2)) {
if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) {
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09)
return RESULT_ERR_INVALID_ARG; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
ch = (ch >> 4) * 10 + (ch & 0x0f);
}
switch (m_dataType.type)
@@ -447,11 +490,21 @@ result_t StringDataField::readSymbols(SymbolString& input,
if (i + 1 == m_length)
output << (2000 + ch);
else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12))
return RESULT_ERR_INVALID_ARG; // invalid date
return RESULT_ERR_OUT_OF_RANGE; // invalid date
else
output << setw(2) << setfill('0') << static_cast<unsigned>(ch) << ".";
break;
case bt_tim:
if (m_dataType.replacement != 0 && ch == m_dataType.replacement) {
if (m_length == 1) { // truncated time
output << NULL_VALUE << ":" << NULL_VALUE;
break;
}
if (i > 0)
output << ":";
output << NULL_VALUE;
break;
}
if (m_length == 1) { // truncated time
if (i == 0) {
ch /= 6; // hours
@@ -461,8 +514,8 @@ result_t StringDataField::readSymbols(SymbolString& input,
else
ch = (ch % 6) * 10; // minutes
}
if ((i == 0 && ch > 24) || (i > 0 && (ch > 59 || ( last == 24 && ch > 0) )))
return RESULT_ERR_INVALID_ARG; // invalid time
if ((i == 0 && ch > 24) || (i > 0 && (ch > 59 || (last == 24 && ch > 0) )))
return RESULT_ERR_OUT_OF_RANGE; // invalid time
if (i > 0)
output << ":";
output << setw(2) << setfill('0') << static_cast<unsigned>(ch);
@@ -512,10 +565,10 @@ result_t StringDataField::writeSymbols(istringstream& input,
token.clear();
token.push_back(input.get());
if (input.eof() == true)
return RESULT_ERR_INVALID_ARG; // too short hex value
return RESULT_ERR_INVALID_NUM; // too short hex value
token.push_back(input.get());
if (input.eof() == true)
return RESULT_ERR_INVALID_ARG; // too short hex value
return RESULT_ERR_INVALID_NUM; // too short hex value
value = parseInt(token.c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK)
@@ -526,7 +579,7 @@ result_t StringDataField::writeSymbols(istringstream& input,
if (m_length == 4 && i == 2)
continue; // skip weekday in between
if (input.eof() == true || getline(input, token, '.') == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
return RESULT_ERR_EOF; // incomplete
value = parseInt(token.c_str(), 10, 0, 2099, result);
if (result != RESULT_OK)
return result; // invalid date part
@@ -541,7 +594,7 @@ result_t StringDataField::writeSymbols(istringstream& input,
t.tm_year = (value < 100 ? value + 2000 : value) - 1900;
t.tm_isdst = 0; // automatic
if (mktime(&t) < 0)
return RESULT_ERR_INVALID_ARG; // invalid date
return RESULT_ERR_INVALID_NUM; // invalid date
unsigned char daysSinceSunday = (unsigned char)t.tm_wday; // Sun=0
if ((m_dataType.flags & BCD) != 0)
output[baseOffset + offset - incr] = (6+daysSinceSunday) % 7; // Sun=0x06
@@ -551,18 +604,32 @@ result_t StringDataField::writeSymbols(istringstream& input,
if (value >= 2000)
value -= 2000;
else if (value > 99)
return RESULT_ERR_INVALID_ARG; // invalid year
return RESULT_ERR_OUT_OF_RANGE; // invalid year
} else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12))
return RESULT_ERR_INVALID_ARG; // invalid date part
return RESULT_ERR_OUT_OF_RANGE; // invalid date part
break;
case bt_tim:
if (input.eof() == true || getline(input, token, LENGTH_SEPARATOR) == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
return RESULT_ERR_EOF; // incomplete
if (m_dataType.replacement != 0 && strcmp(token.c_str(), NULL_VALUE) == 0) {
value = m_dataType.replacement;
if (m_length == 1) { // truncated time
if (i == 0) {
last = value;
offset -= incr; // repeat for minutes
count++;
continue;
}
if (last != m_dataType.replacement)
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
}
break;
}
value = parseInt(token.c_str(), 10, 0, 59, result);
if (result != RESULT_OK)
return result; // invalid time part
if ((i == 0 && value > 24) || (i > 0 && (last == 24 && value > 0) ))
return RESULT_ERR_INVALID_ARG; // invalid time part
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
if (m_length == 1) { // truncated time
if (i == 0) {
last = value;
@@ -571,10 +638,10 @@ result_t StringDataField::writeSymbols(istringstream& input,
continue;
}
if ((value % 10) != 0)
return RESULT_ERR_INVALID_ARG; // invalid truncated time minutes
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
value = last * 6 + (value / 10);
if (value > 24 * 6)
return RESULT_ERR_INVALID_ARG; // invalid time
return RESULT_ERR_OUT_OF_RANGE; // invalid time
}
break;
default:
@@ -589,18 +656,18 @@ result_t StringDataField::writeSymbols(istringstream& input,
}
lastLast = last;
last = value;
if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat || (m_dataType.type == bt_tim && m_length > 2)) {
if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) {
if (value > 99)
return RESULT_ERR_INVALID_ARG; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
value = ((value / 10) << 4) | (value % 10);
}
if (value > 0xff)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
output[baseOffset + offset] = (unsigned char)value;
}
if (i < m_length)
return RESULT_ERR_INVALID_ARG; // input too short
return RESULT_ERR_EOF; // input too short
return RESULT_OK;
}
@@ -612,6 +679,18 @@ bool NumericDataField::hasFullByteOffset(bool after)
|| (after == true && m_bitOffset + (m_bitCount % 8) >= 8);
}
void NumericDataField::dump(ostream& output)
{
SingleDataField::dump(output);
if ((m_dataType.flags & ADJ) != 0) {
if ((m_dataType.maxBits % 8) != 0)
output << ":" << static_cast<unsigned>(m_bitCount);
else
output << ":" << static_cast<unsigned>(m_length);
}
output << FIELD_SEPARATOR;
}
result_t NumericDataField::readRawValue(SymbolString& input,
unsigned char baseOffset, unsigned int& value)
{
@@ -620,7 +699,7 @@ result_t NumericDataField::readRawValue(SymbolString& input,
unsigned char ch;
if (baseOffset + m_length > input.size())
return RESULT_ERR_INVALID_ARG; // not enough data available
return RESULT_ERR_INVALID_POS; // not enough data available
if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first)
start = m_length - 1;
@@ -636,7 +715,7 @@ result_t NumericDataField::readRawValue(SymbolString& input,
return RESULT_OK;
}
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09)
return RESULT_ERR_INVALID_ARG; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
ch = (ch >> 4) * 10 + (ch & 0x0f);
value += ch * exp;
@@ -671,7 +750,7 @@ result_t NumericDataField::writeRawValue(unsigned int value,
if ((m_dataType.flags & BCD) == 0) {
if ((m_bitCount % 8) != 0 && (value & ~((1 << m_bitCount) - 1)) != 0)
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_OUT_OF_RANGE;
value <<= m_bitOffset;
}
@@ -705,7 +784,7 @@ result_t NumberDataField::derive(string name, string comment,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (name.empty() == true)
name = m_name;
if (comment.empty() == true)
@@ -728,6 +807,13 @@ result_t NumberDataField::derive(string name, string comment,
return RESULT_OK;
}
void NumberDataField::dump(ostream& output)
{
NumericDataField::dump(output);
output << static_cast<unsigned>(m_divisor) << FIELD_SEPARATOR;
output << m_unit << FIELD_SEPARATOR << m_comment << FIELD_SEPARATOR;
}
result_t NumberDataField::readSymbols(SymbolString& input,
unsigned char baseOffset, ostringstream& output)
{
@@ -778,7 +864,7 @@ result_t NumberDataField::writeSymbols(istringstream& input,
if (isIgnored() == true || strcasecmp(str, NULL_VALUE) == 0)
value = m_dataType.replacement; // replacement value
else if (str == NULL || *str == 0)
return RESULT_ERR_INVALID_ARG; // input too short
return RESULT_ERR_EOF; // input too short
else {
char* strEnd = NULL;
if (m_divisor <= 1) {
@@ -792,17 +878,17 @@ result_t NumberDataField::writeSymbols(istringstream& input,
else
value = strtoul(str, &strEnd, 10);
if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_ARG; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
else {
char* strEnd = NULL;
double dvalue = strtod(str, &strEnd);
if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_ARG; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
dvalue = round(dvalue * m_divisor);
if ((m_dataType.flags & SIG) != 0) {
if (dvalue < -(1LL << (8 * m_length)) || dvalue >= (1LL << (8 * m_length)))
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
if (dvalue < 0 && m_bitCount != 32)
value = (unsigned int) (dvalue + (1 << m_bitCount));
else
@@ -810,7 +896,7 @@ result_t NumberDataField::writeSymbols(istringstream& input,
}
else {
if (dvalue < 0.0 || dvalue >= (1LL << (8 * m_length)))
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
value = (unsigned int) dvalue;
}
}
@@ -818,13 +904,13 @@ result_t NumberDataField::writeSymbols(istringstream& input,
if ((m_dataType.flags & SIG) != 0) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_dataType.minValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
else if (value > m_dataType.maxValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
else if (value < m_dataType.minValueOrLength || value > m_dataType.maxValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
return writeRawValue(value, baseOffset, output);
@@ -837,7 +923,7 @@ result_t ValueListDataField::derive(string name, string comment,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (name.empty() == true)
name = m_name;
if (comment.empty() == true)
@@ -860,6 +946,21 @@ result_t ValueListDataField::derive(string name, string comment,
return RESULT_OK;
}
void ValueListDataField::dump(ostream& output)
{
NumericDataField::dump(output);
bool first = true;
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) {
if (first == true)
first = false;
else
output << VALUE_SEPARATOR;
output << static_cast<unsigned>(it->first) << "=" << it->second;
}
output << FIELD_SEPARATOR;
output << m_unit << FIELD_SEPARATOR << m_comment << FIELD_SEPARATOR;
}
result_t ValueListDataField::readSymbols(SymbolString& input,
unsigned char baseOffset, ostringstream& output)
{
@@ -880,7 +981,7 @@ result_t ValueListDataField::readSymbols(SymbolString& input,
return RESULT_OK;
}
return RESULT_ERR_INVALID_ARG; // value assignment not found
return RESULT_ERR_NOTFOUND; // value assignment not found
}
result_t ValueListDataField::writeSymbols(istringstream& input,
@@ -898,7 +999,7 @@ result_t ValueListDataField::writeSymbols(istringstream& input,
if (strcasecmp(str, NULL_VALUE) == 0)
return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value
return RESULT_ERR_INVALID_ARG; // value assignment not found
return RESULT_ERR_NOTFOUND; // value assignment not found
}
DataFieldSet::~DataFieldSet()
@@ -947,43 +1048,38 @@ result_t DataFieldSet::derive(string name, string comment,
return RESULT_OK;
}
result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
ostringstream& output, bool verbose, char separator)
void DataFieldSet::dump(ostream& output)
{
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++)
(*it)->dump(output);
}
result_t DataFieldSet::read(const PartType partType,
SymbolString& data, unsigned char offset,
ostringstream& output, bool leadingSeparator,
bool verbose, char separator)
{
if (verbose)
output << m_name << "={ ";
bool first = true;
unsigned char offsets[4];
memset(offsets, 0, sizeof(offsets));
offsets[pt_masterData] = masterOffset;
offsets[pt_slaveData] = slaveOffset;
bool previousFullByteOffset[] = { true, true, true, true };
bool previousFullByteOffset = true;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it;
bool ignored = field->isIgnored();
PartType partType = field->getPartType();
if (partType != pt_any && field->getPartType() != partType)
continue;
if (ignored == false) {
if (first)
first = false;
else
output << separator;
}
if (partType == pt_masterDataID)
partType = pt_masterData;
if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false)
offsets[partType]--;
if (previousFullByteOffset == false && field->hasFullByteOffset(false) == false)
offset--;
result_t result = field->read(masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], output, verbose, separator);
//cout<<"read "<<field->getName().c_str()<<" in part "<<static_cast<unsigned>(field->getPartType())<<" offset "<<static_cast<unsigned>(offsets[field->getPartType()])<<endl;
result_t result = field->read(partType, data, offset, output, leadingSeparator, verbose, separator);
if (result != RESULT_OK)
return result;
offsets[partType] += field->getLength(partType);
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
offset += field->getLength(partType);
previousFullByteOffset = field->hasFullByteOffset(true);
leadingSeparator |= field->isIgnored() == false;
}
if (verbose == true) {
@@ -996,46 +1092,93 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset
}
result_t DataFieldSet::write(istringstream& input,
SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
char separator)
const PartType partType, SymbolString& data,
unsigned char offset, char separator)
{
string token;
unsigned char offsets[4];
memset(offsets, 0, sizeof(offsets));
offsets[pt_masterData] = masterOffset;
offsets[pt_slaveData] = slaveOffset;
bool previousFullByteOffset[] = { true, true, true, true };
bool previousFullByteOffset = true;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it;
bool ignored = field->isIgnored();
PartType partType = field->getPartType();
if (partType != pt_any && field->getPartType() != partType)
continue;
if (partType == pt_masterDataID)
partType = pt_masterData;
if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false)
offsets[partType]--;
if (previousFullByteOffset == false && field->hasFullByteOffset(false) == false)
offset--;
result_t result;
if (m_fields.size() > 1) {
if (ignored == true)
if (field->isIgnored() == true)
token.clear();
else if (getline(input, token, separator) == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
token.clear();
istringstream single(token);
result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator);
result = (*it)->write(single, partType, data, offset, separator);
}
else
result = (*it)->write(input, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator);
result = (*it)->write(input, partType, data, offset, separator);
if (result != RESULT_OK)
return result;
offsets[partType] += field->getLength(partType);
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
offset += field->getLength(partType);
previousFullByteOffset = field->hasFullByteOffset(true);
}
return RESULT_OK;
}
void DataFieldTemplates::clear()
{
for (map<string, DataField*>::iterator it=m_fieldsByName.begin(); it!=m_fieldsByName.end(); it++) {
delete it->second;
it->second = NULL;
}
m_fieldsByName.clear();
}
result_t DataFieldTemplates::add(DataField* field, bool replace)
{
string name = field->getName();
map<string, DataField*>::iterator it = m_fieldsByName.find(name);
if (it != m_fieldsByName.end()) {
if (replace == false)
return RESULT_ERR_DUPLICATE; // duplicate key
delete it->second;
it->second = field;
return RESULT_OK;
}
m_fieldsByName[name] = field;
return RESULT_OK;
}
result_t DataFieldTemplates::addFromFile(vector<string>& row, void* arg, vector< vector<string> >* defaults)
{
DataField* field = NULL;
vector<string>::iterator it = row.begin();
result_t result = DataField::create(it, row.end(), this, field);
if (result != RESULT_OK)
return result;
result = add(field);
if (result != RESULT_OK)
delete field;
return result;
}
DataField* DataFieldTemplates::get(const string name)
{
map<string, DataField*>::const_iterator ref = m_fieldsByName.find(name);
if (ref == m_fieldsByName.end())
return NULL;
return ref->second;
}
+187 -51
View File
@@ -23,16 +23,20 @@
#include "symbol.h"
#include "result.h"
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <map>
using namespace std;
#define FIELD_SEPARATOR ';'
/** the message part in which a data field is stored. */
enum PartType {
pt_any, // stored in any data (master or slave)
pt_masterData, // stored in master data
pt_masterDataID, // stored in master data and also used as message ID part
pt_slaveData, // stored in slave data
};
@@ -79,7 +83,17 @@ typedef struct {
*/
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length=NULL);
/**
* @brief Print the error position of the iterator to stdout.
* @param begin the iterator to the beginning of the items.
* @param end the iterator to the end of the items.
* @param pos the iterator with the erroneous position.
* @param separator the character to place between items.
*/
void printErrorPos(vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, char separator=';');
class DataFieldTemplates;
class SingleDataField;
/**
@@ -104,7 +118,7 @@ public:
* @brief Factory method for creating new instances.
* @param it the iterator to traverse for the definition parts.
* @param end the iterator pointing to the end of the definition parts.
* @param templates a map of @a DataField templates to be referenced by name.
* @param templates the @a DataFieldTemplates to be referenced by name, or NULL.
* @param returnField the variable in which to store the created instance.
* @param isSetMessage whether the field is part of a set message (default false).
* @param dstAddress the destination bus address (default @a SYN for creating a template @a DataField).
@@ -112,7 +126,7 @@ public:
* Note: the caller needs to free the created instance.
*/
static result_t create(vector<string>::iterator& it, const vector<string>::iterator end,
const map<string, DataField*> templates, DataField*& returnField,
DataFieldTemplates* templates, DataField*& returnField,
const bool isSetMessage=false, const unsigned char dstAddress=SYN);
/**
* @brief Returns the length of this field (or contained fields) in bytes.
@@ -145,31 +159,38 @@ public:
*/
string getComment() const { return m_comment; }
/**
* @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.
* @brief Dump the field settings to the output.
* @param output the @a ostream to dump to.
*/
virtual void dump(ostream& output) = 0;
/**
* @brief Reads the value from the @a SymbolString.
* @param partType the @a PartType of the data.
* @param data the unescaped data @a SymbolString for reading binary data.
* @param offset the additional offset to add for reading binary data.
* @param output the @a ostringstream to append the formatted value to.
* @param leadingSeparator whether to prepend a separator before the formatted value.
* @param verbose whether to prepend the name, append the unit (if present), and append
* the comment in square brackets (if present).
* @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code.
* @return @a RESULT_OK on success (or if the partType does not match), or an error code.
*/
virtual result_t read(SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
ostringstream& output,
virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset,
ostringstream& output, bool leadingSeparator=false,
bool verbose=false, char separator=';') = 0;
/**
* @brief Writes the value to the master or slave @a SymbolString.
* @param input the @a istringstream to parse the formatted value from.
* @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 partType the @a PartType of the data.
* @param data the unescaped data @a SymbolString for writing binary data.
* @param offset the additional offset to add for writing binary data.
* @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t write(istringstream& input,
SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
char separator=';') = 0;
const PartType partType, SymbolString& data,
unsigned char offset, char separator=';') = 0;
protected:
@@ -232,34 +253,17 @@ public:
* only consumes a part of a byte and a subsequent field may re-use the same offset.
*/
virtual bool hasFullByteOffset(bool after) { return true; }
/**
* @brief Reads the value from the master or slave @a SymbolString.
* @param masterData the unescaped master data @a SymbolString for reading binary data.
* @param masterOffset the extra offset for reading master data.
* @param slaveData the unescaped slave data @a SymbolString for reading binary data.
* @param slaveOffset the extra offset for reading slave data.
* @param output the ostringstream to append the formatted value to.
* @param verbose whether to prepend the name, append the unit (if present), and append
* the comment in square brackets (if present).
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t read(SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
ostringstream& output,
bool verbose, char separator);
/**
* @brief Writes the value to the master or slave @a SymbolString.
* @param input the @a istringstream to parse the formatted value from.
* @param masterData the unescaped master data @a SymbolString for writing binary data.
* @param masterOffset the extra offset for writing master data.
* @param slaveData the unescaped slave data @a SymbolString for writing binary data.
* @param slaveOffset the extra offset for writing slave data.
* @return @a RESULT_OK on success, or an error code.
*/
// @copydoc
virtual void dump(ostream& output);
// @copydoc
virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset,
ostringstream& output, bool leadingSeparator=false,
bool verbose=false, char separator=';');
// @copydoc
virtual result_t write(istringstream& input,
SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
char separator);
const PartType partType, SymbolString& data,
unsigned char offset, char separator=';');//TODO replace
protected:
@@ -280,6 +284,8 @@ protected:
*/
virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output) = 0;
protected:
/** the value unit. */
const string m_unit;
/** the data type definition. */
@@ -321,6 +327,8 @@ public:
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields);
// @copydoc
virtual void dump(ostream& output);
protected:
@@ -361,6 +369,8 @@ public:
virtual ~NumericDataField() {}
// @copydoc
virtual bool hasFullByteOffset(bool after);
// @copydoc
virtual void dump(ostream& output);
protected:
@@ -387,7 +397,6 @@ protected:
/** the offset to the first bit in the binary value. */
const unsigned char m_bitOffset;
};
@@ -424,6 +433,8 @@ public:
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields);
// @copydoc
virtual void dump(ostream& output);
protected:
@@ -432,6 +443,8 @@ protected:
// @copydoc
virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output);
private:
/** the combined divisor to apply on the value, or 1 for none. */
const unsigned int m_divisor;
@@ -471,6 +484,8 @@ public:
string unit, const PartType partType, unsigned int divisor,
map<unsigned int, string> values,
vector<SingleDataField*>& fields);
// @copydoc
virtual void dump(ostream& output);
protected:
@@ -479,6 +494,8 @@ protected:
// @copydoc
virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output);
private:
/** the value=text assignments. */
map<unsigned int, string> m_values;
@@ -531,17 +548,18 @@ public:
*/
size_t size() const { return m_fields.size(); }
// @copydoc
virtual result_t read(SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
ostringstream& output,
bool verbose, char separator);
virtual void dump(ostream& output);
// @copydoc
virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset,
ostringstream& output, bool leadingSeparator=false,
bool verbose=false, char separator=';');
// @copydoc
virtual result_t write(istringstream& input,
SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
char separator);
const PartType partType, SymbolString& data,
unsigned char offset, char separator=';');
protected:
private:
/** the @a vector of @a SingleDataField instances part of this set. */
vector<SingleDataField*> m_fields;
@@ -549,4 +567,122 @@ protected:
};
/**
* @brief An abstract class that support reading definitions from a file.
*/
template<typename T>
class FileReader
{
public:
/**
* @brief Constructs a new instance.
*/
FileReader(bool supportsDefaults)
: m_supportsDefaults(supportsDefaults) {}
/**
* @brief Destructor.
*/
virtual ~FileReader() {}
/**
* @brief Reads the definitions from a file.
* @param filename the name (and path) of the file to read.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t readFromFile(string filename, T arg=NULL)
{
ifstream ifs;
ifs.open(filename.c_str(), ifstream::in);
if (ifs.is_open() == false)
return RESULT_ERR_NOTFOUND;
string line;
unsigned int lineNo = 0;
vector<string> row;
string token;
vector< vector<string> > defaults;
while (getline(ifs, line) != 0) {
lineNo++;
// skip empty lines and comments
if (line.length() == 0 || line.substr(0, 1) == "#" || line.substr(0, 2) == "//")
continue;
istringstream isstr(line);
row.clear();
while (getline(isstr, token, FIELD_SEPARATOR) != 0)
row.push_back(token);
if (m_supportsDefaults == true && line.substr(0, 1) == "*") {
row[0] = row[0].substr(1);
defaults.push_back(row);
continue;
}
result_t result = addFromFile(row, arg, m_supportsDefaults == true ? &defaults : NULL);
if (result != RESULT_OK) {
cerr << "error reading \"" << filename << "\" line " << static_cast<unsigned>(lineNo) << ": " << getResultCode(result) << endl;
ifs.close();
return result;
}
}
ifs.close();
return RESULT_OK;
}
/**
* @brief Adds a definition that was read from a file.
* @param row the definition row read from the file.
* @param defaults all previously read default rows (initial star char removed), or NULL if not supported.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t addFromFile(vector<string>& row, T arg, vector< vector<string> >* defaults) = 0;
private:
/** whether this instance supports rows with defaults (starting with a star). */
bool m_supportsDefaults;
};
/**
* @brief A map of template @a DataField instances.
*/
class DataFieldTemplates : public FileReader<void*>
{
public:
/**
* @brief Constructs a new instance.
*/
DataFieldTemplates() : FileReader(false) {}
/**
* @brief Destructor.
*/
virtual ~DataFieldTemplates() { clear(); }
/**
* @brief Removes all @a DataField instances.
*/
void clear();
/**
* @brief Adds a template @a DataField instance to this map.
* @param field the @a DataField instance to add.
* @param replace whether replacing an already stored instance is allowed.
* @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success.
*/
result_t add(DataField* message, bool replace=false);
// @copydoc
virtual result_t addFromFile(vector<string>& row, void* arg, vector< vector<string> >* defaults);
/**
* @brief Gets the template @a DataField instance with the specified name.
* @return the template @a DataField instance, or NULL.
* Note: the caller may not free the returned instance.
*/
DataField* get(string name);
private:
/** the known template @a DataField instances by name. */
map<string, DataField*> m_fieldsByName;
};
#endif // LIBEBUS_DATA_H_
-347
View File
@@ -1,347 +0,0 @@
/*
* 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>
using namespace std;
Decode::Decode(const string& data, const string& factor)
: m_data(data)
{
if ((factor.find_first_not_of("0123456789.") == string::npos) == true)
m_factor = static_cast<float>(strtod(factor.c_str(), NULL));
else
m_factor = 1.0;
}
string DecodeHEX::decode()
{
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);
}
string DecodeUCH::decode()
{
stringstream ss;
ss << hex << m_data;
unsigned short x;
ss >> x;
ostringstream result;
result << setprecision(3) << fixed << static_cast<float>(x * m_factor);
return result.str();
}
string DecodeSCH::decode()
{
stringstream ss;
ss << hex << m_data;
unsigned short x;
ss >> x;
ostringstream result;
if ((x & 0x80) == 0x80)
result << setprecision(3) << fixed
<< static_cast<float>(static_cast<short>(- ( ((unsigned char) (~ x)) + 1) ) * m_factor);
else
result << setprecision(3) << fixed
<< static_cast<float>(static_cast<short>(x) * m_factor);
return result.str();
}
string DecodeUIN::decode()
{
stringstream ss;
ss << hex << m_data;
unsigned short x;
ss >> x;
ostringstream result;
result << setprecision(3) << fixed << static_cast<float>(x * m_factor);
return result.str();
}
string DecodeSIN::decode()
{
stringstream ss;
ss << hex << m_data;
unsigned short x;
ss >> x;
ostringstream result;
result << setprecision(3) << fixed << static_cast<float>(static_cast<short>(x) * m_factor);
return result.str();
}
string DecodeULG::decode()
{
stringstream ss;
ss << hex << m_data;
unsigned int x;
ss >> x;
ostringstream result;
result << setprecision(3) << fixed << static_cast<float>(x * m_factor);
return result.str();
}
string DecodeSLG::decode()
{
stringstream ss;
ss << hex << m_data;
unsigned int x;
ss >> x;
ostringstream result;
result << setprecision(3) << fixed <<static_cast<float>(static_cast<int>(x) * m_factor);
return result.str();
}
string DecodeFLT::decode()
{
stringstream ss;
ss << hex << m_data;
short x;
ss >> x;
ostringstream result;
result << setprecision(3) << fixed << static_cast<float>(x / 1000.0 * m_factor);
return result.str();
}
string DecodeSTR::decode()
{
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);
}
string DecodeBCD::decode()
{
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();
}
string DecodeD1B::decode()
{
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();
}
string DecodeD1C::decode()
{
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();
}
string DecodeD2B::decode()
{
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();
}
string DecodeD2C::decode()
{
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();
}
string DecodeBDA::decode()
{
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 << setw(2) << setfill('0') << array[0] << "."
<< setw(2) << setfill('0') << array[1] << "."
<< array[2] + 2000;
return result.str();
}
string DecodeHDA::decode()
{
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 << setw(2) << setfill('0') << dd << "."
<< setw(2) << setfill('0') << mm << "."
<< yy + 2000;
return result.str();
}
string DecodeBTI::decode()
{
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 << setw(2) << setfill('0') << array[0] << ":"
<< setw(2) << setfill('0') << array[1] << ":"
<< setw(2) << setfill('0') << array[2];
return result.str();
}
string DecodeHTI::decode()
{
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 << setw(2) << setfill('0') << hh << ":"
<< setw(2) << setfill('0') << mm << ":"
<< setw(2) << setfill('0') << ss;
return result.str();
}
string DecodeBDY::decode()
{
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"};
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();
}
string DecodeHDY::decode()
{
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"};
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();
}
string DecodeTTM::decode()
{
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 << setw(2) << setfill('0') << hh << ":"
<< setw(2) << setfill('0') << mm;
return result.str();
}
-286
View File
@@ -1,286 +0,0 @@
/*
* 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>
using namespace std;
class Decode
{
public:
Decode(const string& data, const string& factor = "");
virtual ~Decode() {}
virtual string decode() = 0;
protected:
string m_data;
float m_factor;
};
class DecodeHEX : public Decode
{
public:
DecodeHEX(const string& data) : Decode(data) {}
~DecodeHEX() {}
string decode();
};
class DecodeUCH : public Decode
{
public:
DecodeUCH(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeUCH() {}
string decode();
};
class DecodeSCH : public Decode
{
public:
DecodeSCH(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeSCH() {}
string decode();
};
class DecodeUIN : public Decode
{
public:
DecodeUIN(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeUIN() {}
string decode();
};
class DecodeSIN : public Decode
{
public:
DecodeSIN(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeSIN() {}
string decode();
};
class DecodeULG : public Decode
{
public:
DecodeULG(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeULG() {}
string decode();
};
class DecodeSLG : public Decode
{
public:
DecodeSLG(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeSLG() {}
string decode();
};
class DecodeFLT : public Decode
{
public:
DecodeFLT(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeFLT() {}
string decode();
};
class DecodeSTR : public Decode
{
public:
DecodeSTR(string data) : Decode(data) {}
~DecodeSTR() {}
string decode();
};
class DecodeBCD : public Decode
{
public:
DecodeBCD(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeBCD() {}
string decode();
};
class DecodeD1B : public Decode
{
public:
DecodeD1B(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeD1B() {}
string decode();
};
class DecodeD1C : public Decode
{
public:
DecodeD1C(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeD1C() {}
string decode();
};
class DecodeD2B : public Decode
{
public:
DecodeD2B(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeD2B() {}
string decode();
};
class DecodeD2C : public Decode
{
public:
DecodeD2C(const string& data, const string& factor)
: Decode(data, factor) {}
~DecodeD2C() {}
string decode();
};
class DecodeBDA : public Decode
{
public:
DecodeBDA(const string& data) : Decode(data) {}
~DecodeBDA() {}
string decode();
};
class DecodeHDA : public Decode
{
public:
DecodeHDA(const string& data) : Decode(data) {}
~DecodeHDA() {}
string decode();
};
class DecodeBTI : public Decode
{
public:
DecodeBTI(const string& data) : Decode(data) {}
~DecodeBTI() {}
string decode();
};
class DecodeHTI : public Decode
{
public:
DecodeHTI(const string& data) : Decode(data) {}
~DecodeHTI() {}
string decode();
};
class DecodeBDY : public Decode
{
public:
DecodeBDY(const string& data) : Decode(data) {}
~DecodeBDY() {}
string decode();
};
class DecodeHDY : public Decode
{
public:
DecodeHDY(const string& data) : Decode(data) {}
~DecodeHDY() {}
string decode();
};
class DecodeTTM : public Decode
{
public:
DecodeTTM(const string& data) : Decode(data) {}
~DecodeTTM() {}
string decode();
};
#endif // LIBEBUS_DECODE_H_
-364
View File
@@ -1,364 +0,0 @@
/*
* 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>
using namespace std;
Encode::Encode(const string& data, const string& factor)
: m_data(data)
{
if ((factor.find_first_not_of("0123456789.") == string::npos) == true)
m_factor = static_cast<float>(strtod(factor.c_str(), NULL));
else
m_factor = 1.0;
}
string EncodeHEX::encode()
{
m_data.erase(remove_if(m_data.begin(), m_data.end(), ::isspace), m_data.end());
return m_data;
}
string EncodeUCH::encode()
{
ostringstream result;
unsigned short src = static_cast<unsigned short>(strtod(m_data.c_str(), NULL) / m_factor);
result << setw(2) << hex << setfill('0') << src;
return result.str().substr(result.str().length()-2,2);
}
string EncodeSCH::encode()
{
ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -127 || src > 127)
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(0x80);
else
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(src);
return result.str().substr(result.str().length()-2,2);
}
string EncodeUIN::encode()
{
ostringstream result;
unsigned short src = static_cast<unsigned short>(strtod(m_data.c_str(), NULL) / m_factor);
result << setw(4) << hex << setfill('0') << src;
return result.str().substr(2,2) + result.str().substr(0,2);
}
string EncodeSIN::encode()
{
ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
result << setw(4) << hex << setfill('0') << src;
return result.str().substr(2,2) + result.str().substr(0,2);
}
string EncodeULG::encode()
{
ostringstream result;
unsigned long src = static_cast<unsigned long>(strtod(m_data.c_str(), NULL) / m_factor);
result << setw(8) << hex << setfill('0') << src;
return result.str().substr(6,2) + result.str().substr(4,2) +
result.str().substr(2,2) + result.str().substr(0,2);
}
string EncodeSLG::encode()
{
ostringstream result;
int src = static_cast<int>(strtod(m_data.c_str(), NULL) / m_factor);
result << setw(8) << hex << setfill('0') << src;
return result.str().substr(6,2) + result.str().substr(4,2) +
result.str().substr(2,2) + result.str().substr(0,2);
}
string EncodeFLT::encode()
{
ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) * 1000.0 / m_factor);
result << setw(4) << hex << setfill('0') << src;
return result.str().substr(2,2) + result.str().substr(0,2);
}
string EncodeSTR::encode()
{
ostringstream result;
for (size_t i = 0; i < m_data.length(); i++)
result << setw(2) << hex << setfill('0') << static_cast<short>(m_data[i]);
return result.str();
}
string EncodeBCD::encode()
{
ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
if (src > 99)
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(0xFF);
else
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>( ((src / 10) << 4) | (src % 10) );
return result.str().substr(result.str().length()-2,2);
}
string EncodeD1B::encode()
{
ostringstream result;
short src = static_cast<short>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -127 || src > 127)
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(0x80);
else
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(src);
return result.str().substr(result.str().length()-2,2);
}
string EncodeD1C::encode()
{
ostringstream result;
float src = static_cast<float>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < 0.0 || src > 100.0)
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(0xFF);
else
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(src * 2.0);
return result.str();
}
string EncodeD2B::encode()
{
ostringstream result;
float src = static_cast<float>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -127.999 || src > 127.999) {
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(0x80)
<< setw(2) << hex << 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 << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(tgt_msb)
<< setw(2) << hex << setfill('0')
<< static_cast<unsigned>(tgt_lsb);
}
return result.str();
}
string EncodeD2C::encode()
{
ostringstream result;
float src = static_cast<float>(strtod(m_data.c_str(), NULL) / m_factor);
if (src < -2047.999 || src > 2047.999) {
result << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(0x80)
<< setw(2) << hex << 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 << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(tgt_msb)
<< setw(2) << hex << setfill('0')
<< static_cast<unsigned>(tgt_lsb);
}
return result.str();
}
string EncodeBDA::encode()
{
// prepare data
string token;
istringstream stream(m_data);
vector<string> data;
while (getline(stream, token, '.') != 0)
data.push_back(token);
ostringstream result;
result << setw(2) << dec << setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< setw(2) << dec << setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< setw(2) << dec << setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL) - 2000);
return result.str();
}
string EncodeHDA::encode()
{
// prepare data
string token;
istringstream stream(m_data);
vector<string> data;
while (getline(stream, token, '.') != 0)
data.push_back(token);
ostringstream result;
result << setw(2) << hex << setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< setw(2) << hex << setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< setw(2) << hex << setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL) - 2000);
return result.str();
}
string EncodeBTI::encode()
{
// prepare data
string token;
istringstream stream(m_data);
vector<string> data;
while (getline(stream, token, ':') != 0)
data.push_back(token);
ostringstream result;
result << setw(2) << dec << setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< setw(2) << dec << setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< setw(2) << dec << setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL));
return result.str();
}
string EncodeHTI::encode()
{
// prepare data
string token;
istringstream stream(m_data);
vector<string> data;
while (getline(stream, token, ':') != 0)
data.push_back(token);
ostringstream result;
result << setw(2) << hex << setfill('0')
<< static_cast<short>(strtod(data[0].c_str(), NULL))
<< setw(2) << hex << setfill('0')
<< static_cast<short>(strtod(data[1].c_str(), NULL))
<< setw(2) << hex << setfill('0')
<< static_cast<short>(strtod(data[2].c_str(), NULL));
return result.str();
}
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;
ostringstream result;
result << setw(2) << hex << setfill('0') << day;
return result.str();
}
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;
ostringstream result;
result << setw(2) << hex << setfill('0') << day;
return result.str();
}
string EncodeTTM::encode()
{
// prepare data
string token;
istringstream stream(m_data);
vector<string> data;
while (getline(stream, token, ':') != 0)
data.push_back(token);
ostringstream result;
result << setw(2) << hex << setfill('0')
<< static_cast<short>( (strtod(data[0].c_str(), NULL) * 6)
+ (strtod(data[1].c_str(), NULL) / 10) );
return result.str();
}
-286
View File
@@ -1,286 +0,0 @@
/*
* 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>
using namespace std;
class Encode
{
public:
Encode(const string& data, const string& factor = "");
virtual ~Encode() {}
virtual string encode() = 0;
protected:
string m_data;
float m_factor;
};
class EncodeHEX : public Encode
{
public:
EncodeHEX(const string& data) : Encode(data) {}
~EncodeHEX() {}
string encode();
};
class EncodeUCH : public Encode
{
public:
EncodeUCH(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeUCH() {}
string encode();
};
class EncodeSCH : public Encode
{
public:
EncodeSCH(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeSCH() {}
string encode();
};
class EncodeUIN : public Encode
{
public:
EncodeUIN(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeUIN() {}
string encode();
};
class EncodeSIN : public Encode
{
public:
EncodeSIN(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeSIN() {}
string encode();
};
class EncodeULG : public Encode
{
public:
EncodeULG(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeULG() {}
string encode();
};
class EncodeSLG : public Encode
{
public:
EncodeSLG(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeSLG() {}
string encode();
};
class EncodeFLT : public Encode
{
public:
EncodeFLT(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeFLT() {}
string encode();
};
class EncodeSTR : public Encode
{
public:
EncodeSTR(const string& data) : Encode(data) {}
~EncodeSTR() {}
string encode();
};
class EncodeBCD : public Encode
{
public:
EncodeBCD(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeBCD() {}
string encode();
};
class EncodeD1B : public Encode
{
public:
EncodeD1B(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeD1B() {}
string encode();
};
class EncodeD1C : public Encode
{
public:
EncodeD1C(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeD1C() {}
string encode();
};
class EncodeD2B : public Encode
{
public:
EncodeD2B(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeD2B() {}
string encode();
};
class EncodeD2C : public Encode
{
public:
EncodeD2C(const string& data, const string& factor)
: Encode(data, factor) {}
~EncodeD2C() {}
string encode();
};
class EncodeBDA : public Encode
{
public:
EncodeBDA(const string& data) : Encode(data) {}
~EncodeBDA() {}
string encode();
};
class EncodeHDA : public Encode
{
public:
EncodeHDA(const string& data) : Encode(data) {}
~EncodeHDA() {}
string encode();
};
class EncodeBTI : public Encode
{
public:
EncodeBTI(const string& data) : Encode(data) {}
~EncodeBTI() {}
string encode();
};
class EncodeHTI : public Encode
{
public:
EncodeHTI(const string& data) : Encode(data) {}
~EncodeHTI() {}
string encode();
};
class EncodeBDY : public Encode
{
public:
EncodeBDY(const string& data) : Encode(data) {}
~EncodeBDY() {}
string encode();
};
class EncodeHDY : public Encode
{
public:
EncodeHDY(const string& data) : Encode(data) {}
~EncodeHDY() {}
string encode();
};
class EncodeTTM : public Encode
{
public:
EncodeTTM(const string& data) : Encode(data) {}
~EncodeTTM() {}
string encode();
};
#endif // LIBEBUS_ENCODE_H_
+333 -76
View File
@@ -27,28 +27,76 @@
using namespace std;
result_t Message::create(vector<string>::iterator& it, const vector<string>::iterator end,
const map<string, DataField*> templates, Message*& returnValue)
Message::Message(const string clazz, const string name, const bool isSet,
const bool isPassive, const string comment,
const unsigned char srcAddress, const unsigned char dstAddress,
const vector<unsigned char> id, DataField* data,
const unsigned int pollPriority)
: m_class(clazz), m_name(name), m_isSet(isSet),
m_isPassive(isPassive), m_comment(comment),
m_srcAddress(srcAddress), m_dstAddress(dstAddress),
m_id(id), m_data(data), m_pollPriority(pollPriority),
m_lastUpdateTime(0)
{
int exp = 7;
unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5);
if (isPassive == true)
key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--); // 0..25
else
key |= 0x1fLL << (8 * exp--); // special value for active
key |= (unsigned long long)dstAddress << (8 * exp--);
for (vector<unsigned char>::const_iterator it=id.begin(); it<id.end(); it++)
key |= (unsigned long long)*it << (8 * exp--);
m_key = key;
}
/**
* @brief Helper method for getting a default if the value is empty.
* @param value the value to check.
* @param defaults a @a vector of defaults, or NULL.
* @param pos the position in defaults.
* @return the default if available and value is empty, or the value.
*/
string getDefault(string value, vector<string>* defaults, size_t pos)
{
/*cout<<"getDefault("<<value<<",";
if (defaults==NULL)
cout<<"NULL";
else
cout<<static_cast<unsigned>(defaults->size());
cout<<","<<static_cast<unsigned>(pos)<<"=";*/
if (value.length() > 0 || defaults == NULL || pos > defaults->size()) {
//cout<<value<<endl;
return value;
}
value = defaults->at(pos);
//cout<<value<<endl;
return value;
}
result_t Message::create(vector<string>::iterator& it, const vector<string>::iterator end,
vector< vector<string> >* defaultsRows,
DataFieldTemplates* templates, Message*& returnValue)
{
// [type];[class];name;[comment];[QQ];ZZ;id;fields...
result_t result;
// [type];class;name;[comment];[QQ];ZZ;id;fields...
bool isSet = false, isPassive = false;
char defaultsChar;
unsigned int pollPriority = 0;
size_t defaultPos = 1;
if (it == end)
return RESULT_ERR_EOF;
const char* str = (*it++).c_str();
if (it == end)
return RESULT_ERR_EOF;
bool isSetMessage, isActiveMessage;
unsigned int pollPriority = 0;
if (strcasecmp(str, "W") == 0) {
isActiveMessage = true;
isSetMessage = true;
} else if (str[0] == 'C' || str[0] == 'c') {
isActiveMessage = false;
isSetMessage = str[1] == 'W' || str[1] == 'w';
} else if (str[0] == 'P' || str[0] == 'p') {
isActiveMessage = true;
isSetMessage = false;
if (str[0] == 0 || strncasecmp(str, "R", 1) == 0) { // default: active get
defaultsChar = 'r';
} else if (strncasecmp(str, "W", 1) == 0) { // active set
isSet = true;
defaultsChar = 'w';
} else if (strncasecmp(str, "P", 1) == 0) { // poll (=active get)
if (str[1] == 0)
pollPriority = 1;
else {
@@ -57,12 +105,31 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
if (result != RESULT_OK)
return result;
}
} else {
isActiveMessage = true;
isSetMessage = false;
defaultsChar = 'r';
} else if (str[0] >= '0' && str[0] <= '9') { // poll priority (=active get)
result_t result;
pollPriority = parseInt(str, 10, 1, 9, result);
if (result != RESULT_OK)
return result;
defaultsChar = 'r';
} else { // any other: passive set/get
isPassive = true;
isSet = strncasecmp(str+1, "W", 1) == 0;
defaultsChar = str[0];
}
string clazz = *it++;
vector<string>* defaults = NULL;
if (defaultsRows != NULL && defaultsRows->size() > 0) {
for (vector< vector<string> >::reverse_iterator it = defaultsRows->rbegin(); it != defaultsRows->rend(); it++) {
string check = (*it)[0];
if (check[0] == defaultsChar) {
defaults = &(*it);
break;
}
}
}
string clazz = getDefault(*it++, defaults, defaultPos++);
if (it == end)
return RESULT_ERR_EOF;
@@ -71,17 +138,18 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return RESULT_ERR_EOF;
if (name.length() == 0)
return RESULT_ERR_INVALID_ARG; // empty name
defaultPos++;
string comment = *it++;
string comment = getDefault(*it++, defaults, defaultPos++);
if (it == end)
return RESULT_ERR_EOF;
str = (*it++).c_str();
str = getDefault(*it++, defaults, defaultPos++).c_str();
if (it == end)
return RESULT_ERR_EOF;
unsigned char srcAddress;
if (*str == 0 || isActiveMessage == true)
srcAddress = SYN; // no specific source defined, or ignore for active message
if (*str == 0)
srcAddress = SYN; // no specific source defined
else {
srcAddress = parseInt(str, 16, 0, 0xff, result);
if (result != RESULT_OK)
@@ -90,7 +158,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return RESULT_ERR_INVALID_ARG;
}
str = (*it++).c_str();
str = getDefault(*it++, defaults, defaultPos++).c_str();
if (it == end)
return RESULT_ERR_EOF;
@@ -100,73 +168,262 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
if (isValidAddress(dstAddress) == false)
return RESULT_ERR_INVALID_ARG;
istringstream input(*it++); // message id (PBSB + optional master data)
vector<unsigned char> id;
string token;
if (it == end)
return RESULT_ERR_EOF;
while (input.eof() == false) {
while (input.peek() == ' ')
input.get();
if (input.eof() == true) // no more digits
break;
token.clear();
token.push_back(input.get());
if (input.eof() == true)
return RESULT_ERR_INVALID_ARG; // too short hex
token.push_back(input.get());
for (int pos=0, useDefaults=1; pos<2; pos++) { // message id (PBSB, optional master data)
string token = *it++;
if (useDefaults == 1) {
if (pos == 0 && token.size() > 0) {
useDefaults = 0;
} else {
token = getDefault("", defaults, defaultPos).append(token);
}
}
istringstream input(token);
if (it == end)
return RESULT_ERR_EOF;
while (input.eof() == false) {
while (input.peek() == ' ')
input.get();
if (input.eof() == true) // no more digits
break;
token.clear();
token.push_back(input.get());
if (input.eof() == true) {
return RESULT_ERR_INVALID_ARG; // too short hex
}
token.push_back(input.get());
unsigned char value = parseInt(token.c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK)
return result; // invalid hex value
id.push_back(value);
unsigned char value = parseInt(token.c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK) {
return result; // invalid hex value
}
id.push_back(value);
}
if (pos == 0 && id.size() != 2) {
return RESULT_ERR_INVALID_ARG; // missing/too short/too PBSB
}
defaultPos++;
}
if (id.size() < 2 || id.size() > 6)
if (id.size() < 2 || id.size() > 6) {
return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID
}
vector<string>::iterator realEnd = end;
vector<string> newTypes;
if (defaults!=NULL && defaults->size() > defaultPos + 2) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]")
while (defaults->size() > defaultPos + 2 && defaults->at(defaultPos + 2).size() > 0) {
for (size_t i = 0; i < 6; i++) {
if (defaults->size() > defaultPos)
newTypes.push_back(defaults->at(defaultPos));
else
newTypes.push_back("");
defaultPos++;
}
}
if (newTypes.size() > 0) {
while (it != end) {
newTypes.push_back(*it++);
}
it = newTypes.begin();
realEnd = newTypes.end();
}
}
DataField* data = NULL;
result = DataField::create(it, end, templates, data, isSetMessage, dstAddress);
result = DataField::create(it, realEnd, templates, data, isSet, dstAddress);
if (result != RESULT_OK) {
return result;
}
returnValue = new Message(clazz, name, isSet, isPassive, comment, srcAddress, dstAddress, id, data, pollPriority);
return RESULT_OK;
}
result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator)
{
if (m_isPassive == true)
return RESULT_ERR_INVALID_ARG; // prepare not possible
SymbolString master;
master.clear();
result_t result = master.push_back(srcAddress, false, false);
if (result != RESULT_OK)
return result;
returnValue = new Message(clazz, name, isSetMessage, isActiveMessage, comment, srcAddress, dstAddress, id, data, pollPriority);
return RESULT_OK;
}
result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator)
{
if (m_isActiveMessage == true) {
masterData.clear();
masterData.push_back(srcAddress, false);
masterData.push_back(m_dstAddress, false);
masterData.push_back(m_id[0], false);
masterData.push_back(m_id[1], false);
unsigned char addData = m_data->getLength(pt_masterData);
masterData.push_back(m_id.size() - 2 + addData, false);
for (size_t i=2; i<m_id.size(); i++)
masterData.push_back(m_id[i], false);
SymbolString slaveData;
result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator);
if (result != RESULT_OK)
return result;
masterData.push_back(masterData.getCRC(), false, false);
}
return RESULT_OK;
}
result_t Message::handle(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator, bool answer)
{
if (m_isActiveMessage == true) {
result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator);
result = master.push_back(m_dstAddress, false, false);
if (result != RESULT_OK)
return result;
result = master.push_back(m_id[0], false, false);
if (result != RESULT_OK)
return result;
result = master.push_back(m_id[1], false, false);
if (result != RESULT_OK)
return result;
unsigned char addData = m_data->getLength(pt_masterData);
result = master.push_back(m_id.size() - 2 + addData, false, false);
if (result != RESULT_OK)
return result;
for (size_t i=2; i<m_id.size(); i++) {
result = master.push_back(m_id[i], false, false);
if (result != RESULT_OK)
return result;
}
else if (answer == true) {
result = m_data->write(input, pt_masterData, master, m_id.size() - 2, separator);
if (result != RESULT_OK)
return result;
masterData = SymbolString(master);
return result;
}
result_t Message::decode(const PartType partType, SymbolString& data,
ostringstream& output, bool leadingSeparator, char separator)
{
unsigned char offset;
if (partType == pt_masterData)
offset = m_id.size() - 2;
else
offset = 0;
int startPos = output.str().length();
result_t result = m_data->read(partType, data, offset, output, leadingSeparator, false, separator);
time(&m_lastUpdateTime);
if (result != RESULT_OK) {
m_lastValue.clear();
return result;
}
m_lastValue = output.str().substr(startPos);
/*if (m_isPassive == false && answer == true) {
istringstream input; // TODO create input from database of internal variables
result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator);
if (result != RESULT_OK)
return result;
}
}*/
return RESULT_OK;
}
result_t MessageMap::add(Message* message)
{
unsigned long long pkey = message->getKey();
bool isPassive = message->isPassive();
if (isPassive == true) {
map<unsigned long long, Message*>::iterator keyIt = m_passiveMessagesByKey.find(pkey);
if (keyIt != m_passiveMessagesByKey.end()) {
return RESULT_ERR_DUPLICATE; // duplicate key
}
}
bool isSet = message->isSet();
string clazz = message->getClass();
string name = message->getName();
string key = string(isPassive ? "P" : (isSet ? "W" : "R")) + clazz + ";" + name;
map<string, Message*>::iterator nameIt = m_messagesByName.find(key);
if (nameIt != m_messagesByName.end()) {
return RESULT_ERR_DUPLICATE; // duplicate key
}
m_messagesByName[key] = message;
key = string(isPassive ? "-P;" : (isSet ? "-W;" : "-R;")) + name; // also store without class
m_messagesByName[key] = message; // last key without class overrides previous
if (message->isPassive() == true) {
unsigned char idLength = message->getId().size() - 2;
if (idLength < m_minIdLength)
m_minIdLength = idLength;
if (idLength > m_maxIdLength)
m_maxIdLength = idLength;
m_passiveMessagesByKey[pkey] = message;
}
//m_pollMessages.push()
return RESULT_OK;
}
result_t MessageMap::addFromFile(vector<string>& row, DataFieldTemplates* arg, vector< vector<string> >* defaults)
{
Message* message = NULL;
string types = row[0];
if (types.length() == 0)
types.append("r");
result_t result = RESULT_ERR_EOF;
istringstream stream(types);
string type;
while (getline(stream, type, ',') != 0) {
row[0] = type;
vector<string>::iterator it = row.begin();
result = Message::create(it, row.end(), defaults, arg, message);
if (result != RESULT_OK) {
printErrorPos(row.begin(), row.end(), it);
return result;
}
result = add(message);
if (result != RESULT_OK) {
delete message;
}
}
return result;
}
Message* MessageMap::find(const string& clazz, const string& name, const bool isSet,const bool isPassive)
{
for (int i=0; i<2; i++) {
string key;
if (i==0)
key = string(isPassive ? "P" : (isSet ? "W" : "R")) + clazz + ";" + name;
else
key = string(isPassive ? "-P;" : (isSet ? "-W;" : "-R;")) + name; // second try: without class
map<string, Message*>::iterator it = m_messagesByName.find(key);
if (it != m_messagesByName.end())
return it->second;
}
return NULL;
}
Message* MessageMap::find(SymbolString& master)
{
if (master.size() < 5)
return NULL;
unsigned char maxIdLength = master[4];
if (maxIdLength < m_minIdLength)
return NULL;
if (maxIdLength > m_maxIdLength)
maxIdLength = m_maxIdLength;
if (master.size() < 5+maxIdLength)
return NULL;
unsigned long long sourceMask = 0x1fLL << (8 * 7);
for (int idLength=maxIdLength; idLength>=m_minIdLength; idLength--) {
int exp = 7;
unsigned long long key = (unsigned long long)idLength << (8 * exp + 5);
key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--);
key |= (unsigned long long)master[1] << (8 * exp--);
key |= (unsigned long long)master[2] << (8 * exp--);
key |= (unsigned long long)master[3] << (8 * exp--);
for (unsigned char i=0; i<idLength; i++)
key |= (unsigned long long)master[5 + i] << (8 * exp--);
map<unsigned long long , Message*>::iterator it = m_passiveMessagesByKey.find(key);
if (it != m_passiveMessagesByKey.end())
return it->second;
if ((key & sourceMask) != 0) {
key &= ~sourceMask; // try again without specific source master
it = m_passiveMessagesByKey.find(key);
if (it != m_passiveMessagesByKey.end())
return it->second;
}
}
return NULL;
}
void MessageMap::clear()
{
for (map<string, Message*>::iterator it=m_messagesByName.begin(); it!=m_messagesByName.end(); it++) {
if (it->first[0] != '-') // avoid double free
delete it->second;
it->second = NULL;
}
m_messagesByName.clear();
m_passiveMessagesByKey.clear();
m_maxIdLength = 0;
}
+125 -46
View File
@@ -25,40 +25,36 @@
#include "symbol.h"
#include <string>
#include <vector>
#include <map>
using namespace std;
/**
* @brief Base class for all kinds of bus messages.
* @brief Defines parameters of a message sent or received on the bus.
*/
class Message
{
public:
/**
* @brief Constructs a new instance.
* @brief Construct a new instance.
* @param class the optional device class.
* @param name the message name (unique within the same class and type).
* @param isSetMessage whether this is a set message.
* @param isActiveMessage true if message can be initiated by the daemon
* itself any any other participant, false if message can only be initiated
* by a participant other than the daemon.
* @param isSet whether this is a set message.
* @param isPassive true if message can only be initiated by a participant other than us,
* false if message can be initiated by any participant.
* @param comment the comment.
* @param srcAddress the source address (optional if passive), or @a SYN for any.
* @param srcAddress the source address, or @a SYN for any (only relevant if passive).
* @param dstAddress the destination address.
* @param id the primary, secondary, and optional further ID bytes.
* @param data the @a DataField for encoding/decoding the message.
* @param pollPriority the priority for polling, or 0 for no polling at all.
*/
Message(const string clazz, const string name, const bool isSetMessage,
const bool isActiveMessage, const string comment,
Message(const string clazz, const string name, const bool isSet,
const bool isPassive, const string comment,
const unsigned char srcAddress, const unsigned char dstAddress,
const vector<unsigned char> id, DataField* data,
const unsigned int pollPriority)
: m_class(clazz), m_name(name), m_isSetMessage(isSetMessage),
m_isActiveMessage(isActiveMessage), m_comment(comment),
m_srcAddress(srcAddress), m_dstAddress(dstAddress),
m_id(id), m_data(data), m_pollPriority(pollPriority) {}
const unsigned int pollPriority);
/**
* @brief Destructor.
*/
@@ -67,13 +63,15 @@ public:
* @brief Factory method for creating a new instance.
* @param it the iterator to traverse for the definition parts.
* @param end the iterator pointing to the end of the definition parts.
* @param templates a map of @a DataField templates to be referenced by name.
* @param defaultsRows a @a vector with rows containing defaults, or NULL.
* @param templates the @a DataFieldTemplates to be referenced by name, or NULL.
* @param returnValue the variable in which to store the created instance.
* @return @a RESULT_OK on success, or an error code.
* Note: the caller needs to free the created instance.
*/
static result_t create(vector<string>::iterator& it, const vector<string>::iterator end,
const map<string, DataField*> templates, Message*& returnValue);
vector< vector<string> >* defaultsRows,
DataFieldTemplates* templates, Message*& returnValue);
/**
* @brief Get the optional device class.
* @return the optional device class.
@@ -88,15 +86,13 @@ public:
* @brief Get whether this is a set message.
* @return whether this is a set message.
*/
bool isSetMessage() const { return m_isSetMessage; }
bool isSet() const { return m_isSet; }
/**
* @brief Get whether message can be initiated by the daemon itself and any other
* participant.
* @return true if message can be initiated by the daemon itself and any other
* participant, false if message can only be initiated by a participant
* other than the daemon.
* @brief Get whether message can be initiated only by a participant other than us.
* @return true if message can only be initiated by a participant other than us,
* false if message can be initiated by any participant.
*/
bool isActiveMessage() const { return m_isActiveMessage; }
bool isPassive() const { return m_isPassive; }
/**
* @brief Get the comment.
* @return the comment.
@@ -118,30 +114,47 @@ public:
*/
vector<unsigned char> getId() const { return m_id; }
/**
* @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.
* @param output the @a ostringstream to append the formatted value to.
* @param verbose whether to prepend the name, append the unit (if present), and append
* the comment in square brackets (if present).
* @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code.
* @brief Return the key for storing in @a MessageSet.
* @return the key for storing in @a MessageSet.
*/
//result_t read(SymbolString& masterData, SymbolString& slaveData, ostringstream& output,
// bool verbose=false, char separator=';') = 0;
unsigned long long getKey() { return m_key; }
/**
* @brief Writes the value to the master or slave @a SymbolString.
* @param input the @a istringstream to parse the formatted value from.
* @param masterData the unescaped master data @a SymbolString for writing binary data.
* @param slaveData the unescaped slave data @a SymbolString for writing binary data.
* @brief Get the polling priority, or 0 for no polling at all.
* @return the polling priority, or 0 for no polling at all.
*/
unsigned char getPollPriority() const { return m_pollPriority; }
/**
* @brief Prepare master @a SymbolString for sending to the bus.
* @param masterData the master data @a SymbolString for writing symbols to.
* @param input the @a istringstream to parse the formatted value(s) from.
* @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code.
*/
result_t prepare(const unsigned char srcAddress, SymbolString& masterData,
result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData,
istringstream& input, char separator=';');
result_t handle(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator=';', bool answer=false);
/**
* @brief Decode a received message.
* @param partType the @a PartType of the data.
* @param data the unescaped data @a SymbolString for reading binary data.
* @param output the @a ostringstream to append the formatted value to.
* @param leadingSeparator whether to prepend a separator before the formatted value.
* @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code.
*/
result_t decode(const PartType partType, SymbolString& data,
ostringstream& output, bool leadingSeparator=false, char separator=';');
/**
* @brief Get the last decoded value.
* @return the last decoded value, or the empty string if it was not successful.
*/
string getLastValue() { return m_lastValue; }
/**
* @brief Get the system time when @a m_lastValue was updated.
* @return the system time when @a m_lastValue was updated, or 0 if this message was not decoded yet.
*/
time_t getLastUpdateTime() { return m_lastUpdateTime; }
private:
@@ -150,23 +163,89 @@ private:
/** the message name (unique within the same class and type). */
const string m_name;
/** whether this is a set message. */
const bool m_isSetMessage;
/** true if message can be initiated by the daemon itself and any other
* participant, false if message can only be initiated by a participant
* other than the daemon. */
const bool m_isActiveMessage;
const bool m_isSet;
/** true if message can only be initiated by a participant other than us,
* false if message can be initiated by any participant. */
const bool m_isPassive;
/** the comment. */
const string m_comment;
/** the source address (optional if passive), or @a SYN for any. */
/** the source address, or @a SYN for any (only relevant if passive). */
const unsigned char m_srcAddress;
/** the destination address. */
const unsigned char m_dstAddress;
/** the primary, secondary, and optionally further command ID bytes. */
const vector<unsigned char> m_id;
/** the key for storing in @a MessageSet. */
unsigned long long m_key;
/** the @a DataField for encoding/decoding the message. */
DataField* m_data;
/** the priority for polling, or 0 for no polling at all. */
const unsigned char m_pollPriority;
/** the last decoded value. */
string m_lastValue;
/** the system time when @a m_lastValue was updated. */
time_t m_lastUpdateTime;
};
/**
* @brief Holds a map of all known @a Message instances.
*/
class MessageMap : public FileReader<DataFieldTemplates*>
{
public:
/**
* @brief Construct a new instance.
*/
MessageMap() : FileReader(true), m_minIdLength(4), m_maxIdLength(0) {}
/**
* @brief Destructor.
*/
virtual ~MessageMap() { clear(); }
/**
* @brief Add a @a Message instance to this set.
* @param message the @a Message instance to add.
* @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success.
*/
result_t add(Message* message);
// @copydoc
virtual result_t addFromFile(vector<string>& row, DataFieldTemplates* arg, vector< vector<string> >* defaults);
/**
* @brief Find the @a Message instance for the specified class and name.
* @param class the optional device class.
* @param name the message name.
* @param isSet whether this is a set message.
* @param isPassive whether this is a passive message.
* @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance.
*/
Message* find(const string& clazz, const string& name, const bool isSet, const bool isPassive=false);
/**
* @brief Find the @a Message instance for the specified master data.
* @param master the master @a SymbolString for identifying the @a Message.
* @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance.
*/
Message* find(SymbolString& master);
/**
* @brief Removes all @a Message instances.
*/
void clear();
private:
/** the minimum ID length used by any of the known @a Message instances. */
unsigned char m_minIdLength;
/** the maximum ID length used by any of the known @a Message instances. */
unsigned char m_maxIdLength;
/** the known @a Message instances by class and name. */
map<string, Message*> m_messagesByName;
/** the known passive @a Message instances by key. */
map<unsigned long long, Message*> m_passiveMessagesByKey;
};
+87 -18
View File
@@ -22,9 +22,11 @@
#endif
#include "port.h"
#include "result.h"
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -61,16 +63,16 @@ bool Device::isValid()
ssize_t Device::sendBytes(const unsigned char* buffer, size_t nbytes)
{
if (isValid() == false)
return -1; // TODO RESULT_ERR_DEVICE
return RESULT_ERR_DEVICE;
// write bytes to device
return write(m_fd, buffer, nbytes);
}
ssize_t Device::recvBytes(const long timeout, size_t maxCount)
ssize_t Device::recvBytes(const long timeout, size_t maxCount, unsigned char* buffer)
{
if (isValid() == false)
return -1; // TODO RESULT_ERR_DEVICE
return RESULT_ERR_DEVICE;
if (timeout > 0) {
int ret;
@@ -100,16 +102,26 @@ ssize_t Device::recvBytes(const long timeout, size_t maxCount)
ret = pselect(m_fd + 1, &readfds, NULL, NULL, &tdiff, NULL);
#endif
#endif
if (ret == -1) return RESULT_ERR_DEVICE;
if (ret == 0) return RESULT_ERR_TIMEOUT;
}
if (ret == -1) return -1; // TODO RESULT_ERR_DEVICE
if (ret == 0) return -2; // TODO RESULT_ERR_TIMEOUT
if (buffer != NULL) {
// read bytes from device directly into provided buffer
ssize_t nbytes = read(m_fd, buffer, maxCount);
if (nbytes == 0)
return RESULT_ERR_EOF;
return nbytes;
}
if (maxCount > sizeof(m_buffer))
maxCount = sizeof(m_buffer);
// read bytes from device
// read bytes from device into temporary buffer
ssize_t nbytes = read(m_fd, m_buffer, maxCount);
if (nbytes == 0)
return RESULT_ERR_EOF;
for (int i = 0; i < nbytes; i++)
m_recvBuffer.push(m_buffer[i]);
@@ -132,7 +144,7 @@ unsigned char Device::getByte()
}
void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck)
result_t DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck)
{
m_noDeviceCheck = noDeviceCheck;
struct termios newSettings;
@@ -142,7 +154,7 @@ void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck)
m_fd = open(deviceName.c_str(), O_RDWR | O_NOCTTY);
if (m_fd < 0 || isatty(m_fd) == 0)
return;
return RESULT_ERR_NOTFOUND;
// save current settings
tcgetattr(m_fd, &m_oldSettings);
@@ -151,10 +163,11 @@ void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck)
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_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode
newSettings.c_iflag |= IGNPAR; // ignore parity errors
newSettings.c_oflag &= ~OPOST;
// non-canonical mode: read() blocks until at least one byte is available
newSettings.c_cc[VMIN] = 1;
newSettings.c_cc[VTIME] = 0;
@@ -168,7 +181,7 @@ void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck)
fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL) & ~O_NONBLOCK);
m_open = true;
return RESULT_OK;
}
void DeviceSerial::closeDevice()
@@ -189,7 +202,7 @@ void DeviceSerial::closeDevice()
}
void DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck)
result_t DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck)
{
m_noDeviceCheck = noDeviceCheck;
@@ -210,13 +223,13 @@ void DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck
he = gethostbyname(host);
if (he == NULL)
return;
return RESULT_ERR_NOTFOUND;
memcpy(&sock.sin_addr, he->h_addr_list[0], he->h_length);
} else {
ret = inet_aton(host, &sock.sin_addr);
if (ret == 0)
return;
return RESULT_ERR_NOTFOUND;
}
sock.sin_family = AF_INET;
@@ -224,14 +237,16 @@ void DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck
m_fd = socket(AF_INET, SOCK_STREAM, 0);
if (m_fd < 0)
return;
return RESULT_ERR_GENERIC_IO;
ret = connect(m_fd, (struct sockaddr*) &sock, sizeof(sock));
if (ret < 0)
return;
return RESULT_ERR_GENERIC_IO;
free(hostport);
m_open = true;
return RESULT_OK;
}
void DeviceNetwork::closeDevice()
@@ -246,8 +261,12 @@ void DeviceNetwork::closeDevice()
}
Port::Port(const string deviceName, const bool noDeviceCheck)
: m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck)
Port::Port(const string deviceName, const bool noDeviceCheck,
const bool logRaw, void (*logRawFunc)(const unsigned char byte, bool received),
const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize)
: m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck),
m_logRaw(logRaw), m_logRawFunc(logRawFunc),
m_dumpRawFile(dumpRawFile), m_dumpRawMaxSize(dumpRawMaxSize)
{
m_device = NULL;
@@ -256,6 +275,56 @@ Port::Port(const string deviceName, const bool noDeviceCheck)
setType(dt_network);
else
setType(dt_serial);
m_dumpRaw = false;
setDumpRaw(dumpRaw); // open fstream if necessary
}
unsigned char Port::byte()
{
unsigned char byte = m_device->getByte();
if (m_logRaw == true && m_logRawFunc != NULL)
(*m_logRawFunc)(byte, true);
if (m_dumpRaw == true && m_dumpRawStream.is_open() == true) {
m_dumpRawStream.write((char*)&byte, 1);
if (m_dumpRawStream.tellp() >= m_dumpRawMaxSize * 1024) {
string oldfile = m_dumpRawFile + ".old";
if (rename(m_dumpRawFile.c_str(), oldfile.c_str()) == 0) {
m_dumpRawStream.close();
m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app);
}
}
}
return byte;
}
void Port::setDumpRaw(bool dumpRaw)
{
if (dumpRaw == m_dumpRaw)
return;
m_dumpRaw = dumpRaw;
if (dumpRaw == false)
m_dumpRawStream.close();
else
m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app);
}
void Port::setDumpRawFile(const string& dumpFile) {
if (dumpFile == m_dumpRawFile)
return;
m_dumpRawStream.close();
m_dumpRawFile = dumpFile;
if (m_dumpRaw == true)
m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app);
}
void Port::setType(const DeviceType type)
+90 -14
View File
@@ -24,6 +24,9 @@
#include <queue>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include "result.h"
using namespace std;
@@ -64,7 +67,7 @@ public:
* @param deviceName to determine device type.
* @param noDeviceCheck en-/disable device check.
*/
virtual void openDevice(const string deviceName, const bool noDeviceCheck) = 0;
virtual result_t openDevice(const string deviceName, const bool noDeviceCheck) = 0;
/**
* @brief virtual close function for closing opened file descriptor
@@ -89,9 +92,10 @@ public:
* @brief recvBytes read bytes from opened file descriptor.
* @param timeout time for new input data [usec].
* @param maxCount max size of receive buffer.
* @param buffer optional direct buffer to write to (instead of queuing the data).
* @return number of read bytes or -1 if an error has occured.
*/
ssize_t recvBytes(const long timeout, size_t maxCount);
ssize_t recvBytes(const long timeout, size_t maxCount, unsigned char* buffer=NULL);
/**
* @brief fetch first byte from receive buffer.
@@ -147,7 +151,7 @@ public:
* @param deviceName to determine device type.
* @param noDeviceCheck en-/disable device check.
*/
void openDevice(const string deviceName, const bool noDeviceCheck);
virtual result_t openDevice(const string deviceName, const bool noDeviceCheck);
/**
* @brief close function for closing opened file descriptor
@@ -177,7 +181,7 @@ public:
* @param deviceName to determine device type.
* @param noDeviceCheck en-/disable device check.
*/
void openDevice(const string deviceName, const bool noDeviceCheck);
virtual result_t openDevice(const string deviceName, const bool noDeviceCheck);
/**
* @brief close opened file descriptor
@@ -199,18 +203,25 @@ public:
* @brief constructs a new instance and determine device type.
* @param deviceName to determine device type.
* @param noDeviceCheck en-/disable device check.
* @param logRaw whether logging of raw data is enabled.
* @param logRawFunc a function to call for logging raw data, or NULL.
* @param dumpRaw whether dumping of raw data to a file is enabled.
* @param dumpRawFile the name of the file to dump raw data to.
* @param dumpRawMaxSize the maximum size of @a m_dumpFile.
*/
Port(const string deviceName, const bool noDeviceCheck);
Port(const string deviceName, const bool noDeviceCheck,
const bool logRaw, void (*logRawFunc)(const unsigned char byte, bool received),
const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize);
/**
* @brief destructor.
*/
~Port() { delete m_device; }
~Port() { delete m_device; m_dumpRawStream.close(); }
/**
* @brief open device
*/
void open() { m_device->openDevice(m_deviceName, m_noDeviceCheck); }
result_t open() { return m_device->openDevice(m_deviceName, m_noDeviceCheck); }
/**
* @brief close device
@@ -230,22 +241,33 @@ public:
* @return number of written bytes or -1 if an error has occured.
*/
ssize_t send(const unsigned char* buffer, size_t nbytes = MAX_WRITE_SIZE)
{ return m_device->sendBytes(buffer, nbytes); }
{
ssize_t ret = m_device->sendBytes(buffer, nbytes);
if (ret>0 && m_logRaw == true && m_logRawFunc != NULL)
(*m_logRawFunc)(buffer[0], false);
return ret;
}
/**
* @brief recv read bytes from opened file descriptor.
* @param timeout max time out for new input data.
* @param timeout max time out for new input data [usec], or 0 for infinite.
* @param maxCount max size of receive buffer.
* @return number of read bytes or -1 if an error has occured.
* @param buffer optional direct buffer to write to (instead of queuing the data).
* @return number of read bytes (never 0) or a negative result_t code.
*/
ssize_t recv(const long timeout, size_t maxCount = MAX_READ_SIZE)
{ return m_device->recvBytes(timeout, maxCount); }
ssize_t recv(const long timeout, size_t maxCount = MAX_READ_SIZE, unsigned char* buffer=NULL)
{
ssize_t ret = m_device->recvBytes(timeout, maxCount, buffer);
if (buffer && ret>0 && m_logRaw == true && m_logRawFunc != NULL)
(*m_logRawFunc)(buffer[0], true);
return ret;
}
/**
* @brief fetch first byte from receive buffer.
* @return first byte (raw)
*/
unsigned char byte() { return m_device->getByte(); }
unsigned char byte();
/**
* @brief get current size (bytes) of the receive buffer.
@@ -253,9 +275,45 @@ public:
*/
ssize_t size() const { return m_device->sizeRecvBuffer(); }
/**
* @brief Get whether logging of raw data is enabled.
* @return whether logging of raw data is enabled.
*/
bool getLogRaw() { return m_logRaw; }
/**
* @brief Enable or disable logging of raw data.
* @param logRawData true to enable logging of raw data, false to disable it.
*/
void setLogRaw(bool logRaw=true) { m_logRaw = logRaw; }
/**
* @brief Get whether dumping of raw data to a file is enabled.
* @return whether dumping of raw data to a file is enabled.
*/
bool getDumpRaw() { return m_dumpRaw; }
/**
* @brief Enable or disable dumping of raw data to a file.
* @param dumpRaw true to enable dumping of raw data to a file, false to disable it.
*/
void setDumpRaw(bool dumpRaw=true);
/**
* @brief Set the name of the file to dump raw data to.
* @param dumpFile the name of the file to dump raw data to.
*/
void setDumpRawFile(const string& dumpFile);
/**
* @brief Set the maximum size of a file to dump raw data to.
* @param maxSize the maximum size of a file to dump raw data to.
*/
void setDumpRawMaxSize(const long maxSize) { m_dumpRawMaxSize = maxSize; }
private:
/** the device name */
string m_deviceName;
const string m_deviceName;
/** the device instance */
Device* m_device;
@@ -263,6 +321,24 @@ private:
/** true if device check is disabled */
bool m_noDeviceCheck;
/** whether logging of raw data is enabled. */
bool m_logRaw;
/** a function to call for logging raw data, or NULL. */
void (*m_logRawFunc)(const unsigned char byte, bool received);
/** whether dumping of raw data to a file is enabled. */
bool m_dumpRaw;
/** the name of the file to dump raw data to. */
string m_dumpRawFile;
/** the maximum size of @a m_dumpFile. */
long m_dumpRawMaxSize;
/** the @a ofstream for dumping raw data to. */
ofstream m_dumpRawStream;
/**
* @brief internal setter for device type.
* @param type of device
+26 -17
View File
@@ -23,24 +23,33 @@
using namespace std;
const char* getResultCode(result_t resultCode) {
cout << "DEBUG error code: " << static_cast<signed>(resultCode) << endl;
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";
case RESULT_ERR_EOF: return "ERR_EOF: end of input reached";
default:
if (resultCode >= 0)
return "success";
return "ERR: unknown error code";
case RESULT_OK: return "success";
case RESULT_IN_ESC: return "success: escape sequence received";
case RESULT_SYN: return "success: SYN received";
case RESULT_ERR_GENERIC_IO: return "ERR: generic I/O error";
case RESULT_ERR_DEVICE: return "ERR: generic device error";
case RESULT_ERR_SEND: return "ERR: send error";
case RESULT_ERR_ESC: return "ERR: invalid escape sequence";
case RESULT_ERR_TIMEOUT: return "ERR: read timeout";
case RESULT_ERR_NOTFOUND: return "ERR: file/element not found or not readable";
case RESULT_ERR_EOF: return "ERR: end of input reached";
case RESULT_ERR_INVALID_ARG: return "ERR: invalid argument";
case RESULT_ERR_INVALID_NUM: return "ERR: invalid numeric argument";
case RESULT_ERR_INVALID_POS: return "ERR: invalid position";
case RESULT_ERR_OUT_OF_RANGE: return "ERR: argument value out of valid range";
case RESULT_ERR_INVALID_PART: return "ERR: invalid part type value";
case RESULT_ERR_MISSING_TYPE: return "ERR: missing data type";
case RESULT_ERR_INVALID_LIST: return "ERR: invalid value list";
case RESULT_ERR_DUPLICATE: return "ERR: duplicate entry";
case RESULT_ERR_BUS_LOST: return "ERR: arbitration lost";
case RESULT_ERR_CRC: return "ERR: CRC error";
case RESULT_ERR_ACK: return "ERR: ACK error";
case RESULT_ERR_NAK: return "ERR: NAK received";
default:
if (resultCode >= 0)
return "success: unknown result code";
return "ERR: unknown result code";
}
}
+24 -19
View File
@@ -20,27 +20,32 @@
#ifndef LIBEBUS_RESULT_H_
#define LIBEBUS_RESULT_H_
static const int RESULT_OK = 0;
static const int RESULT_OK = 0; // success
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_IN_ESC = 1; // start of escape sequence received
static const int RESULT_SYN = 2; // regular SYN after message 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)
static const int RESULT_ERR_EOF = -12; // end of input reached
static const int RESULT_ERR_GENERIC_IO = -1; // generic I/O error (usually fatal)
static const int RESULT_ERR_DEVICE = -2; // generic device error (usually fatal)
static const int RESULT_ERR_SEND = -3; // send error
static const int RESULT_ERR_ESC = -4; // invalid escape sequence
static const int RESULT_ERR_TIMEOUT = -5; // read timeout
static const int RESULT_ERR_NOTFOUND = -6; // file/element not found or not readable
static const int RESULT_ERR_EOF = -7; // end of input reached
static const int RESULT_ERR_INVALID_ARG = -8; // invalid argument
static const int RESULT_ERR_INVALID_NUM = -9; // invalid numeric argument
static const int RESULT_ERR_INVALID_POS = -10; // invalid position
static const int RESULT_ERR_OUT_OF_RANGE = -11; // argument value out of valid range
static const int RESULT_ERR_INVALID_PART = -12; // invalid part type value
static const int RESULT_ERR_MISSING_TYPE = -13; // missing data type
static const int RESULT_ERR_INVALID_LIST = -14; // invalid value list
static const int RESULT_ERR_DUPLICATE = -15; // duplicate entry
static const int RESULT_ERR_BUS_LOST = -16; // arbitration lost
static const int RESULT_ERR_CRC = -17; // CRC error
static const int RESULT_ERR_ACK = -18; // ACK error
static const int RESULT_ERR_NAK = -19; // NAK received
/** type for result code. */
typedef int result_t;
+57 -3
View File
@@ -48,7 +48,7 @@ static const unsigned char CRC_LOOKUP_TABLE[] =
};
SymbolString::SymbolString(const string str)
SymbolString::SymbolString(const string& str) //TODO use a factory method instead
: m_unescapeState(0), m_crc(0)
{
// parse + escape
@@ -60,7 +60,18 @@ SymbolString::SymbolString(const string str)
push_back(m_crc, false, false);
}
SymbolString::SymbolString(const string str, bool isEscaped)
SymbolString::SymbolString(const SymbolString& str)
: m_unescapeState(0), m_crc(0)
{
// escape
for (size_t i = 0; i < str.size(); i++) {
push_back(str[i], false, true);
}
// add CRC + escape
push_back(m_crc, false, false);
}
SymbolString::SymbolString(const string& str, bool isEscaped)
: m_unescapeState(1), m_crc(0)
{
// parse + optionally unescape
@@ -99,7 +110,7 @@ const string SymbolString::getDataStr(const bool unescape)
return sstr.str();
}
int SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC)
result_t 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) {
@@ -189,6 +200,49 @@ bool isMaster(unsigned char addr) {
&& ((addrLo == 0x0) || (addrLo == 0x1) || (addrLo == 0x3) || (addrLo == 0x7) || (addrLo == 0xF));
}
unsigned char getMasterNumber(unsigned char addr) {
unsigned char addrHi = (addr & 0xF0) >> 4;
unsigned char addrLo = (addr & 0x0F);
unsigned char priority;
switch (addrLo)
{
case 0x0:
priority = 0;
break;
case 0x1:
priority = 1;
break;
case 0x3:
priority = 2;
break;
case 0x7:
priority = 3;
break;
case 0xF:
priority = 4;
break;
default:
return 0;
}
switch (addrHi)
{
case 0x0:
return 5*0 + priority + 1;
case 0x1:
return 5*1 + priority + 2;
case 0x3:
return 5*2 + priority + 3;
case 0x7:
return 5*3 + priority + 4;
case 0xF:
return 5*4 + priority + 5;
default:
return 0;
}
}
bool isValidAddress(unsigned char addr, bool allowBroadcast) {
return addr != SYN && addr != ESC && (allowBroadcast == true || addr != BROADCAST);
}
+33 -8
View File
@@ -20,6 +20,7 @@
#ifndef LIBEBUS_SYMBOL_H_
#define LIBEBUS_SYMBOL_H_
#include "result.h"
#include <cstring>
#include <cstdlib>
#include <sstream>
@@ -43,20 +44,24 @@ 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 string str);
SymbolString(const string& str);
/**
* @brief Creates a new escaped instance from an unescaped @a SymbolString and adds the calculated CRC.
* @param str the unescaped SymbolString.
*/
SymbolString(const SymbolString& 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 string str, const bool isEscaped);
SymbolString(const string& str, const bool isEscaped);
/**
* @brief Returns the symbols as hex string.
* @param unescape whether to unescape an escaped instance.
@@ -80,7 +85,20 @@ public:
* @param other the other instance.
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols).
*/
bool operator==(SymbolString other) { return m_unescapeState==other.m_unescapeState && m_data==other.m_data; }
bool operator==(SymbolString& other) {
return m_unescapeState==other.m_unescapeState && m_data==other.m_data;
/*bool ret = m_unescapeState==other.m_unescapeState && m_data==other.m_data;
for (int i=0; i<m_data.size(); i++) {
cout<<setw(2)<<setfill('0')<<hex<<static_cast<unsigned>(m_data[i])<<" ";
}
cout<<"["<<static_cast<unsigned>(m_unescapeState)<<"]";
cout<<(ret?" == ":" != ");
for (int i=0; i<other.m_data.size(); i++) {
cout<<setw(2)<<setfill('0')<<hex<<static_cast<unsigned>(other.m_data[i])<<" ";
}
cout<<"["<<static_cast<unsigned>(other.m_unescapeState)<<"]"<<endl;
return ret;*/
}
/**
* @brief Appends a the symbol to the end of the symbol string and escapes/unescapes it if necessary.
* @param value the symbol to append.
@@ -90,12 +108,12 @@ public:
* 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);
result_t push_back(const unsigned char value, const bool isEscaped=true, 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(); }
unsigned char size() const { return (unsigned char)m_data.size(); }
/**
* @brief Returns the calculated CRC.
* @return the calculated CRC.
@@ -131,14 +149,21 @@ private:
/**
* Returns whether the address is one of the 25 master addresses.
* @brief 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);
/**
* Returns whether the address is a valid bus address.
* @brief Returns the number of the master if the address is a valid bus address.
* @param addr the bus address.
* @return the number of the master if the address is a valid bus address (1 to 25), or 0.
*/
unsigned char getMasterNumber(unsigned char addr);
/**
* @brief Returns whether the address is a valid bus address.
* @param addr the address to check.
* @param allowBroadcast whether to also allow @a addr to be the broadcast address (default true).
* @return <code>true</code> if the specified address is a valid bus address.
Regular → Executable
+5 -16
View File
@@ -1,15 +1,13 @@
AM_CXXFLAGS = -fpic \
-Wall \
-Wextra \
-I$(top_srcdir)/src/lib/ebus
-I$(top_srcdir)/src/lib/ebus \
-I$(top_srcdir)/src/lib/utils
noinst_PROGRAMS = test_port \
test_symbol \
test_data \
test_commands \
test_configfile \
test_decode \
test_encode
test_message
test_port_SOURCES = test_port.cpp
test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a
@@ -20,17 +18,8 @@ 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_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
test_message_SOURCES = test_message.cpp
test_message_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a
distclean-local:
-rm -f Makefile.in
-86
View File
@@ -1,86 +0,0 @@
/*
* 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 std;
// will be part of cfg csv class
void readCSV(istream& is, Commands& commands){
string line;
// read lines
while (getline(is, line) != 0) {
vector<string> row;
string column;
int count;
count = 0;
istringstream stream(line);
// walk through columns
while (getline(stream, column, ';') != 0) {
row.push_back(column);
count++;
}
commands.addCommand(row);
}
}
int main()
{
Commands* commands = ConfigCommands("test", ft_csv).getCommands();
cout << "Commands: " << commands->sizeCmdDB() << endl;
//~ string data("g ci password pin1");
string data("s vwxmk DesiredTemp");
int index = commands->findCommand(data);
cout << "found at index: " << index << endl;
// prepare data
string token;
istringstream stream(data);
vector<string> cmd;
// split stream
while (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");
//~ string result = command->calcResult(cmd);
string result = command->calcData();
cout << "result: " << result << endl;
delete command;
return 0;
}
-47
View File
@@ -1,47 +0,0 @@
/*
* 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 std;
int main() {
string dir("test");
ConfigCommands config(dir, ft_csv);
Commands* commands = config.getCommands();
cout << "size: " << commands->sizeCmdDB() << endl;
commands->findCommand("g ci Password");
cout << (*commands)[0][0] << endl;
delete commands;
return 0;
}
+22 -16
View File
@@ -68,6 +68,9 @@ int main()
{"x;;bti", "00:00:00", "10fe070003000000", "00", ""},
{"x;;bti", "23:59:59", "10fe070003595923", "00", ""},
{"x;;bti", "", "10fe070003605923", "00", "rw"},
{"x;;hti", "21:04:58", "10fe07000315043a", "00", ""},
{"x;;vti", "21:04:58", "10fe0700033a0415", "00", ""},
{"x;;vti", "-:-:-", "10fe070003636363", "00", ""},
{"x;;htm", "21:04", "10fe0700021504", "00", ""},
{"x;;htm", "00:00", "10fe0700020000", "00", ""},
{"x;;htm", "23:59", "10fe070002173b", "00", ""},
@@ -77,7 +80,7 @@ int main()
{"x;;ttm", "22:40", "10fe07000188", "00", ""},
{"x;;ttm", "00:00", "10fe07000100", "00", ""},
{"x;;ttm", "23:50", "10fe0700018f", "00", ""},
{"x;;ttm", "24:00", "10fe07000190", "00", ""},
{"x;;ttm", "-:-", "10fe07000190", "00", ""},
{"x;;ttm", "", "10fe07000191", "00", "rw"},
{"x;;bdy", "Mon", "10fe07000300", "00", ""},
{"x;;bdy", "Sun", "10fe07000306", "00", ""},
@@ -94,7 +97,7 @@ int main()
{"x;;uch:17", "", "10feffff00", "00", "c"},
{"x;s;uch", "0", "1025ffff0310111213", "0300010203", "W"},
{"x;s;uch", "0", "1025ffff00", "0100", ""},
{"x;s;uch;;;;y;m;uch", "2;3","1025ffff0103", "0102", ""},
{"x;s;uch;;;;y;m;uch", "3;2","1025ffff0103", "0102", ""},
{"x;;uch", "38", "10feffff0126", "00", ""},
{"x;;uch", "0", "10feffff0100", "00", ""},
{"x;;uch", "254", "10feffff01fe", "00", ""},
@@ -165,7 +168,7 @@ int main()
{"x;;bi3:2;0=off,1=on","off","10feffff0100", "00", ""},
{"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""},
{"x;s;uch","3","1050ffff00", "0103", ""},
{"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"},
{"x;;d2b;;C;Aussentemperatur","x=18.004 C [Aussentemperatur]","10fe0700090112", "00", "v"},
{"x;;bti;;;;y;;bda;;;;z;;bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610061406", "00", ""}, // combination
{"x;;bi3;;;;y;;bi5", "1;-", "10feffff0108", "00", ""}, // bit combination
{"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
@@ -173,7 +176,7 @@ int main()
{"x;;bi3;;;;y;;bi5", "-;-", "10feffff0100", "00", ""}, // bit combination
{"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination
{"x;;bi6:2;;;;y;;bi0:2;;;;t;;uch", "2;1;9","10feffff03800109", "00", ""}, // bit combination
{"temp;;d2b;;°C;Aussentemperatur","","", "", "t"}, // template with relative pos
{"temp;;d2b;;C;Aussentemperatur","","", "", "t"}, // template with relative pos
{"x;;temp","18.004","10fe0700020112", "00", ""}, // reference to template
{"relrel;;d2b;;;;y;;d1c","","", "", "t"}, // template struct with relative pos
{"x;;relrel","18.004;9.5","10fe070003011213", "00", ""}, // reference to template struct
@@ -181,7 +184,7 @@ int main()
{"x;;trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct
{"x;;temp;;;;y;;d1c","18.004;9.5","10fe070003011213", "00", ""}, // reference to template, normal def
};
map<string, DataField*> templates;
DataFieldTemplates* templates = new DataFieldTemplates();
DataField* fields = NULL;
for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) {
string check[5] = checks[i];
@@ -233,21 +236,23 @@ int main()
if (isTemplate) {
// store new template
string name = fields->getName();
map<string, DataField*>::iterator current = templates.find(name);
if (current == templates.end()) {
templates[name] = fields;
} else {
delete current->second;
current->second = fields;
result = templates->add(fields, true);
if (result == RESULT_OK) {
fields = NULL;
cout << " store template OK" << endl;
}
fields = NULL;
else
cout << " store template error: " << getResultCode(result) << endl;
continue;
}
ostringstream output;
SymbolString writeMstr = SymbolString(mstr.getDataStr().substr(0, 10), false);
SymbolString writeSstr = SymbolString(sstr.getDataStr().substr(0, 2), false);
result = fields->read(mstr, 0, sstr, 0, output, verbose);
result = fields->read(pt_masterData, mstr, 0, output, false, verbose);
if (result == RESULT_OK) {
result = fields->read(pt_slaveData, sstr, 0, output, output.str().empty() == false, verbose);
}
if (failedRead == true)
if (result == RESULT_OK)
cout << " failed read " << fields->getName() << " >"
@@ -266,7 +271,9 @@ int main()
if (verbose == false) {
istringstream input(expectStr);
result = fields->write(input, writeMstr, 0, writeSstr, 0);
result = fields->write(input, pt_masterData, writeMstr, 0);
if (result == RESULT_OK)
result = fields->write(input, pt_slaveData, writeSstr, 0);
if (failedWrite == true) {
if (result == RESULT_OK)
cout << " failed write " << fields->getName() << " >"
@@ -288,8 +295,7 @@ int main()
fields = NULL;
}
for (map<string, DataField*>::iterator it = templates.begin(); it != templates.end(); it++)
delete it->second;
delete templates;
return 0;
-308
View File
@@ -1,308 +0,0 @@
/*
* 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 std;
int main()
{
Decode* help_dec = NULL;
cout << endl;
// HEX
{
const char* hex[] = {"53706569636865722020"};
for (size_t i = 0; i < sizeof(hex)/sizeof(hex[0]); i++) {
help_dec = new DecodeHEX(hex[i]);
cout << "DecodeHEX: " << setw(20) << hex[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeUCH: " << setw(20) << uch[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeSCH: " << setw(20) << sch[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeUIN: " << setw(20) << uin[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeSIN: " << setw(20) << sin[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeULG: " << setw(20) << ulg[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeSLG: " << setw(20) << slg[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeFLT: " << setw(20) << flt[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeSTR: " << setw(20) << str[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeBCD: " << setw(20) << bcd[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeD1B: " << setw(20) << d1b[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeD1C: " << setw(20) << d1c[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeD2B: " << setw(20) << d2b[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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");
cout << "DecodeD2C: " << setw(20) << d2c[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeBDA: " << setw(20) << bda[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeHDA: " << setw(20) << hda[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeBTI: " << setw(20) << bti[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeHTI: " << setw(20) << hti[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeBDY: " << setw(20) << bdy[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeHDY: " << setw(20) << hdy[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << 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]);
cout << "DecodeTTM: " << setw(20) << ttm[i] << " = " << help_dec->decode() << endl;
delete help_dec;
}
cout << endl;
}
return 0;
}
-309
View File
@@ -1,309 +0,0 @@
/*
* 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 std;
int main()
{
Encode* help_enc = NULL;
cout << 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]);
cout << "EncodeHEX: " << setw(20) << hex[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeUCH: " << setw(20) << uch[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeSCH: " << setw(20) << sch[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeUIN: " << setw(20) << uin[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeSIN: " << setw(20) << sin[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeULG: " << setw(20) << ulg[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeSLG: " << setw(20) << slg[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeFLT: " << setw(20) << flt[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeSTR: " << setw(20) << str[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeBCD: " << setw(20) << bcd[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeD1B: " << setw(20) << d1b[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeD1C: " << setw(20) << d1c[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeD2B: " << setw(20) << d2b[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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");
cout << "EncodeD2C: " << setw(20) << d2c[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeBDA: " << setw(20) << bda[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeHDA: " << setw(20) << hda[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeBTI: " << setw(20) << bti[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeHTI: " << setw(20) << hti[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeBDY: " << setw(20) << bdy[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeHDY: " << setw(20) << hdy[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << 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]);
cout << "EncodeTTM: " << setw(20) << ttm[i] << " = " << help_enc->encode() << endl;
delete help_enc;
}
cout << endl;
}
return 0;
}
+118 -76
View File
@@ -19,6 +19,7 @@
#include "message.h"
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
@@ -40,42 +41,37 @@ void verify(bool expectFailMatch, string type, string input,
<< gotStr << "<, expected >" << expectStr << "<" << endl;
}
void printErrorPos(vector<string>::iterator it, const vector<string>::iterator end, vector<string>::iterator pos)
{
cout << "Errroneous item is here:" << endl;
bool first = true;
int cnt = 0;
if (pos > it)
pos--;
while (it != end) {
if (first == true)
first = false;
else {
cout << ';';
if (it <= pos) {
cnt++;
}
}
if (it < pos) {
cnt += (*it).length();
}
cout << (*it++);
}
cout << endl;
cout << setw(cnt) << " " << setw(0) << "^" << endl;
}
int main()
{
// message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields...
// field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]]
string checks[][5] = {
// "message", "flags"
{";;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""},
{"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", ""},
{"u;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"},
{"w;;first;;;15;b509;0400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"},
{"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"},
{"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"},
{"u;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "pm"},
{"uw;ehp;test;Test;;08;B5de;ab;;;power;;;;;s;hex:1", "8;39", "1008b5de02ab08", "0139", "pm"},
{"","55.50;ok","1025b50903290000","050000780300",""},
{"","no;25","10feb505042700190023","",""},
};
map<string, DataField*> templates;
DataFieldTemplates* templates = new DataFieldTemplates();
result_t result = templates->readFromFile("_types.csv");
if (result == RESULT_OK)
cout << "read templates OK" << endl;
else
cout << "read templates error: " << getResultCode(result) << endl;
MessageMap* messages = new MessageMap();
result = messages->readFromFile("neu-ehp00.csv", templates);
if (result == RESULT_OK)
cout << "read messages OK" << endl;
else
cout << "read messages error: " << getResultCode(result) << endl;
Message* message = NULL;
Message* deleteMessage = NULL;
for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) {
string check[5] = checks[i];
istringstream isstr(check[0]);
@@ -83,6 +79,7 @@ int main()
SymbolString mstr = SymbolString(check[2], false);
SymbolString sstr = SymbolString(check[3], false);
string flags = check[4];
bool dontMap = flags.find('m') != string::npos;
bool failedCreate = flags.find('c') != string::npos;
bool failedPrepare = flags.find('p') != string::npos;
bool failedPrepareMatch = flags.find('P') != string::npos;
@@ -92,63 +89,108 @@ int main()
while (getline(isstr, item, ';') != 0)
entries.push_back(item);
if (message != NULL) {
delete message;
message = NULL;
if (deleteMessage != NULL) {
delete deleteMessage;
deleteMessage = NULL;
}
vector<string>::iterator it = entries.begin();
result_t result = Message::create(it, entries.end(), templates, message);
if (failedCreate == true) {
if (result == RESULT_OK)
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
if (entries.size() == 0) {
message = messages->find(mstr);
if (message == NULL) {
cout << "\"" << check[2] << "\": find error: NULL" << endl;
continue;
}
cout << "\"" << check[2] << "\": find OK" << endl;
} else {
vector<string>::iterator it = entries.begin();
result = Message::create(it, entries.end(), NULL, templates, deleteMessage);
if (failedCreate == true) {
if (result == RESULT_OK)
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
else
cout << "\"" << check[0] << "\": failed create OK" << endl;
continue;
}
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": create error: "
<< getResultCode(result) << endl;
printErrorPos(entries.begin(), entries.end(), it);
continue;
}
if (deleteMessage == NULL) {
cout << "\"" << check[0] << "\": create error: NULL" << endl;
continue;
}
if (it != entries.end()) {
cout << "\"" << check[0] << "\": create error: trailing input" << endl;
continue;
}
cout << "\"" << check[0] << "\": create OK" << endl;
if (dontMap == false) {
result_t result = messages->add(deleteMessage);
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": add error: "
<< getResultCode(result) << endl;
continue;
}
cout << " map OK" << endl;
message = deleteMessage;
deleteMessage = NULL;
Message* foundMessage = messages->find(mstr);
if (foundMessage == message)
cout << " find OK" << endl;
else if (foundMessage == NULL)
cout << " find error: NULL" << endl;
else
cout << " find error: different" << endl;
}
else
cout << "\"" << check[0] << "\": failed create OK" << endl;
continue;
message = deleteMessage;
}
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": create error: "
<< getResultCode(result) << endl;
printErrorPos(entries.begin(), entries.end(), it);
continue;
}
if (message == NULL) {
cout << "\"" << check[0] << "\": create error: NULL" << endl;
continue;
}
if (it != entries.end()) {
cout << "\"" << check[0] << "\": create error: trailing input" << endl;
continue;
}
cout << "\"" << check[0] << "\": create OK" << endl;
istringstream input(inputStr);
SymbolString writeMstr = SymbolString();
result = message->prepare(0xff, writeMstr, input);
if (failedPrepare == true) {
if (message->isPassive() == true) {
ostringstream output;
result = message->decode(pt_masterData, mstr, output);
if (result == RESULT_OK)
cout << "\"" << check[0] << "\": failed prepare error: unexpectedly succeeded" << endl;
else
cout << "\"" << check[0] << "\": failed prepare OK" << endl;
continue;
result = message->decode(pt_slaveData, sstr, output, output.str().empty() == false);
if (result != RESULT_OK) {
cout << " \"" << inputStr << "\": decode error: "
<< getResultCode(result) << endl;
continue;
}
cout << " \"" << inputStr << "\": decode OK" << endl;
bool match = inputStr == output.str();
verify(false, "decode", check[2] + "/" + check[3], match, inputStr, output.str());
} else {
result = message->prepareMaster(0xff, writeMstr, input);
if (failedPrepare == true) {
if (result == RESULT_OK)
cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl;
else
cout << " \"" << inputStr << "\": failed prepare OK" << endl;
continue;
}
if (result != RESULT_OK) {
cout << " \"" << inputStr << "\": prepare error: "
<< getResultCode(result) << endl;
continue;
}
cout << " \"" << inputStr << "\": prepare OK" << endl;
bool match = writeMstr==mstr;
verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr());
}
if (result != RESULT_OK) {
cout << " prepare >" << inputStr << "< error: "
<< getResultCode(result) << endl;
continue;
}
cout << " prepare >" << inputStr << "< OK" << endl;
bool match = writeMstr==mstr;
verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr());
delete message;
message = NULL;
}
for (map<string, DataField*>::iterator it = templates.begin(); it != templates.end(); it++)
delete it->second;
if (deleteMessage != NULL) {
delete deleteMessage;
deleteMessage = NULL;
}
delete templates;
delete messages;
return 0;
+1 -1
View File
@@ -26,7 +26,7 @@ using namespace std;
int main ()
{
string dev("/dev/ttyUSB20");
Port port(dev, true);
Port port(dev, true, false, NULL, false, "", 1);
port.open();
+8 -8
View File
@@ -30,17 +30,17 @@ int main ()
std::string gotStr = sstr.getDataStr(false), expectStr = "10feb5050427a90015a90177";
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
std::cout << "ctor escaped successful." << std::endl;
std::cout << "ctor escaped OK" << std::endl;
else
std::cout << "ctor escaped invalid: got " << gotStr << ", expected "
std::cout << "ctor escaped error: got " << gotStr << ", expected "
<< expectStr << std::endl;
unsigned char gotCrc = sstr.getCRC(), expectCrc = 0x77;
if (gotCrc == expectCrc)
std::cout << "CRC successful." << std::endl;
std::cout << "CRC OK" << std::endl;
else
std::cout << "CRC invalid: got 0x" << std::nouppercase << std::setw(2)
std::cout << "CRC error: 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
@@ -50,9 +50,9 @@ int main ()
gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa77";
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
std::cout << "unescape successful." << std::endl;
std::cout << "unescape OK" << std::endl;
else
std::cout << "unescape invalid: got " << gotStr << ", expected "
std::cout << "unescape error: got " << gotStr << ", expected "
<< expectStr << std::endl;
sstr = SymbolString("10feb5050427a90015a90177", true);
@@ -60,9 +60,9 @@ int main ()
gotStr = sstr.getDataStr();
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
std::cout << "ctor unescaped successful." << std::endl;
std::cout << "ctor unescaped OK" << std::endl;
else
std::cout << "ctor unescaped invalid: got " << gotStr << ", expected "
std::cout << "ctor unescaped error: got " << gotStr << ", expected "
<< expectStr << std::endl;
return 0;
Regular → Executable
View File
+3
View File
@@ -160,6 +160,9 @@ void Appl::setOptVal(const char* option, const string value, DataType datatype)
case dt_bool:
m_optvals[option] = true;
break;
case dt_hex:
m_optvals[option] = strtol(value.c_str(), NULL, 16);
break;
case dt_int:
m_optvals[option] = strtol(value.c_str(), NULL, 10);
break;
+2 -1
View File
@@ -33,7 +33,8 @@ using namespace std;
enum DataType {
dt_none, /*!< default for __text_only__ */
dt_bool, /*!< boolean */
dt_int, /*!< integer */
dt_hex, /*!< hex integer */
dt_int, /*!< dec integer */
dt_long, /*!< long */
dt_float, /*!< float */
dt_string /*!< string */
+10 -12
View File
@@ -100,7 +100,7 @@ void LogSink::addMessage(const LogMessage& message)
m_logQueue.add((tmp));
}
void* LogSink::run()
void LogSink::run()
{
while (1) {
LogMessage* message = m_logQueue.remove();
@@ -111,13 +111,12 @@ void* LogSink::run()
write(*message);
delete message;
}
return NULL;
return;
}
write(*message);
delete message;
}
return NULL;
}
@@ -187,7 +186,7 @@ Logger& Logger::operator-=(const LogSink* sink)
void Logger::log(const int area, const int level, const string& data, ...)
{
if (m_running == true) {
if (isRunning() == true) {
char* tmp;
va_list ap;
va_start(ap, data);
@@ -203,11 +202,11 @@ void Logger::log(const int area, const int level, const string& data, ...)
}
void* Logger::run()
void Logger::run()
{
m_running = true;
bool running = true;
while (m_running == true) {
do {
LogMessage* message = m_logQueue.remove();
sinkCI_t iter = m_sinks.begin();
@@ -215,28 +214,27 @@ void* Logger::run()
for (; iter != m_sinks.end(); ++iter) {
if (*iter != 0) {
if (((*iter)->getAreas() & message->getArea()
if ((((*iter)->getAreas() & message->getArea()) != 0
&& (*iter)->getLevel() >= message->getLevel())
&& message->isRunning() == true) {
(*iter)->addMessage(*message);
}
else if (message->isRunning() == false) {
(*iter)->addMessage(*message);
m_running = false;
running = false;
}
}
}
delete message;
}
return NULL;
} while (running == true);
}
void Logger::stop()
{
m_logQueue.add(new LogMessage(LogMessage(bas, error, "", false)));
usleep(100000);
Thread::stop();
}
+3 -8
View File
@@ -143,9 +143,8 @@ public:
/**
* @brief endless loop for logging sink instance.
* @return void pointer.
*/
void* run();
void run();
/**
* @brief get the logging areas.
@@ -294,14 +293,13 @@ public:
/**
* @brief endless loop for logger instance.
* @return void pointer.
*/
void* run();
virtual void run();
/**
* @brief shutdown logger subsystem.
*/
void stop();
virtual void stop();
private:
/**
@@ -334,9 +332,6 @@ private:
/** queue for logging messages */
WQueue<LogMessage*> m_logQueue;
/** true if this instance is running */
bool m_running;
};
#endif // LIBUTILS_LOGGER_H_
+25 -19
View File
@@ -23,25 +23,22 @@
#include "thread.h"
/**
* @brief static function which will be called on thread startup.
* @return void pointer.
*/
static void* runThread(void* arg)
void* Thread::runThread(void* arg)
{
return ((Thread*)arg)->run();
((Thread*)arg)->enter();
return NULL;
}
Thread::~Thread()
{
if (m_running == true && m_detached == false)
if (m_started == true && m_detached == false)
pthread_detach(m_threadid);
if (m_running == true)
if (m_started == true)
pthread_cancel(m_threadid);
}
int Thread::start(const char* name)
bool Thread::start(const char* name)
{
int result = pthread_create(&m_threadid, NULL, runThread, this);
@@ -52,32 +49,36 @@ int Thread::start(const char* name)
pthread_setname_np(m_threadid, name);
#endif
m_running = true;
m_started = true;
return true;
}
return result;
return false;
}
int Thread::join()
bool Thread::join()
{
int result = -1;
if (m_running == true) {
if (m_started == true) {
m_stopped = true;
result = pthread_join(m_threadid, NULL);
if (result == 0)
if (result == 0) {
m_detached = false;
m_started = false;
}
}
return result;
return result == 0;
}
int Thread::detach()
bool Thread::detach()
{
int result = -1;
if (m_running == true && m_detached == false) {
if (m_started == true && m_detached == false) {
result = pthread_detach(m_threadid);
if (result == 0)
@@ -85,6 +86,11 @@ int Thread::detach()
}
return result;
return result == 0;
}
void Thread::enter() {
m_running = true;
run();
m_running = false;
}
+47 -18
View File
@@ -32,7 +32,7 @@ public:
/**
* @brief constructor.
*/
Thread() : m_threadid(0), m_running(false), m_detached(false) {}
Thread() : m_threadid(0), m_started(false), m_running(false), m_stopped(false), m_detached(false) {}
/**
* @brief virtual destructor.
@@ -40,44 +40,73 @@ public:
virtual ~Thread();
/**
* @brief create the thread and set name for process list.
* @param name the thread name which show in process list.
* @return value of thread creating.
* @brief Thread entry helper for pthread_create.
* @param arg pointer to the @a Thread.
* @return NULL.
*/
int start(const char* name);
static void* runThread(void* arg);
/**
* @brief join the thread.
* @return value of thread joining.
* @brief Return whether this @a Thread is still running and not yet stopped.
* @return true if this @a Thread is till running and not yet stopped.
*/
int join();
virtual bool isRunning() { return m_running == true && m_stopped == false; }
/**
* @brief detach the thread.
* @return value of thread detaching.
* @brief Create the native thread and set its name.
* @param name the thread name to show in the process list.
* @return whether the thread was started.
*/
int detach();
virtual bool start(const char* name);
/**
* @brief return the thread id.
* @return own thread id.
* @brief Notify the thread that it shall stop.
*/
virtual void stop() { m_stopped = true; }
/**
* @brief Join the thread.
* @return whether the thread was joined.
*/
virtual bool join();
/**
* @brief Detach the thread.
* @return whether the thread was detached.
*/
virtual bool detach();
/**
* @brief Get the thread id.
* @return the thread id.
*/
pthread_t self() {return m_threadid; }
/**
* @brief virtul function which must be implemented in derived class.
* @return void pointer.
* @brief Thread entry method to be overridden by derived class.
*/
virtual void* run() = 0;
virtual void run() = 0;
private:
/**
* @brief Enter the Thread loop by calling run().
*/
void enter();
/** own thread id */
pthread_t m_threadid;
/** true if thread is running */
/** Whether the thread was started. */
bool m_started;
/** Whether the thread is still running (i.e. in @a run() ). */
bool m_running;
/** true if thread is detached */
/** Whether the thread was stopped by @a stop() or @a join(). */
bool m_stopped;
/** Whether the thread was detached */
bool m_detached;
};
+44 -14
View File
@@ -67,17 +67,25 @@ public:
/**
* @brief remove the first item from queue.
* @return the item.
* @param wait true to wait for an item to be added to the queue, false to return NULL if no item is available.
* @return the item, or NULL if no item is available and wait was false.
*/
T remove()
T remove(bool wait=true)
{
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();
T item;
if (wait == true) {
while (m_queue.size() == 0)
pthread_cond_wait(&m_cond, &m_mutex);
item = m_queue.front();
m_queue.pop_front();
}
else if (m_queue.size() > 0) {
item = m_queue.front();
m_queue.pop_front();
} else
item = NULL;
pthread_mutex_unlock(&m_mutex);
@@ -85,17 +93,39 @@ public:
}
/**
* @brief return the first item from queue without remove.
* @return the item.
* @brief Remove the specified item from queue.
* @param item the item to remove.
* @return whether the item was removed.
*/
T next()
bool remove(T item)
{
pthread_mutex_lock(&m_mutex);
int oldSize = m_queue.size();
if (oldSize > 0)
m_queue.remove(item);
int newSize = m_queue.size();
pthread_mutex_unlock(&m_mutex);
return newSize != oldSize;
}
/**
* @brief return the first item from queue without remove.
* @return the item, or NULL if no item is available and wait was false.
*/
T next(bool wait=true)
{
pthread_mutex_lock(&m_mutex);
while (m_queue.size() == 0)
pthread_cond_wait(&m_cond, &m_mutex);
T item = m_queue.front();
T item;
if (wait == true) {
while (m_queue.size() == 0)
pthread_cond_wait(&m_cond, &m_mutex);
item = m_queue.front();
}
else if (m_queue.size() > 0)
item = m_queue.front();
else
item = NULL;
pthread_mutex_unlock(&m_mutex);