2018-04-01 06:53:37 +00:00
|
|
|
/*
|
2020-01-27 08:29:40 +00:00
|
|
|
Copyright (C) 2019-2020 Fredrik Öhrström
|
2018-04-01 06:53:37 +00:00
|
|
|
|
|
|
|
This program 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.
|
|
|
|
|
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2018-03-05 10:29:25 +00:00
|
|
|
|
|
|
|
#include"wmbus.h"
|
2020-01-27 08:29:40 +00:00
|
|
|
#include"wmbus_utils.h"
|
2018-03-05 10:29:25 +00:00
|
|
|
#include"serial.h"
|
|
|
|
|
|
|
|
#include<assert.h>
|
|
|
|
#include<fcntl.h>
|
|
|
|
#include<pthread.h>
|
|
|
|
#include<semaphore.h>
|
2020-05-11 09:59:47 +00:00
|
|
|
#include<errno.h>
|
2018-03-05 10:29:25 +00:00
|
|
|
#include<sys/types.h>
|
|
|
|
#include<unistd.h>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2020-01-27 08:29:40 +00:00
|
|
|
struct WMBusSimulator : public WMBusCommonImplementation
|
|
|
|
{
|
2018-03-05 10:29:25 +00:00
|
|
|
bool ping();
|
|
|
|
uint32_t getDeviceId();
|
2019-06-06 15:28:20 +00:00
|
|
|
LinkModeSet getLinkModes();
|
2020-08-01 19:56:46 +00:00
|
|
|
void deviceReset();
|
|
|
|
void deviceSetLinkModes(LinkModeSet lms);
|
2019-06-06 15:28:20 +00:00
|
|
|
LinkModeSet supportedLinkModes() { return Any_bit; }
|
|
|
|
int numConcurrentLinkModes() { return 0; }
|
|
|
|
bool canSetLinkModes(LinkModeSet lms) { return true; }
|
2018-03-05 10:29:25 +00:00
|
|
|
|
|
|
|
void processSerialData();
|
|
|
|
void simulate();
|
2020-08-01 19:56:46 +00:00
|
|
|
string device() { return file_; }
|
2018-03-05 10:29:25 +00:00
|
|
|
|
|
|
|
WMBusSimulator(string file, SerialCommunicationManager *manager);
|
|
|
|
|
|
|
|
private:
|
|
|
|
vector<uchar> received_payload_;
|
|
|
|
vector<function<void(Telegram*)>> telegram_listeners_;
|
|
|
|
|
|
|
|
string file_;
|
2019-06-06 15:28:20 +00:00
|
|
|
LinkModeSet link_modes_;
|
2018-03-05 10:29:25 +00:00
|
|
|
vector<string> lines_;
|
|
|
|
};
|
|
|
|
|
|
|
|
int loadFile(string file, vector<string> *lines);
|
|
|
|
|
2019-11-03 15:31:30 +00:00
|
|
|
unique_ptr<WMBus> openSimulator(string device, SerialCommunicationManager *manager, unique_ptr<SerialDevice> serial_override)
|
2018-03-05 10:29:25 +00:00
|
|
|
{
|
|
|
|
WMBusSimulator *imp = new WMBusSimulator(device, manager);
|
2018-12-28 17:35:32 +00:00
|
|
|
return unique_ptr<WMBus>(imp);
|
2018-03-05 10:29:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WMBusSimulator::WMBusSimulator(string file, SerialCommunicationManager *manager)
|
2020-08-01 19:56:46 +00:00
|
|
|
: WMBusCommonImplementation(DEVICE_SIMULATOR, manager, NULL), file_(file)
|
2018-03-05 10:29:25 +00:00
|
|
|
{
|
|
|
|
vector<string> lines;
|
|
|
|
loadFile(file, &lines_);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WMBusSimulator::ping() {
|
|
|
|
verbose("(simulator) ping\n");
|
|
|
|
verbose("(simulator) pong\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t WMBusSimulator::getDeviceId() {
|
|
|
|
verbose("(simulator) get device info\n");
|
|
|
|
verbose("(simulator) device info: 11111111\n");
|
|
|
|
return 0x11111111;
|
|
|
|
}
|
|
|
|
|
2019-06-06 15:28:20 +00:00
|
|
|
LinkModeSet WMBusSimulator::getLinkModes() {
|
2018-03-05 10:29:25 +00:00
|
|
|
verbose("(simulator) get link mode\n");
|
2019-06-06 15:28:20 +00:00
|
|
|
string hr = link_modes_.hr();
|
|
|
|
verbose("(simulator) config: link mode %s\n", hr.c_str());
|
|
|
|
return link_modes_;
|
2018-03-05 10:29:25 +00:00
|
|
|
}
|
|
|
|
|
2020-08-01 19:56:46 +00:00
|
|
|
void WMBusSimulator::deviceReset()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void WMBusSimulator::deviceSetLinkModes(LinkModeSet lms)
|
2018-03-05 10:29:25 +00:00
|
|
|
{
|
2019-06-06 15:28:20 +00:00
|
|
|
link_modes_ = lms;
|
|
|
|
string hr = lms.hr();
|
|
|
|
verbose("(simulator) set link mode %s\n", hr.c_str());
|
2018-03-05 10:29:25 +00:00
|
|
|
verbose("(simulator) set link mode completed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int loadFile(string file, vector<string> *lines)
|
|
|
|
{
|
|
|
|
char block[32768+1];
|
|
|
|
vector<uchar> buf;
|
|
|
|
|
|
|
|
int fd = open(file.c_str(), O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
while (true) {
|
|
|
|
ssize_t n = read(fd, block, sizeof(block));
|
|
|
|
if (n == -1) {
|
|
|
|
if (errno == EINTR) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
error("Could not read file %s errno=%d\n", file.c_str(), errno);
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
buf.insert(buf.end(), block, block+n);
|
|
|
|
if (n < (ssize_t)sizeof(block)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
bool eof, err;
|
|
|
|
auto i = buf.begin();
|
|
|
|
for (;;) {
|
|
|
|
string line = eatTo(buf, i, '\n', 32768, &eof, &err);
|
|
|
|
if (err) {
|
|
|
|
error("Error parsing simulation file.\n");
|
|
|
|
}
|
|
|
|
if (line.length() > 0) {
|
|
|
|
lines->push_back(line);
|
|
|
|
}
|
|
|
|
if (eof) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WMBusSimulator::simulate()
|
|
|
|
{
|
2018-03-05 14:12:58 +00:00
|
|
|
time_t start_time = time(NULL);
|
|
|
|
|
2020-08-01 19:56:46 +00:00
|
|
|
for (auto l : lines_)
|
|
|
|
{
|
2018-03-05 10:29:25 +00:00
|
|
|
string hex = "";
|
2018-03-05 14:12:58 +00:00
|
|
|
int found_time = 0;
|
|
|
|
time_t rel_time = 0;
|
2020-08-01 19:56:46 +00:00
|
|
|
if (l.substr(0,9) == "telegram=")
|
|
|
|
{
|
|
|
|
for (size_t i=9; i<l.length(); ++i)
|
|
|
|
{
|
2018-03-05 10:29:25 +00:00
|
|
|
if (l[i] == '|') continue;
|
2020-08-01 19:56:46 +00:00
|
|
|
if (l[i] == '+')
|
|
|
|
{
|
2018-03-05 14:12:58 +00:00
|
|
|
found_time = i;
|
|
|
|
rel_time = atoi(&l[i+1]);
|
|
|
|
break;
|
|
|
|
}
|
2018-03-05 10:29:25 +00:00
|
|
|
hex += l[i];
|
|
|
|
}
|
2020-08-01 19:56:46 +00:00
|
|
|
if (found_time)
|
|
|
|
{
|
2018-11-25 11:33:14 +00:00
|
|
|
debug("(simulator) from file \"%s\" to trigger at relative time %ld\n", hex.c_str(), rel_time);
|
2018-03-05 14:12:58 +00:00
|
|
|
time_t curr = time(NULL);
|
2020-08-01 19:56:46 +00:00
|
|
|
if (curr < start_time+rel_time)
|
|
|
|
{
|
2018-11-25 11:33:14 +00:00
|
|
|
debug("(simulator) waiting %d seconds before simulating telegram.\n", (start_time+rel_time)-curr);
|
2020-08-01 19:56:46 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
2018-03-05 14:12:58 +00:00
|
|
|
curr = time(NULL);
|
|
|
|
if (curr > start_time + rel_time) break;
|
|
|
|
usleep(1000*1000);
|
2020-08-01 19:56:46 +00:00
|
|
|
if (!manager_->isRunning()) break;
|
2018-03-05 14:12:58 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-01 19:56:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-25 11:33:14 +00:00
|
|
|
debug("(simulator) from file \"%s\"\n", hex.c_str());
|
2018-03-05 14:12:58 +00:00
|
|
|
}
|
2020-08-01 19:56:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-03-05 10:29:25 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<uchar> payload;
|
|
|
|
bool ok = hex2bin(hex.c_str(), &payload);
|
2020-08-01 19:56:46 +00:00
|
|
|
if (!ok)
|
|
|
|
{
|
2018-03-05 10:29:25 +00:00
|
|
|
error("Not a valid string of hex bytes! \"%s\"\n", l.c_str());
|
|
|
|
}
|
2020-01-27 08:29:40 +00:00
|
|
|
handleTelegram(payload);
|
2018-03-05 10:29:25 +00:00
|
|
|
}
|
|
|
|
manager_->stop();
|
|
|
|
}
|