Merge pull request #18 from john30/master; first version supporting get, set, and cyc again.
This commit is contained in:
Regular → Executable
+4
-11
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
@@ -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 << ';';
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
@@ -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_
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user