/* Copyright (C) 2018 Fredrik Öhrström 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 . */ #include"wmbus.h" #include"serial.h" #include #include #include #include #include #include using namespace std; struct WMBusSimulator : public WMBus { bool ping(); uint32_t getDeviceId(); LinkMode getLinkMode(); void setLinkMode(LinkMode lm); void onTelegram(function cb); void processSerialData(); SerialDevice *serial() { return NULL; } void simulate(); WMBusSimulator(string file, SerialCommunicationManager *manager); private: vector received_payload_; vector> telegram_listeners_; string file_; SerialCommunicationManager *manager_ {}; LinkMode link_mode_ {}; vector lines_; }; int loadFile(string file, vector *lines); unique_ptr openSimulator(string device, SerialCommunicationManager *manager) { WMBusSimulator *imp = new WMBusSimulator(device, manager); return unique_ptr(imp); } WMBusSimulator::WMBusSimulator(string file, SerialCommunicationManager *manager) : file_(file), manager_(manager) { vector 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; } LinkMode WMBusSimulator::getLinkMode() { verbose("(simulator) get link mode\n"); verbose("(simulator) config: link mode %02x\n", link_mode_); return link_mode_; } void WMBusSimulator::setLinkMode(LinkMode lm) { if (lm != LinkModeC1 && lm != LinkModeT1) { error("LinkMode %d is not implemented\n", (int)lm); } link_mode_ = lm; verbose("(simulator) set link mode %02x\n", lm); verbose("(simulator) set link mode completed\n"); } void WMBusSimulator::onTelegram(function cb) { telegram_listeners_.push_back(cb); } int loadFile(string file, vector *lines) { char block[32768+1]; vector 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() { time_t start_time = time(NULL); for (auto l : lines_) { string hex = ""; int found_time = 0; time_t rel_time = 0; if (l.substr(0,9) == "telegram=") { for (size_t i=9; i start_time + rel_time) break; usleep(1000*1000); } } } else { debug("(simulator) from file \"%s\"\n", hex.c_str()); } } else { continue; } vector payload; bool ok = hex2bin(hex.c_str(), &payload); if (!ok) { error("Not a valid string of hex bytes! \"%s\"\n", l.c_str()); } Telegram t; t.parse(payload); for (auto f : telegram_listeners_) { if (f) f(&t); } if (isVerboseEnabled() && !t.handled) { verbose("(wmbus simulator) telegram ignored by all configured meters!\n"); } } manager_->stop(); } bool detectSimulator(string device, SerialCommunicationManager *manager) { return true; }