/* Copyright (C) 2019-2023 Fredrik Öhrström (gpl-3.0-or-later) 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"serial.h" #include"util.h" #include"wmbus.h" #include"wmbus_common_implementation.h" #include"wmbus_utils.h" #include #include #include #include #include #include #include using namespace std; struct WMBusSimulator : public BusDeviceCommonImplementation { bool ping(); string getDeviceId(); string getDeviceUniqueId(); LinkModeSet getLinkModes(); void deviceReset(); bool deviceSetLinkModes(LinkModeSet lms); LinkModeSet supportedLinkModes() { return Any_bit; } int numConcurrentLinkModes() { return 0; } bool canSetLinkModes(LinkModeSet lms) { return true; } void processSerialData(); void simulate(); string device() { return file_; } WMBusSimulator(string alias, string file, string hex, shared_ptr manager); private: vector received_payload_; vector> telegram_listeners_; string file_; LinkModeSet link_modes_; vector lines_; }; shared_ptr openSimulator(Detected detected, shared_ptr manager, shared_ptr serial_override) { string bus_alias = detected.specified_device.bus_alias; string device = detected.found_file; string hex = detected.found_hex; WMBusSimulator *imp = new WMBusSimulator(bus_alias, device, hex, manager); return shared_ptr(imp); } WMBusSimulator::WMBusSimulator(string bus_alias, string file, string hex, shared_ptr manager) : BusDeviceCommonImplementation(bus_alias, DEVICE_SIMULATION, manager, NULL, false), file_(file) { assert(file != "" || hex != ""); if (hex != "") { lines_.push_back("telegram="+hex); } if (file != "") { loadFile(file, &lines_); } } bool WMBusSimulator::ping() { return true; } string WMBusSimulator::getDeviceId() { return "?"; } string WMBusSimulator::getDeviceUniqueId() { return "?"; } LinkModeSet WMBusSimulator::getLinkModes() { string hr = link_modes_.hr(); return link_modes_; } void WMBusSimulator::deviceReset() { } bool WMBusSimulator::deviceSetLinkModes(LinkModeSet lms) { link_modes_ = lms; return true; } void WMBusSimulator::processSerialData() { assert(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); if (!manager_->isRunning()) { debug("(simulation) exiting early\n"); break; } } } } else { debug("(simulation) 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()); } size_t frame_length; int payload_len, payload_offset; bool is_mbus = FullFrame == checkMBusFrame(payload, &frame_length, &payload_len, &payload_offset, true); bool is_wmbus = FullFrame == checkWMBusFrame(payload, &frame_length, &payload_len, &payload_offset, true); debug("(simulator) is_mbus=%s is_wmbus=%s\n", is_mbus?"true":"false", is_wmbus?"true":"false"); if (is_mbus && is_wmbus) { warning("(mbus) telegram matches both mbus and wmbus! Assuming it is wmbus only.\n"); is_mbus = false; } if (is_mbus) { debug("(simulator) is mbus telegram.\n"); AboutTelegram about("", 0, FrameType::MBUS); // Remove two bytes, which are the checksum and end of telegram marker (0x16). while (((size_t)payload_len) < payload.size()) payload.pop_back(); handleTelegram(about, payload); } if (is_wmbus) { debug("(simulator) is wmbus telegram.\n"); AboutTelegram about("", 0, FrameType::WMBUS); // Since this is a simulation, try to remove any frame format A or B // data link layer crcs. These might remain if we have received the telegram // to be simulated, from a CUL device or some other devices that does not remove the crcs. // Normally the dongle (im871a/amb8465/rc1180/rtlwmbus/rtl443) removes the dll-crcs. // Removing dll-crcs are also done explicitly in the wmbus_cul.cc driver. removeAnyDLLCRCs(payload); handleTelegram(about, payload); } } manager_->stop(); }