kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add partial support for RC1180.
rodzic
e4f9eb23db
commit
d443fd4ea2
1
Makefile
1
Makefile
|
@ -160,6 +160,7 @@ METER_OBJS:=\
|
||||||
$(BUILD)/wmbus_rtl433.o \
|
$(BUILD)/wmbus_rtl433.o \
|
||||||
$(BUILD)/wmbus_simulator.o \
|
$(BUILD)/wmbus_simulator.o \
|
||||||
$(BUILD)/wmbus_rawtty.o \
|
$(BUILD)/wmbus_rawtty.o \
|
||||||
|
$(BUILD)/wmbus_rc1180.o \
|
||||||
$(BUILD)/wmbus_wmb13u.o \
|
$(BUILD)/wmbus_wmb13u.o \
|
||||||
$(BUILD)/wmbus_utils.o
|
$(BUILD)/wmbus_utils.o
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ Availability of **wmbusmeters** for other Linux distributions can be checked on
|
||||||
|
|
||||||
# Run as a daemon
|
# Run as a daemon
|
||||||
|
|
||||||
Remove the wmbus dongle (im871a,amb8465,rfmrx2,cul,d1tc) or the generic rtlsdr dongle (RTL2838) from your computer.
|
Remove the wmbus dongle (im871a,amb8465,cul,rc1180,rfmrx2,d1tc) or the generic rtlsdr dongle (RTL2838) from your computer.
|
||||||
|
|
||||||
`make; sudo make install` will install wmbusmeters as a daemon.
|
`make; sudo make install` will install wmbusmeters as a daemon.
|
||||||
|
|
||||||
Check the contents of your `/etc/wmbusmeters.conf` file, assuming it
|
Check the contents of your `/etc/wmbusmeters.conf` file, assuming it
|
||||||
has `device=auto` and you are using a im871a,amb8465 or cul device,
|
has `device=auto` and you are using a im871a,amb8465,rc1180 or cul device,
|
||||||
then you can now start the daemon with `sudo systemctl start wmbusmeters`.
|
then you can now start the daemon with `sudo systemctl start wmbusmeters`.
|
||||||
|
|
||||||
When the daemon is running it will scan for wmbus devices every few seconds
|
When the daemon is running it will scan for wmbus devices every few seconds
|
||||||
|
@ -166,7 +166,7 @@ As <options> you can use:
|
||||||
--meterfilestimestamp=(never|day|hour|minute|micros) the meter file is suffixed with a
|
--meterfilestimestamp=(never|day|hour|minute|micros) the meter file is suffixed with a
|
||||||
timestamp (localtime) with the given resolution.
|
timestamp (localtime) with the given resolution.
|
||||||
--oneshot wait for an update from each meter, then quit
|
--oneshot wait for an update from each meter, then quit
|
||||||
--resetafter=<time> reset the wmbus dongle regularly, default is 24h
|
--resetafter=<time> reset the wmbus dongle regularly, default is 23h
|
||||||
--selectfields=id,timestamp,total_m3 select fields to be printed
|
--selectfields=id,timestamp,total_m3 select fields to be printed
|
||||||
--separator=<c> change field separator to c
|
--separator=<c> change field separator to c
|
||||||
--shell=<cmdline> invokes cmdline with env variables containing the latest reading
|
--shell=<cmdline> invokes cmdline with env variables containing the latest reading
|
||||||
|
@ -223,10 +223,11 @@ As meter quadruples you specify:
|
||||||
Supported wmbus dongles:
|
Supported wmbus dongles:
|
||||||
IMST 871a (im871a)
|
IMST 871a (im871a)
|
||||||
Amber 8465 (amb8465)
|
Amber 8465 (amb8465)
|
||||||
BMeters RFM-RX2 (rfmrx2)
|
|
||||||
CUL family (cul)
|
CUL family (cul)
|
||||||
|
Radiocraft (RC1180) work in progress
|
||||||
rtl_wmbus (rtlwmbus)
|
rtl_wmbus (rtlwmbus)
|
||||||
rtl_433 (rtl433)
|
rtl_433 (rtl433)
|
||||||
|
BMeters RFM-RX2 (rfmrx2)
|
||||||
|
|
||||||
Supported water meters:
|
Supported water meters:
|
||||||
Apator at-wmbus-08 (apator08) (non-standard protocol)
|
Apator at-wmbus-08 (apator08) (non-standard protocol)
|
||||||
|
|
|
@ -54,7 +54,8 @@ LIST_OF_MAIN_MENU
|
||||||
#define LIST_OF_WMBUS_RECEIVERS \
|
#define LIST_OF_WMBUS_RECEIVERS \
|
||||||
X(AMB8465, "amb8465") \
|
X(AMB8465, "amb8465") \
|
||||||
X(CUL, "cul") \
|
X(CUL, "cul") \
|
||||||
X(IM871A, "im871a")
|
X(IM871A, "im871a") \
|
||||||
|
X(RC1180, "rc1180") \
|
||||||
|
|
||||||
enum class ReceiversType {
|
enum class ReceiversType {
|
||||||
#define X(name,description) name,
|
#define X(name,description) name,
|
||||||
|
@ -238,6 +239,9 @@ void detectWMBUSReceiver()
|
||||||
case ReceiversType::IM871A:
|
case ReceiversType::IM871A:
|
||||||
probeFor("im871a", detectIM871A);
|
probeFor("im871a", detectIM871A);
|
||||||
break;
|
break;
|
||||||
|
case ReceiversType::RC1180:
|
||||||
|
probeFor("rc1180", detectRC1180);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +283,9 @@ void resetWMBUSReceiver()
|
||||||
case ReceiversType::IM871A:
|
case ReceiversType::IM871A:
|
||||||
notImplementedYet("Resetting im871a");
|
notImplementedYet("Resetting im871a");
|
||||||
break;
|
break;
|
||||||
|
case ReceiversType::RC1180:
|
||||||
|
notImplementedYet("Resetting RC1180");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/main.cc
26
src/main.cc
|
@ -190,7 +190,7 @@ shared_ptr<WMBus> createWMBusDeviceFrom(Detected *detected, Configuration *confi
|
||||||
|
|
||||||
if (detected->override_tty)
|
if (detected->override_tty)
|
||||||
{
|
{
|
||||||
serial_override = manager->createSerialDeviceFile(detected->device.file);
|
serial_override = manager->createSerialDeviceFile(detected->device.file, string("override ")+detected->device.file.c_str());
|
||||||
verbose("(serial) override with devicefile: %s\n", detected->device.file.c_str());
|
verbose("(serial) override with devicefile: %s\n", detected->device.file.c_str());
|
||||||
link_modes_matter = false;
|
link_modes_matter = false;
|
||||||
}
|
}
|
||||||
|
@ -307,6 +307,12 @@ shared_ptr<WMBus> createWMBusDeviceFrom(Detected *detected, Configuration *confi
|
||||||
wmbus = openD1TC(detected->device.file, manager, serial_override);
|
wmbus = openD1TC(detected->device.file, manager, serial_override);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DEVICE_RC1180:
|
||||||
|
{
|
||||||
|
verbose("(rc1180) on %s\n", detected->device.file.c_str());
|
||||||
|
wmbus = openRC1180(detected->device.file, manager, serial_override);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DEVICE_WMB13U:
|
case DEVICE_WMB13U:
|
||||||
{
|
{
|
||||||
verbose("(wmb13u) on %s\n", detected->device.file.c_str());
|
verbose("(wmb13u) on %s\n", detected->device.file.c_str());
|
||||||
|
@ -556,7 +562,14 @@ void open_wmbus_device(Configuration *config, string how, string device, Detecte
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
verbose("(main) started %s on %s (%s)\n", toString(detected->type), device.c_str(), how.c_str());
|
if (detected->type != DEVICE_SIMULATOR)
|
||||||
|
{
|
||||||
|
notice("Started %s on %s (%s)\n", toString(detected->type), device.c_str(), how.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verbose("Started %s on %s (%s)\n", toString(detected->type), device.c_str(), how.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<WMBus> w = createWMBusDeviceFrom(detected, config, serial_manager_);
|
shared_ptr<WMBus> w = createWMBusDeviceFrom(detected, config, serial_manager_);
|
||||||
|
@ -564,11 +577,12 @@ void open_wmbus_device(Configuration *config, string how, string device, Detecte
|
||||||
WMBus *wmbus = wmbus_devices_.back().get();
|
WMBus *wmbus = wmbus_devices_.back().get();
|
||||||
wmbus->setLinkModes(config->listen_to_link_modes);
|
wmbus->setLinkModes(config->listen_to_link_modes);
|
||||||
|
|
||||||
// By default, reset your dongle once every day.
|
// By default, reset your dongle once every 23 hours,
|
||||||
int regular_reset = 24*3600;
|
// so that the reset is not at the exact same time every day.
|
||||||
|
int regular_reset = 23*3600;
|
||||||
if (config->resetafter != 0) regular_reset = config->resetafter;
|
if (config->resetafter != 0) regular_reset = config->resetafter;
|
||||||
wmbus->setResetInterval(regular_reset);
|
wmbus->setResetInterval(regular_reset);
|
||||||
verbose("(main) regular reset %d\n", regular_reset);
|
verbose("(main) regular reset of %s %s will happen every %d seconds\n", toString(detected->type), device.c_str(), regular_reset);
|
||||||
|
|
||||||
string using_link_modes = wmbus->getLinkModes().hr();
|
string using_link_modes = wmbus->getLinkModes().hr();
|
||||||
verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
|
verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
|
||||||
|
@ -604,7 +618,7 @@ void perform_auto_scan_of_serial_devices(Configuration *config)
|
||||||
{
|
{
|
||||||
debug("(main) device %s not currently used, detect contents...\n", device.c_str());
|
debug("(main) device %s not currently used, detect contents...\n", device.c_str());
|
||||||
// This serial device is not in use.
|
// This serial device is not in use.
|
||||||
Detected detected = detectImstAmberCul(device, "", "", serial_manager_, true, false, false);
|
Detected detected = detectImstAmberCulRC(device, "", "", serial_manager_, true, false, false);
|
||||||
if (detected.type != DEVICE_UNKNOWN)
|
if (detected.type != DEVICE_UNKNOWN)
|
||||||
{
|
{
|
||||||
open_wmbus_device(config, "auto", device, &detected);
|
open_wmbus_device(config, "auto", device, &detected);
|
||||||
|
|
121
src/serial.cc
121
src/serial.cc
|
@ -70,10 +70,10 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
|
||||||
SerialCommunicationManagerImp(time_t exit_after_seconds, bool start_event_loop);
|
SerialCommunicationManagerImp(time_t exit_after_seconds, bool start_event_loop);
|
||||||
~SerialCommunicationManagerImp();
|
~SerialCommunicationManagerImp();
|
||||||
|
|
||||||
shared_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate);
|
shared_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate, string purpose);
|
||||||
shared_ptr<SerialDevice> createSerialDeviceCommand(string device, string command, vector<string> args, vector<string> envs,
|
shared_ptr<SerialDevice> createSerialDeviceCommand(string device, string command, vector<string> args, vector<string> envs,
|
||||||
function<void()> on_exit);
|
function<void()> on_exit, string purpose);
|
||||||
shared_ptr<SerialDevice> createSerialDeviceFile(string file);
|
shared_ptr<SerialDevice> createSerialDeviceFile(string file, string purpose);
|
||||||
shared_ptr<SerialDevice> createSerialDeviceSimulator();
|
shared_ptr<SerialDevice> createSerialDeviceSimulator();
|
||||||
|
|
||||||
void listenTo(SerialDevice *sd, function<void()> cb);
|
void listenTo(SerialDevice *sd, function<void()> cb);
|
||||||
|
@ -86,6 +86,7 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
|
||||||
bool isRunning();
|
bool isRunning();
|
||||||
|
|
||||||
shared_ptr<SerialDevice> addSerialDeviceForManagement(SerialDevice *sd);
|
shared_ptr<SerialDevice> addSerialDeviceForManagement(SerialDevice *sd);
|
||||||
|
void tickleEventLoop();
|
||||||
void removeNonWorkingSerialDevices();
|
void removeNonWorkingSerialDevices();
|
||||||
void closeAllDoNotRemove();
|
void closeAllDoNotRemove();
|
||||||
|
|
||||||
|
@ -106,7 +107,6 @@ private:
|
||||||
|
|
||||||
bool running_ {};
|
bool running_ {};
|
||||||
bool expect_devices_to_work_ {}; // false during detection phase, true when running.
|
bool expect_devices_to_work_ {}; // false during detection phase, true when running.
|
||||||
int max_fd_ {};
|
|
||||||
time_t start_time_ {};
|
time_t start_time_ {};
|
||||||
time_t exit_after_seconds_ {};
|
time_t exit_after_seconds_ {};
|
||||||
|
|
||||||
|
@ -144,6 +144,7 @@ struct SerialDeviceImp : public SerialDevice
|
||||||
int receive(vector<uchar> *data);
|
int receive(vector<uchar> *data);
|
||||||
bool working() { return resetting_ || fd_ != -1; }
|
bool working() { return resetting_ || fd_ != -1; }
|
||||||
bool opened() { return resetting_ || fd_ != -2; }
|
bool opened() { return resetting_ || fd_ != -2; }
|
||||||
|
bool isClosed() { return fd_ == -1 && !resetting_; }
|
||||||
bool readonly() { return is_stdin_ || is_file_; }
|
bool readonly() { return is_stdin_ || is_file_; }
|
||||||
|
|
||||||
void expectAscii() { expecting_ascii_ = true; }
|
void expectAscii() { expecting_ascii_ = true; }
|
||||||
|
@ -163,9 +164,10 @@ struct SerialDeviceImp : public SerialDevice
|
||||||
return available > 0;
|
return available > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialDeviceImp(SerialCommunicationManagerImp *manager)
|
SerialDeviceImp(SerialCommunicationManagerImp *manager, string purpose)
|
||||||
{
|
{
|
||||||
manager_ = manager;
|
manager_ = manager;
|
||||||
|
purpose_ = purpose;
|
||||||
}
|
}
|
||||||
~SerialDeviceImp() = default;
|
~SerialDeviceImp() = default;
|
||||||
|
|
||||||
|
@ -186,6 +188,7 @@ protected:
|
||||||
bool no_callbacks_ = false;
|
bool no_callbacks_ = false;
|
||||||
SerialCommunicationManagerImp *manager_;
|
SerialCommunicationManagerImp *manager_;
|
||||||
bool resetting_ {}; // Set to true while resetting.
|
bool resetting_ {}; // Set to true while resetting.
|
||||||
|
string purpose_; // Can be set to identify a serial device purose.
|
||||||
|
|
||||||
friend struct SerialCommunicationManagerImp;
|
friend struct SerialCommunicationManagerImp;
|
||||||
};
|
};
|
||||||
|
@ -252,7 +255,7 @@ int SerialDeviceImp::receive(vector<uchar> *data)
|
||||||
|
|
||||||
struct SerialDeviceTTY : public SerialDeviceImp
|
struct SerialDeviceTTY : public SerialDeviceImp
|
||||||
{
|
{
|
||||||
SerialDeviceTTY(string device, int baud_rate, SerialCommunicationManagerImp * manager);
|
SerialDeviceTTY(string device, int baud_rate, SerialCommunicationManagerImp * manager, string purpose);
|
||||||
~SerialDeviceTTY();
|
~SerialDeviceTTY();
|
||||||
|
|
||||||
AccessCheck open(bool fail_if_not_ok);
|
AccessCheck open(bool fail_if_not_ok);
|
||||||
|
@ -268,8 +271,9 @@ struct SerialDeviceTTY : public SerialDeviceImp
|
||||||
};
|
};
|
||||||
|
|
||||||
SerialDeviceTTY::SerialDeviceTTY(string device, int baud_rate,
|
SerialDeviceTTY::SerialDeviceTTY(string device, int baud_rate,
|
||||||
SerialCommunicationManagerImp *manager)
|
SerialCommunicationManagerImp *manager,
|
||||||
: SerialDeviceImp(manager)
|
string purpose)
|
||||||
|
: SerialDeviceImp(manager, purpose)
|
||||||
{
|
{
|
||||||
device_ = device;
|
device_ = device;
|
||||||
baud_rate_ = baud_rate;
|
baud_rate_ = baud_rate;
|
||||||
|
@ -310,7 +314,7 @@ AccessCheck SerialDeviceTTY::open(bool fail_if_not_ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
verbose("(serialtty) opened %s\n", device_.c_str());
|
verbose("(serialtty) opened %s %d (%s)\n", device_.c_str(), fd_, purpose_.c_str());
|
||||||
return AccessCheck::AccessOK;
|
return AccessCheck::AccessOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +329,9 @@ void SerialDeviceTTY::close()
|
||||||
on_disappear_();
|
on_disappear_();
|
||||||
on_disappear_ = NULL;
|
on_disappear_ = NULL;
|
||||||
}
|
}
|
||||||
verbose("(serialtty) closed %s\n", device_.c_str());
|
manager_->tickleEventLoop();
|
||||||
|
|
||||||
|
verbose("(serialtty) closed %s (%s)\n", device_.c_str(), purpose_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialDeviceTTY::send(vector<uchar> &data)
|
bool SerialDeviceTTY::send(vector<uchar> &data)
|
||||||
|
@ -376,7 +382,8 @@ struct SerialDeviceCommand : public SerialDeviceImp
|
||||||
{
|
{
|
||||||
SerialDeviceCommand(string device, string command, vector<string> args, vector<string> envs,
|
SerialDeviceCommand(string device, string command, vector<string> args, vector<string> envs,
|
||||||
SerialCommunicationManagerImp *manager,
|
SerialCommunicationManagerImp *manager,
|
||||||
function<void()> on_exit);
|
function<void()> on_exit,
|
||||||
|
string purpose);
|
||||||
~SerialDeviceCommand();
|
~SerialDeviceCommand();
|
||||||
|
|
||||||
AccessCheck open(bool fail_if_not_ok);
|
AccessCheck open(bool fail_if_not_ok);
|
||||||
|
@ -405,8 +412,9 @@ SerialDeviceCommand::SerialDeviceCommand(string device,
|
||||||
vector<string> args,
|
vector<string> args,
|
||||||
vector<string> envs,
|
vector<string> envs,
|
||||||
SerialCommunicationManagerImp *manager,
|
SerialCommunicationManagerImp *manager,
|
||||||
function<void()> on_exit)
|
function<void()> on_exit,
|
||||||
: SerialDeviceImp(manager)
|
string purpose)
|
||||||
|
: SerialDeviceImp(manager, purpose)
|
||||||
{
|
{
|
||||||
assert(device != "");
|
assert(device != "");
|
||||||
device_ = device;
|
device_ = device;
|
||||||
|
@ -428,7 +436,7 @@ AccessCheck SerialDeviceCommand::open(bool fail_if_not_ok)
|
||||||
assert(fd_ >= 0);
|
assert(fd_ >= 0);
|
||||||
if (!ok) return AccessCheck::NotThere;
|
if (!ok) return AccessCheck::NotThere;
|
||||||
setIsStdin();
|
setIsStdin();
|
||||||
verbose("(serialcmd) opened %s pid %d fd %d\n", command_.c_str(), pid_, fd_);
|
verbose("(serialcmd) opened %s pid %d fd %d (%s)\n", command_.c_str(), pid_, fd_, purpose_.c_str());
|
||||||
return AccessCheck::AccessOK;
|
return AccessCheck::AccessOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +457,10 @@ void SerialDeviceCommand::close()
|
||||||
::flock(fd_, LOCK_UN);
|
::flock(fd_, LOCK_UN);
|
||||||
::close(fd_);
|
::close(fd_);
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
verbose("(serialcmd) closed %s pid=%d fd=%d\n", command_.c_str(), p, f);
|
|
||||||
|
manager_->tickleEventLoop();
|
||||||
|
|
||||||
|
verbose("(serialcmd) closed %s pid=%d fd=%d (%s)\n", command_.c_str(), p, f, purpose_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialDeviceCommand::working()
|
bool SerialDeviceCommand::working()
|
||||||
|
@ -502,7 +513,7 @@ bool SerialDeviceCommand::send(vector<uchar> &data)
|
||||||
|
|
||||||
struct SerialDeviceFile : public SerialDeviceImp
|
struct SerialDeviceFile : public SerialDeviceImp
|
||||||
{
|
{
|
||||||
SerialDeviceFile(string file, SerialCommunicationManagerImp *manager);
|
SerialDeviceFile(string file, SerialCommunicationManagerImp *manager, string purpose);
|
||||||
~SerialDeviceFile();
|
~SerialDeviceFile();
|
||||||
|
|
||||||
AccessCheck open(bool fail_if_not_ok);
|
AccessCheck open(bool fail_if_not_ok);
|
||||||
|
@ -518,8 +529,9 @@ struct SerialDeviceFile : public SerialDeviceImp
|
||||||
};
|
};
|
||||||
|
|
||||||
SerialDeviceFile::SerialDeviceFile(string file,
|
SerialDeviceFile::SerialDeviceFile(string file,
|
||||||
SerialCommunicationManagerImp *manager)
|
SerialCommunicationManagerImp *manager,
|
||||||
: SerialDeviceImp(manager)
|
string purpose)
|
||||||
|
: SerialDeviceImp(manager, purpose)
|
||||||
{
|
{
|
||||||
file_ = file;
|
file_ = file;
|
||||||
}
|
}
|
||||||
|
@ -538,7 +550,7 @@ AccessCheck SerialDeviceFile::open(bool fail_if_not_ok)
|
||||||
flags |= O_NONBLOCK;
|
flags |= O_NONBLOCK;
|
||||||
fcntl(0, F_SETFL, flags);
|
fcntl(0, F_SETFL, flags);
|
||||||
setIsStdin();
|
setIsStdin();
|
||||||
verbose("(serialfile) reading from stdin\n");
|
verbose("(serialfile) reading from stdin (%s)\n", purpose_.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -557,13 +569,9 @@ AccessCheck SerialDeviceFile::open(bool fail_if_not_ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsFile();
|
setIsFile();
|
||||||
verbose("(serialfile) reading from file %s\n", file_.c_str());
|
verbose("(serialfile) reading from file %s (%s)\n", file_.c_str(), purpose_.c_str());
|
||||||
}
|
|
||||||
if (signalsInstalled())
|
|
||||||
{
|
|
||||||
// Tickle the event loop to use the new file descriptor in the select.
|
|
||||||
if (getEventLoopThread()) pthread_kill(getEventLoopThread(), SIGUSR1);
|
|
||||||
}
|
}
|
||||||
|
manager_->tickleEventLoop();
|
||||||
|
|
||||||
return AccessCheck::AccessOK;
|
return AccessCheck::AccessOK;
|
||||||
}
|
}
|
||||||
|
@ -574,7 +582,10 @@ void SerialDeviceFile::close()
|
||||||
::flock(fd_, LOCK_UN);
|
::flock(fd_, LOCK_UN);
|
||||||
::close(fd_);
|
::close(fd_);
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
verbose("(serialfile) closed %s %d\n", file_.c_str(), fd_);
|
|
||||||
|
manager_->tickleEventLoop();
|
||||||
|
|
||||||
|
verbose("(serialfile) closed %s %d (%s)\n", file_.c_str(), fd_, purpose_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialDeviceFile::working()
|
bool SerialDeviceFile::working()
|
||||||
|
@ -601,10 +612,10 @@ bool SerialDeviceFile::send(vector<uchar> &data)
|
||||||
|
|
||||||
struct SerialDeviceSimulator : public SerialDeviceImp
|
struct SerialDeviceSimulator : public SerialDeviceImp
|
||||||
{
|
{
|
||||||
SerialDeviceSimulator(SerialCommunicationManagerImp *m) :
|
SerialDeviceSimulator(SerialCommunicationManagerImp *m, string purpose) :
|
||||||
SerialDeviceImp(m)
|
SerialDeviceImp(m, purpose)
|
||||||
{
|
{
|
||||||
verbose("(serialsimulator) opened\n");
|
verbose("(serialsimulator) opened (%s)\n", purpose_.c_str());
|
||||||
};
|
};
|
||||||
~SerialDeviceSimulator() { };
|
~SerialDeviceSimulator() { };
|
||||||
|
|
||||||
|
@ -633,7 +644,6 @@ SerialCommunicationManagerImp::SerialCommunicationManagerImp(time_t exit_after_s
|
||||||
bool start_event_loop)
|
bool start_event_loop)
|
||||||
{
|
{
|
||||||
running_ = true;
|
running_ = true;
|
||||||
max_fd_ = 0;
|
|
||||||
// Block the event loop until everything is configured.
|
// Block the event loop until everything is configured.
|
||||||
if (start_event_loop)
|
if (start_event_loop)
|
||||||
{
|
{
|
||||||
|
@ -647,28 +657,30 @@ SerialCommunicationManagerImp::SerialCommunicationManagerImp(time_t exit_after_s
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceTTY(string device,
|
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceTTY(string device,
|
||||||
int baud_rate)
|
int baud_rate,
|
||||||
|
string purpose)
|
||||||
{
|
{
|
||||||
return addSerialDeviceForManagement(new SerialDeviceTTY(device, baud_rate, this));
|
return addSerialDeviceForManagement(new SerialDeviceTTY(device, baud_rate, this, purpose));
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceCommand(string device,
|
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceCommand(string device,
|
||||||
string command,
|
string command,
|
||||||
vector<string> args,
|
vector<string> args,
|
||||||
vector<string> envs,
|
vector<string> envs,
|
||||||
function<void()> on_exit)
|
function<void()> on_exit,
|
||||||
|
string purpose)
|
||||||
{
|
{
|
||||||
return addSerialDeviceForManagement(new SerialDeviceCommand(device, command, args, envs, this, on_exit));
|
return addSerialDeviceForManagement(new SerialDeviceCommand(device, command, args, envs, this, on_exit, purpose));
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceFile(string file)
|
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceFile(string file, string purpose)
|
||||||
{
|
{
|
||||||
return addSerialDeviceForManagement(new SerialDeviceFile(file, this));
|
return addSerialDeviceForManagement(new SerialDeviceFile(file, this, purpose));
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceSimulator()
|
shared_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceSimulator()
|
||||||
{
|
{
|
||||||
return addSerialDeviceForManagement(new SerialDeviceSimulator(this));
|
return addSerialDeviceForManagement(new SerialDeviceSimulator(this, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function<void()> cb)
|
void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function<void()> cb)
|
||||||
|
@ -764,12 +776,24 @@ shared_ptr<SerialDevice> SerialCommunicationManagerImp::addSerialDeviceForManage
|
||||||
{
|
{
|
||||||
LOCK_SERIAL_DEVICES(opened);
|
LOCK_SERIAL_DEVICES(opened);
|
||||||
|
|
||||||
max_fd_ = max(sd->fd(), max_fd_);
|
|
||||||
shared_ptr<SerialDevice> ptr = shared_ptr<SerialDevice>(sd);
|
shared_ptr<SerialDevice> ptr = shared_ptr<SerialDevice>(sd);
|
||||||
serial_devices_.push_back(ptr);
|
serial_devices_.push_back(ptr);
|
||||||
|
|
||||||
|
tickleEventLoop();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SerialCommunicationManagerImp::tickleEventLoop()
|
||||||
|
{
|
||||||
|
LOCK_SERIAL_DEVICES(tickle);
|
||||||
|
|
||||||
|
if (signalsInstalled())
|
||||||
|
{
|
||||||
|
// Tickle the event loop to use the new file descriptor in the select.
|
||||||
|
if (getEventLoopThread()) pthread_kill(getEventLoopThread(), SIGUSR1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SerialCommunicationManagerImp::removeNonWorkingSerialDevices()
|
void SerialCommunicationManagerImp::removeNonWorkingSerialDevices()
|
||||||
{
|
{
|
||||||
LOCK_SERIAL_DEVICES(remove_non_working_serial_devices);
|
LOCK_SERIAL_DEVICES(remove_non_working_serial_devices);
|
||||||
|
@ -786,14 +810,6 @@ void SerialCommunicationManagerImp::removeNonWorkingSerialDevices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
max_fd_ = 0;
|
|
||||||
for (shared_ptr<SerialDevice> &sp : serial_devices_)
|
|
||||||
{
|
|
||||||
if (sp->fd() > max_fd_)
|
|
||||||
{
|
|
||||||
max_fd_ = sp->fd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (serial_devices_.size() == 0 && expect_devices_to_work_)
|
if (serial_devices_.size() == 0 && expect_devices_to_work_)
|
||||||
{
|
{
|
||||||
debug("(serial) no devices working emergency exit!\n");
|
debug("(serial) no devices working emergency exit!\n");
|
||||||
|
@ -938,7 +954,16 @@ void *SerialCommunicationManagerImp::eventLoop()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int activity = select(max_fd_+1 , &readfds, NULL , NULL, &timeout);
|
int max_fd = 0;
|
||||||
|
for (shared_ptr<SerialDevice> &sp : serial_devices_)
|
||||||
|
{
|
||||||
|
if (sp->fd() > max_fd)
|
||||||
|
{
|
||||||
|
max_fd = sp->fd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int activity = select(max_fd+1 , &readfds, NULL , NULL, &timeout);
|
||||||
|
|
||||||
if (activity == -1 && errno == EINTR)
|
if (activity == -1 && errno == EINTR)
|
||||||
{
|
{
|
||||||
|
@ -983,7 +1008,7 @@ void *SerialCommunicationManagerImp::eventLoop()
|
||||||
|
|
||||||
for (shared_ptr<SerialDevice> &sd : serial_devices_)
|
for (shared_ptr<SerialDevice> &sd : serial_devices_)
|
||||||
{
|
{
|
||||||
if (sd->opened() && !sd->working()) non_working.push_back(sd);
|
if (sd->opened() && !sd->working() && !sd->isClosed()) non_working.push_back(sd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@ struct SerialDevice
|
||||||
// If fail_if_not_ok then forcefully exit the program if cannot be opened.
|
// If fail_if_not_ok then forcefully exit the program if cannot be opened.
|
||||||
virtual AccessCheck open(bool fail_if_not_ok) = 0;
|
virtual AccessCheck open(bool fail_if_not_ok) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
// Explicitly closed fd == -1
|
||||||
|
virtual bool isClosed() = 0;
|
||||||
// Send will return true only if sending on a tty.
|
// Send will return true only if sending on a tty.
|
||||||
virtual bool send(std::vector<uchar> &data) = 0;
|
virtual bool send(std::vector<uchar> &data) = 0;
|
||||||
// Receive returns the number of bytes received.
|
// Receive returns the number of bytes received.
|
||||||
|
@ -67,15 +69,16 @@ struct SerialDevice
|
||||||
struct SerialCommunicationManager
|
struct SerialCommunicationManager
|
||||||
{
|
{
|
||||||
// Read from a /dev/ttyUSB0 or /dev/ttyACM0 device with baud settings.
|
// Read from a /dev/ttyUSB0 or /dev/ttyACM0 device with baud settings.
|
||||||
virtual shared_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate) = 0;
|
virtual shared_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate, string purpose) = 0;
|
||||||
// Read from a sub shell.
|
// Read from a sub shell.
|
||||||
virtual shared_ptr<SerialDevice> createSerialDeviceCommand(string device,
|
virtual shared_ptr<SerialDevice> createSerialDeviceCommand(string device,
|
||||||
string command,
|
string command,
|
||||||
vector<string> args,
|
vector<string> args,
|
||||||
vector<string> envs,
|
vector<string> envs,
|
||||||
function<void()> on_exit) = 0;
|
function<void()> on_exit,
|
||||||
|
string purpose) = 0;
|
||||||
// Read from stdin (file="stdin") or a specific file.
|
// Read from stdin (file="stdin") or a specific file.
|
||||||
virtual shared_ptr<SerialDevice> createSerialDeviceFile(string file) = 0;
|
virtual shared_ptr<SerialDevice> createSerialDeviceFile(string file, string purpose) = 0;
|
||||||
// A serial device simulator used for internal testing.
|
// A serial device simulator used for internal testing.
|
||||||
virtual shared_ptr<SerialDevice> createSerialDeviceSimulator() = 0;
|
virtual shared_ptr<SerialDevice> createSerialDeviceSimulator() = 0;
|
||||||
|
|
||||||
|
|
15
src/wmbus.cc
15
src/wmbus.cc
|
@ -471,7 +471,7 @@ string mediaTypeJSON(int a_field_device_type)
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
Detected detectImstAmberCul(string file,
|
Detected detectImstAmberCulRC(string file,
|
||||||
string suffix,
|
string suffix,
|
||||||
string linkmodes,
|
string linkmodes,
|
||||||
shared_ptr<SerialCommunicationManager> handler,
|
shared_ptr<SerialCommunicationManager> handler,
|
||||||
|
@ -489,18 +489,28 @@ Detected detectImstAmberCul(string file,
|
||||||
// Anyway by testing for the amb8465 first, we can immediately continue
|
// Anyway by testing for the amb8465 first, we can immediately continue
|
||||||
// with the test for the im871a, without the need for a 1s delay.
|
// with the test for the im871a, without the need for a 1s delay.
|
||||||
|
|
||||||
|
|
||||||
// Talk amb8465 with it...
|
// Talk amb8465 with it...
|
||||||
// assumes this device is configured for 9600 bps, which seems to be the default.
|
// assumes this device is configured for 9600 bps, which seems to be the default.
|
||||||
if (detectAMB8465(file, &detected, handler) == AccessCheck::AccessOK)
|
if (detectAMB8465(file, &detected, handler) == AccessCheck::AccessOK)
|
||||||
{
|
{
|
||||||
return detected;
|
return detected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Talk RC1180 with it...
|
||||||
|
// assumes this device is configured for 19200 bps, which seems to be the default.
|
||||||
|
if (detectRC1180(file, &detected, handler) == AccessCheck::AccessOK)
|
||||||
|
{
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
// Talk im871a with it...
|
// Talk im871a with it...
|
||||||
// assumes this device is configured for 57600 bps, which seems to be the default.
|
// assumes this device is configured for 57600 bps, which seems to be the default.
|
||||||
if (detectIM871A(file, &detected, handler) == AccessCheck::AccessOK)
|
if (detectIM871A(file, &detected, handler) == AccessCheck::AccessOK)
|
||||||
{
|
{
|
||||||
return detected;
|
return detected;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Talk CUL with it...
|
// Talk CUL with it...
|
||||||
// assumes this device is configured for 38400 bps, which seems to be the default.
|
// assumes this device is configured for 38400 bps, which seems to be the default.
|
||||||
if (detectCUL(file, &detected, handler) == AccessCheck::AccessOK)
|
if (detectCUL(file, &detected, handler) == AccessCheck::AccessOK)
|
||||||
|
@ -580,6 +590,7 @@ Detected detectWMBusDeviceSetting(string file,
|
||||||
|
|
||||||
if (suffix == "amb8465") return { { file, suffix }, DEVICE_AMB8465, 0, override_tty, is_tty, is_stdin, is_file };
|
if (suffix == "amb8465") return { { file, suffix }, DEVICE_AMB8465, 0, override_tty, is_tty, is_stdin, is_file };
|
||||||
if (suffix == "im871a") return { { file, suffix }, DEVICE_IM871A, 0, override_tty, is_tty, is_stdin, is_file };
|
if (suffix == "im871a") return { { file, suffix }, DEVICE_IM871A, 0, override_tty, is_tty, is_stdin, is_file };
|
||||||
|
if (suffix == "rc1180") return { { file, suffix }, DEVICE_RC1180, 0, override_tty, is_tty, is_stdin, is_file };
|
||||||
if (suffix == "rfmrx2") return { { file, suffix }, DEVICE_RFMRX2, 0, override_tty, is_tty, is_stdin, is_file };
|
if (suffix == "rfmrx2") return { { file, suffix }, DEVICE_RFMRX2, 0, override_tty, is_tty, is_stdin, is_file };
|
||||||
if (suffix == "rtlwmbus") return { { file, suffix }, DEVICE_RTLWMBUS, 0, override_tty, is_tty, is_stdin, is_file };
|
if (suffix == "rtlwmbus") return { { file, suffix }, DEVICE_RTLWMBUS, 0, override_tty, is_tty, is_stdin, is_file };
|
||||||
if (suffix == "rtl433") return { { file, suffix}, DEVICE_RTL433, 0, override_tty, is_tty, is_stdin, is_file };
|
if (suffix == "rtl433") return { { file, suffix}, DEVICE_RTL433, 0, override_tty, is_tty, is_stdin, is_file };
|
||||||
|
@ -602,7 +613,7 @@ Detected detectWMBusDeviceSetting(string file,
|
||||||
// Ok, we are left with a single /dev/ttyUSB0 lets talk to it
|
// Ok, we are left with a single /dev/ttyUSB0 lets talk to it
|
||||||
// to figure out what is connected to it. We currently only
|
// to figure out what is connected to it. We currently only
|
||||||
// know how to detect Imst, Amber or CUL dongles.
|
// know how to detect Imst, Amber or CUL dongles.
|
||||||
return detectImstAmberCul(file, suffix, linkmodes, handler, is_tty, is_stdin, is_file);
|
return detectImstAmberCulRC(file, suffix, linkmodes, handler, is_tty, is_stdin, is_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -75,6 +75,7 @@ struct Device
|
||||||
X(DEVICE_AMB8465)\
|
X(DEVICE_AMB8465)\
|
||||||
X(DEVICE_RFMRX2)\
|
X(DEVICE_RFMRX2)\
|
||||||
X(DEVICE_SIMULATOR)\
|
X(DEVICE_SIMULATOR)\
|
||||||
|
X(DEVICE_RC1180)\
|
||||||
X(DEVICE_RTLWMBUS)\
|
X(DEVICE_RTLWMBUS)\
|
||||||
X(DEVICE_RTL433)\
|
X(DEVICE_RTL433)\
|
||||||
X(DEVICE_RAWTTY)\
|
X(DEVICE_RAWTTY)\
|
||||||
|
@ -515,6 +516,8 @@ shared_ptr<WMBus> openAMB8465(string device, shared_ptr<SerialCommunicationManag
|
||||||
shared_ptr<SerialDevice> serial_override);
|
shared_ptr<SerialDevice> serial_override);
|
||||||
shared_ptr<WMBus> openRawTTY(string device, int baudrate, shared_ptr<SerialCommunicationManager> manager,
|
shared_ptr<WMBus> openRawTTY(string device, int baudrate, shared_ptr<SerialCommunicationManager> manager,
|
||||||
shared_ptr<SerialDevice> serial_override);
|
shared_ptr<SerialDevice> serial_override);
|
||||||
|
shared_ptr<WMBus> openRC1180(string device, shared_ptr<SerialCommunicationManager> manager,
|
||||||
|
shared_ptr<SerialDevice> serial_override);
|
||||||
shared_ptr<WMBus> openRTLWMBUS(string device, string command, shared_ptr<SerialCommunicationManager> manager, std::function<void()> on_exit,
|
shared_ptr<WMBus> openRTLWMBUS(string device, string command, shared_ptr<SerialCommunicationManager> manager, std::function<void()> on_exit,
|
||||||
shared_ptr<SerialDevice> serial_override);
|
shared_ptr<SerialDevice> serial_override);
|
||||||
shared_ptr<WMBus> openRTL433(string device, string command, shared_ptr<SerialCommunicationManager> manager, std::function<void()> on_exit,
|
shared_ptr<WMBus> openRTL433(string device, string command, shared_ptr<SerialCommunicationManager> manager, std::function<void()> on_exit,
|
||||||
|
@ -577,6 +580,7 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
|
||||||
AccessCheck detectIM871A(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck detectIM871A(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
AccessCheck detectAMB8465(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck detectAMB8465(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
AccessCheck detectRawTTY(string file, int baud, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck detectRawTTY(string file, int baud, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
|
AccessCheck detectRC1180(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
AccessCheck detectRTLSDR(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck detectRTLSDR(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
AccessCheck detectCUL(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck detectCUL(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
AccessCheck detectWMB13U(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck detectWMB13U(string file, Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
|
@ -585,7 +589,7 @@ AccessCheck detectWMB13U(string file, Detected *detected, shared_ptr<SerialCommu
|
||||||
// restore to factory settings.
|
// restore to factory settings.
|
||||||
AccessCheck factoryResetAMB8465(string device, shared_ptr<SerialCommunicationManager> handler, int *was_baud);
|
AccessCheck factoryResetAMB8465(string device, shared_ptr<SerialCommunicationManager> handler, int *was_baud);
|
||||||
|
|
||||||
Detected detectImstAmberCul(string file,
|
Detected detectImstAmberCulRC(string file,
|
||||||
string suffix,
|
string suffix,
|
||||||
string linkmodes,
|
string linkmodes,
|
||||||
shared_ptr<SerialCommunicationManager> handler,
|
shared_ptr<SerialCommunicationManager> handler,
|
||||||
|
|
|
@ -102,7 +102,7 @@ shared_ptr<WMBus> openAMB8465(string device, shared_ptr<SerialCommunicationManag
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600, "amb8465");
|
||||||
WMBusAmber *imp = new WMBusAmber(serial, manager);
|
WMBusAmber *imp = new WMBusAmber(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
@ -508,7 +508,7 @@ void WMBusAmber::handleMessage(int msgid, vector<uchar> &frame)
|
||||||
AccessCheck detectAMB8465(string device, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
AccessCheck detectAMB8465(string device, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||||
{
|
{
|
||||||
// Talk to the device and expect a very specific answer.
|
// Talk to the device and expect a very specific answer.
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600, "detect amb8465");
|
||||||
serial->doNotUseCallbacks();
|
serial->doNotUseCallbacks();
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
@ -562,7 +562,7 @@ AccessCheck detectAMB8465(string device, Detected *detected, shared_ptr<SerialCo
|
||||||
static AccessCheck tryFactoryResetAMB8465(string device, shared_ptr<SerialCommunicationManager> manager, int baud)
|
static AccessCheck tryFactoryResetAMB8465(string device, shared_ptr<SerialCommunicationManager> manager, int baud)
|
||||||
{
|
{
|
||||||
// Talk to the device and expect a very specific answer.
|
// Talk to the device and expect a very specific answer.
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud, "reset amb8465");
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) {
|
if (rc != AccessCheck::AccessOK) {
|
||||||
verbose("(amb8465) could not open device %s using baud %d\n", device.c_str(), baud);
|
verbose("(amb8465) could not open device %s using baud %d\n", device.c_str(), baud);
|
||||||
|
|
|
@ -87,7 +87,7 @@ shared_ptr<WMBus> openCUL(string device, shared_ptr<SerialCommunicationManager>
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400, "cul");
|
||||||
WMBusCUL *imp = new WMBusCUL(serial, manager);
|
WMBusCUL *imp = new WMBusCUL(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ FrameStatus WMBusCUL::checkCULFrame(vector<uchar> &data,
|
||||||
AccessCheck detectCUL(string device, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
AccessCheck detectCUL(string device, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||||
{
|
{
|
||||||
// Talk to the device and expect a very specific answer.
|
// Talk to the device and expect a very specific answer.
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400, "detect cul");
|
||||||
serial->doNotUseCallbacks();
|
serial->doNotUseCallbacks();
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
|
|
@ -63,7 +63,7 @@ shared_ptr<WMBus> openD1TC(string device, shared_ptr<SerialCommunicationManager>
|
||||||
WMBusD1TC *imp = new WMBusD1TC(serial_override, manager);
|
WMBusD1TC *imp = new WMBusD1TC(serial_override, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 115200);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 115200, "d1tc");
|
||||||
WMBusD1TC *imp = new WMBusD1TC(serial, manager);
|
WMBusD1TC *imp = new WMBusD1TC(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ AccessCheck detectD1TC(string device, int baud, shared_ptr<SerialCommunicationMa
|
||||||
{
|
{
|
||||||
// Since we do not know how to talk to the other end, it might not
|
// Since we do not know how to talk to the other end, it might not
|
||||||
// even respond. The only thing we can do is to try to open the serial device.
|
// even respond. The only thing we can do is to try to open the serial device.
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud, "detect d1tc");
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ shared_ptr<WMBus> openIM871A(string device, shared_ptr<SerialCommunicationManage
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 57600, "im871a");
|
||||||
WMBusIM871A *imp = new WMBusIM871A(serial, manager);
|
WMBusIM871A *imp = new WMBusIM871A(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,7 @@ void WMBusIM871A::handleHWTest(int msgid, vector<uchar> &payload)
|
||||||
AccessCheck detectIM871A(string file, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
AccessCheck detectIM871A(string file, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||||
{
|
{
|
||||||
// Talk to the device and expect a very specific answer.
|
// Talk to the device and expect a very specific answer.
|
||||||
auto serial = manager->createSerialDeviceTTY(file.c_str(), 57600);
|
auto serial = manager->createSerialDeviceTTY(file.c_str(), 57600, "detect im871a");
|
||||||
serial->doNotUseCallbacks();
|
serial->doNotUseCallbacks();
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
|
|
@ -58,7 +58,7 @@ shared_ptr<WMBus> openRawTTY(string device, int baudrate, shared_ptr<SerialCommu
|
||||||
WMBusRawTTY *imp = new WMBusRawTTY(serial_override, manager);
|
WMBusRawTTY *imp = new WMBusRawTTY(serial_override, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), baudrate);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), baudrate, "rawtty");
|
||||||
WMBusRawTTY *imp = new WMBusRawTTY(serial, manager);
|
WMBusRawTTY *imp = new WMBusRawTTY(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ AccessCheck detectRawTTY(string device, int baud, Detected *detected, shared_ptr
|
||||||
{
|
{
|
||||||
// Since we do not know how to talk to the other end, it might not
|
// Since we do not know how to talk to the other end, it might not
|
||||||
// even respond. The only thing we can do is to try to open the serial device.
|
// even respond. The only thing we can do is to try to open the serial device.
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud, "detect rawtty");
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include"wmbus.h"
|
||||||
|
#include"wmbus_utils.h"
|
||||||
|
#include"wmbus_cul.h"
|
||||||
|
#include"serial.h"
|
||||||
|
|
||||||
|
#include<assert.h>
|
||||||
|
#include<fcntl.h>
|
||||||
|
#include<grp.h>
|
||||||
|
#include<pthread.h>
|
||||||
|
#include<semaphore.h>
|
||||||
|
#include<string.h>
|
||||||
|
#include<errno.h>
|
||||||
|
#include<sys/stat.h>
|
||||||
|
#include<sys/types.h>
|
||||||
|
#include<unistd.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define SET_LINK_MODE 1
|
||||||
|
#define SET_X01_MODE 2
|
||||||
|
|
||||||
|
struct WMBusRC1180 : public virtual WMBusCommonImplementation
|
||||||
|
{
|
||||||
|
bool ping();
|
||||||
|
uint32_t getDeviceId();
|
||||||
|
LinkModeSet getLinkModes();
|
||||||
|
void deviceReset();
|
||||||
|
void deviceSetLinkModes(LinkModeSet lms);
|
||||||
|
LinkModeSet supportedLinkModes() {
|
||||||
|
return
|
||||||
|
C1_bit |
|
||||||
|
S1_bit |
|
||||||
|
T1_bit;
|
||||||
|
}
|
||||||
|
int numConcurrentLinkModes() { return 1; }
|
||||||
|
bool canSetLinkModes(LinkModeSet lms)
|
||||||
|
{
|
||||||
|
if (0 == countSetBits(lms.bits())) return false;
|
||||||
|
if (!supportedLinkModes().supports(lms)) return false;
|
||||||
|
// Ok, the supplied link modes are compatible,
|
||||||
|
// but im871a can only listen to one at a time.
|
||||||
|
return 1 == countSetBits(lms.bits());
|
||||||
|
}
|
||||||
|
void processSerialData();
|
||||||
|
void simulate();
|
||||||
|
|
||||||
|
WMBusRC1180(shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager);
|
||||||
|
~WMBusRC1180() { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
LinkModeSet link_modes_ {};
|
||||||
|
vector<uchar> read_buffer_;
|
||||||
|
vector<uchar> received_payload_;
|
||||||
|
string sent_command_;
|
||||||
|
string received_response_;
|
||||||
|
|
||||||
|
FrameStatus checkRC1180Frame(vector<uchar> &data,
|
||||||
|
size_t *hex_frame_length,
|
||||||
|
vector<uchar> &payload);
|
||||||
|
|
||||||
|
string setup_;
|
||||||
|
};
|
||||||
|
|
||||||
|
shared_ptr<WMBus> openRC1180(string device, shared_ptr<SerialCommunicationManager> manager, shared_ptr<SerialDevice> serial_override)
|
||||||
|
{
|
||||||
|
if (serial_override)
|
||||||
|
{
|
||||||
|
WMBusRC1180 *imp = new WMBusRC1180(serial_override, manager);
|
||||||
|
return shared_ptr<WMBus>(imp);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400, "rc1180");
|
||||||
|
WMBusRC1180 *imp = new WMBusRC1180(serial, manager);
|
||||||
|
return shared_ptr<WMBus>(imp);
|
||||||
|
}
|
||||||
|
|
||||||
|
WMBusRC1180::WMBusRC1180(shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager) :
|
||||||
|
WMBusCommonImplementation(DEVICE_RC1180, manager, serial)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WMBusRC1180::ping()
|
||||||
|
{
|
||||||
|
verbose("(rc1180) ping\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t WMBusRC1180::getDeviceId()
|
||||||
|
{
|
||||||
|
verbose("(rc1180) getDeviceId\n");
|
||||||
|
return 0x11111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkModeSet WMBusRC1180::getLinkModes()
|
||||||
|
{
|
||||||
|
return link_modes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMBusRC1180::deviceReset()
|
||||||
|
{
|
||||||
|
// No device specific settings needed right now.
|
||||||
|
// The common code in wmbus.cc reset()
|
||||||
|
// will open the serial device and potentially
|
||||||
|
// set the link modes properly.
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMBusRC1180::deviceSetLinkModes(LinkModeSet lms)
|
||||||
|
{
|
||||||
|
if (serial()->readonly()) return; // Feeding from stdin or file.
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!canSetLinkModes(lms))
|
||||||
|
{
|
||||||
|
string modes = lms.hr();
|
||||||
|
error("(rc1180) setting link mode(s) %s is not supported\n", modes.c_str());
|
||||||
|
}
|
||||||
|
// 'brc' command: b - wmbus, r - receive, c - c mode (with t)
|
||||||
|
vector<uchar> msg(5);
|
||||||
|
msg[0] = 'b';
|
||||||
|
msg[1] = 'r';
|
||||||
|
if (lms.has(LinkMode::C1)) {
|
||||||
|
msg[2] = 'c';
|
||||||
|
} else if (lms.has(LinkMode::S1)) {
|
||||||
|
msg[2] = 's';
|
||||||
|
} else if (lms.has(LinkMode::T1)) {
|
||||||
|
msg[2] = 't';
|
||||||
|
}
|
||||||
|
msg[3] = 0xa;
|
||||||
|
msg[4] = 0xd;
|
||||||
|
|
||||||
|
verbose("(rc1180) set link mode %c\n", msg[2]);
|
||||||
|
sent_command_ = string(&msg[0], &msg[3]);
|
||||||
|
received_response_ = "";
|
||||||
|
bool sent = serial()->send(msg);
|
||||||
|
|
||||||
|
if (sent) waitForResponse();
|
||||||
|
|
||||||
|
sent_command_ = "";
|
||||||
|
debug("(rc1180) received \"%s\"", received_response_.c_str());
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
if (lms.has(LinkMode::C1)) {
|
||||||
|
if (received_response_ != "CMODE") ok = false;
|
||||||
|
} else if (lms.has(LinkMode::S1)) {
|
||||||
|
if (received_response_ != "SMODE") ok = false;
|
||||||
|
} else if (lms.has(LinkMode::T1)) {
|
||||||
|
if (received_response_ != "TMODE") ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
string modes = lms.hr();
|
||||||
|
error("(rc1180) setting link mode(s) %s is not supported for this cul device!\n", modes.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// X01 - start the receiver
|
||||||
|
msg[0] = 'X';
|
||||||
|
msg[1] = '0';
|
||||||
|
msg[2] = '1';
|
||||||
|
msg[3] = 0xa;
|
||||||
|
msg[4] = 0xd;
|
||||||
|
|
||||||
|
sent = serial()->send(msg);
|
||||||
|
|
||||||
|
// Any response here, or does it silently move into listening mode?
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMBusRC1180::simulate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMBusRC1180::processSerialData()
|
||||||
|
{
|
||||||
|
vector<uchar> data;
|
||||||
|
|
||||||
|
// Receive and accumulated serial data until a full frame has been received.
|
||||||
|
serial()->receive(&data);
|
||||||
|
|
||||||
|
read_buffer_.insert(read_buffer_.end(), data.begin(), data.end());
|
||||||
|
|
||||||
|
size_t frame_length;
|
||||||
|
int payload_len, payload_offset;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
FrameStatus status = checkWMBusFrame(read_buffer_, &frame_length, &payload_len, &payload_offset);
|
||||||
|
|
||||||
|
if (status == PartialFrame)
|
||||||
|
{
|
||||||
|
// Partial frame, stop eating.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (status == ErrorInFrame)
|
||||||
|
{
|
||||||
|
verbose("(rawtty) protocol error in message received!\n");
|
||||||
|
string msg = bin2hex(read_buffer_);
|
||||||
|
debug("(rawtty) protocol error \"%s\"\n", msg.c_str());
|
||||||
|
read_buffer_.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (status == FullFrame)
|
||||||
|
{
|
||||||
|
vector<uchar> payload;
|
||||||
|
if (payload_len > 0)
|
||||||
|
{
|
||||||
|
uchar l = payload_len;
|
||||||
|
payload.insert(payload.end(), &l, &l+1); // Re-insert the len byte.
|
||||||
|
payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_offset+payload_len);
|
||||||
|
}
|
||||||
|
read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length);
|
||||||
|
handleTelegram(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessCheck detectRC1180(string device, Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||||
|
{
|
||||||
|
// Talk to the device and expect a very specific answer.
|
||||||
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 19200, "detect rc1180");
|
||||||
|
serial->doNotUseCallbacks();
|
||||||
|
AccessCheck rc = serial->open(false);
|
||||||
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
|
||||||
|
verbose("(rc1180) are you there?\n");
|
||||||
|
|
||||||
|
vector<uchar> data;
|
||||||
|
vector<uchar> msg(1);
|
||||||
|
|
||||||
|
// Send a single 0x00 byte. This will trigger the device to enter command mode
|
||||||
|
// the device then responds with '>'
|
||||||
|
msg[0] = 0;
|
||||||
|
|
||||||
|
serial->send(msg);
|
||||||
|
usleep(200*1000);
|
||||||
|
serial->receive(&data);
|
||||||
|
|
||||||
|
if (data[0] != '>') {
|
||||||
|
// no RC1180 device detected
|
||||||
|
serial->close();
|
||||||
|
return AccessCheck::NotThere;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.clear();
|
||||||
|
|
||||||
|
// send '0' to get get the version string: "V 1.67 nanoRC1180868" or similar
|
||||||
|
msg[0] = '0';
|
||||||
|
|
||||||
|
serial->send(msg);
|
||||||
|
// Wait for 200ms so that the USB stick have time to prepare a response.
|
||||||
|
usleep(1000*200);
|
||||||
|
|
||||||
|
serial->receive(&data);
|
||||||
|
string hex = bin2hex(data);
|
||||||
|
|
||||||
|
msg[0] = 'X';
|
||||||
|
serial->send(msg);
|
||||||
|
|
||||||
|
serial->close();
|
||||||
|
|
||||||
|
detected->set(WMBusDeviceType::DEVICE_RC1180, 19200, false);
|
||||||
|
|
||||||
|
return AccessCheck::AccessOK;
|
||||||
|
}
|
|
@ -84,7 +84,7 @@ shared_ptr<WMBus> openRTL433(string device, string command, shared_ptr<SerialCom
|
||||||
WMBusRTL433 *imp = new WMBusRTL433(serial_override, manager);
|
WMBusRTL433 *imp = new WMBusRTL433(serial_override, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
auto serial = manager->createSerialDeviceCommand(device, "/bin/sh", args, envs, on_exit);
|
auto serial = manager->createSerialDeviceCommand(device, "/bin/sh", args, envs, on_exit, "rtl433");
|
||||||
WMBusRTL433 *imp = new WMBusRTL433(serial, manager);
|
WMBusRTL433 *imp = new WMBusRTL433(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ shared_ptr<WMBus> openRTLWMBUS(string device, string command, shared_ptr<SerialC
|
||||||
WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serial_override, manager);
|
WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serial_override, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
auto serial = manager->createSerialDeviceCommand(device, "/bin/sh", args, envs, on_exit);
|
auto serial = manager->createSerialDeviceCommand(device, "/bin/sh", args, envs, on_exit, "rtlwmbus");
|
||||||
WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serial, manager);
|
WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ shared_ptr<WMBus> openWMB13U(string device, shared_ptr<SerialCommunicationManage
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 19200);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 19200, "wmb13u");
|
||||||
WMBusWMB13U *imp = new WMBusWMB13U(serial, manager);
|
WMBusWMB13U *imp = new WMBusWMB13U(serial, manager);
|
||||||
return shared_ptr<WMBus>(imp);
|
return shared_ptr<WMBus>(imp);
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ bool WMBusWMB13U::getConfiguration()
|
||||||
AccessCheck detectWMB13U(string device, shared_ptr<SerialCommunicationManager> manager)
|
AccessCheck detectWMB13U(string device, shared_ptr<SerialCommunicationManager> manager)
|
||||||
{
|
{
|
||||||
// Talk to the device and expect a very specific answer.
|
// Talk to the device and expect a very specific answer.
|
||||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 19200);
|
auto serial = manager->createSerialDeviceTTY(device.c_str(), 19200, "detect wmb13u");
|
||||||
AccessCheck rc = serial->open(false);
|
AccessCheck rc = serial->open(false);
|
||||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat <<EOF > $TEST/test_expected.txt
|
cat <<EOF > $TEST/test_expected.txt
|
||||||
|
Started DEVICE_RTLWMBUS on stdin:rtlwmbus (config)
|
||||||
(wmbus) decrypted content failed check, did you use the correct decryption key? Ignoring telegram.
|
(wmbus) decrypted content failed check, did you use the correct decryption key? Ignoring telegram.
|
||||||
(wmbus) decrypted payload crc failed check, did you use the correct decryption key? Ignoring telegram.
|
(wmbus) decrypted payload crc failed check, did you use the correct decryption key? Ignoring telegram.
|
||||||
(wmbus) decrypted content failed check, did you use the correct decryption key? Ignoring telegram.
|
(wmbus) decrypted content failed check, did you use the correct decryption key? Ignoring telegram.
|
||||||
|
|
Ładowanie…
Reference in New Issue