From 43f0d9b051ea4d3d545d9f8f67d4d5f7b4cf08d2 Mon Sep 17 00:00:00 2001 From: weetmuts Date: Wed, 3 Apr 2019 17:31:51 +0200 Subject: [PATCH] Exit and print info when background rtl_wmbus process fails to start. --- CHANGES | 18 +++++- Makefile | 2 +- README.md | 42 ++++++------ install.sh | 8 ++- src/main.cc | 34 +++++----- src/serial.cc | 52 ++++++++++++--- src/serial.h | 11 +++- src/shell.cc | 82 ++++++++++++++++++------ src/shell.h | 1 + src/util.cc | 20 +++--- src/util.h | 2 +- src/wmbus.cc | 8 +++ src/wmbus.h | 3 +- src/wmbus_rtlwmbus.cc | 24 ++++++- XMLExtract.java => utils/XMLExtract.java | 0 15 files changed, 221 insertions(+), 86 deletions(-) rename XMLExtract.java => utils/XMLExtract.java (100%) diff --git a/CHANGES b/CHANGES index a99478e..d92a73e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,21 @@ -Verison 0.9.3: 2019-03-20 +Version 0.9.4: 2019-04-03 -Added initial support for the Tauron Amiplus electricity meter type (amiplus). +The device auto can now detect an rtlsdr dongle and start +rtl_sdr|rtl_wmbus properly. It can only detecht the rtlsdr +dongle if the new udev rule has been installed, which will +create the symlink /dev/rtlsdr when the dongle is inserted. + +Added the meter vendor Echelon to the generic amiplus meter type. +(The Echelon meter seems to be a standard electricity meter with a +wmbus addon sourced from Develco.) + +Version 0.9.3: 2019-03-20 + +Added initial support for the generic Tauron Amiplus electricity meter type (amiplus). +This is actually a generic meter type, that will match the meter vendors +that provide meters under the Amiplus brand to Taurn. The first vendor to +be supported is from Apator. Added support for the at-wmbus-16-2 snap on meter (apator162). Unfortunately it uses a vendor specific protocol, diff --git a/Makefile b/Makefile index c6a427c..cd08349 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ # make DEBUG=true # make DEBUG=true HOST=arm -VERSION=0.9.2 +VERSION=0.9.4 ifeq "$(HOST)" "arm" CXX=arm-linux-gnueabihf-g++ diff --git a/README.md b/README.md index 074053a..5c55ee5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The program runs on GNU/Linux, MacOSX and Raspberry Pi. # Run as a daemon -Remove the wmbus dongle (im871a or amb8465) from your computer. +Remove the wmbus dongle (im871a,amb8465) or the generic rtlsdr dongle (RTL2838) from your computer. `make; sudo make install` will install wmbusmeters as a daemon that starts automatically when an appropriate wmbus usb dongle is inserted in the computer. @@ -29,9 +29,11 @@ Check the config file /etc/wmbusmeters.conf: loglevel=normal device=auto logtelegrams=false +format=json meterfiles=/var/log/wmbusmeters/meter_readings +meterfilesaction=overwrite logfile=/var/log/wmbusmeters/wmbusmeters.log -shell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters -m "$METER_JSON" +shell=/usr/bin/mosquitto_pub -h localhost -t wmbusmeters/$METER_ID -m "$METER_JSON" ``` Then add a meter file in /etc/wmbusmeters.d/MyTapWater @@ -44,6 +46,8 @@ key=00112233445566778899AABBCCDDEEFF Now plugin your wmbus dongle. Wmbusmeters should start automatically, check with `tail -f /var/log/syslog` and `tail -f /var/log/wmbusmeters/wmbusmeters.log` +(If you are using an rtlsdr dongle, then make sure the binaries /usr/bin/rtl_sdr and +/usr/bin/rtl_wmbus exists and are executable.) The latest reading of the meter can also be found here: /var/log/wmbusmeters/meter_readings/MyTapWater @@ -70,7 +74,7 @@ The files/dir should then be located here: # Running without config files, good for experimentation and test. ``` -wmbusmeters version: 0.9.2 +wmbusmeters version: 0.9.4 Usage: wmbusmeters {options} ( [meter_name] [meter_type] [meter_id] [meter_key] )* As you can use: @@ -91,19 +95,18 @@ As you can use: --useconfig= load config files from dir/etc --verbose for more information -As a you can use: +As a you can use: auto +which will look for the links /dev/im87a,/dev/amb8475 and /dev/rtlsdr (the +links are automatically generated by udev if you have run the install scripts.) +and start wmbusmeters with the proper tty device or rtlwmbus background process. -"/dev/ttyUSB" to which a im871a/amb8465 dongle is attached, -or you can specify auto and wmbusmeters will look for a suitable dongle -on the device links /dev/im871a and /dev/amb8465. +As a you can also use: the exact /dev/ttyUSB0 to your dongle if you do not want +to install the udev rule. -"rtlwmbus:868.95M" to have wmbusmeters spawn: -"rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus" -(you might have to tweak 868.95M to nearby frequencies depending -on the rtl-sdr dongle you are using) - -"rtlwmbus:" to have wmbusmeters spawn -that commandline instead, the output is expected to be like rtl_wmbus. +As a you can also use: rtlwmbus +to spawn the background process: "rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus" +You can also use: rtlwmbus:868.9M to use this fq instead. Fq tuning can sometimes +be necessary. Or you can specify the entire background process command line: "rtlwmbus:" As meter quadruples you specify: a mnemonic for this particular meter @@ -123,7 +126,7 @@ Supported heat cost allocator: Qundis Q caloric (qcaloric) Supported electricity meters: -Tauron Amiplus (amiplus) (almost complete) +Tauron Amiplus (amiplus) (includes vendor apator and echelon) Work in progress: Heat meter Kamstrup Multical 302 (multical302) @@ -132,7 +135,7 @@ Electricity meter Kamstrup Omnipower (omnipower) The wmbus dongles imst871a and amb8465 can only listen on one type of wmbus telegrams at a time. So you can listen to multiple meters as long as they all require the same radio mode C1 or T1. -If you use rtl-sdr/rtl_wmbus, then you can listen to both C1 and T1 at the same time. +If you use rtlwmbus, then you can listen to both C1 and T1 at the same time. # Usage examples @@ -160,9 +163,10 @@ Example format json output: `{"media":"heat","meter":"multical302","name":"MyHeater","id":"22222222","total_kwh":0.000,"total_volume_m3":0.000,"current_kw":"0.000","timestamp":"2018-02-08T09:07:22Z"}` -Example format fields output: +Example format fields output and use rtlsdr dongle with rtlwmbus tuned to 868.9MHz instead of the +default 868.95MHz. -`wmbusmeters --format=fields auto GreenhouseWater multical21 33333333 ""` +`wmbusmeters --format=fields rtlwmbus:868.9M GreenhouseWater multical21 33333333 ""` `GreenhouseTapWater;33333333;9999.099;77.712;0.000;11;31;;2018-03-05 12:10.24` @@ -197,7 +201,7 @@ If the meter does not use encryption of its meter data, then enter an empty key `wmbusmeters --format=json --meterfiles auto MyTapWater multical21 12345678 ""` If you have a Multical21 meter and you have received a KEM file and its password, -from your water municipality, then you can use the XMLExtract.java utility to get +from your water municipality, then you can use the utils/XMLExtract.java utility to get the meter key from the KEM file. You need to unzip the the KEM file first though, if it is zipped. diff --git a/install.sh b/install.sh index 935c169..327b6e2 100755 --- a/install.sh +++ b/install.sh @@ -181,10 +181,13 @@ StopWhenUnneeded=true [Service] Type=forking PrivateTmp=yes -#Restart=always -RestartSec=1 User=wmbusmeters Group=wmbusmeters +Restart=always +RestartSec=1 +StartLimitIntervalSec=10 +StartLimitInterval=10 +StartLimitBurst=3 # Run ExecStartPre with root-permissions @@ -219,6 +222,7 @@ then cat < $ROOT/etc/udev/rules.d/99-wmbus-usb-serial.rules SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",SYMLINK+="im871a",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters.service" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",SYMLINK+="amb8465",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters.service" +SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838",SYMLINK+="rtlsdr",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters.service" EOF echo udev: installed $ROOT/etc/udev/rules.d/99-wmbus-usb-serial.rules else diff --git a/src/main.cc b/src/main.cc index 11ffed6..7989978 100644 --- a/src/main.cc +++ b/src/main.cc @@ -68,20 +68,18 @@ As you can use: --useconfig= load config files from dir/etc --verbose for more information -As a you can use: +As a you can use: auto +which will look for the links /dev/im87a,/dev/amb8475 and /dev/rtlsdr (the +links are automatically generated by udev if you have run the install scripts.) +and start wmbusmeters with the proper tty device or rtlwmbus background process. -"/dev/ttyUSB" to which a im871a/amb8465 dongle is attached, -or you can specify auto and wmbusmeters will look for a suitable dongle -on the device links /dev/im871a and /dev/amb8465. +As a you can also use: the exact /dev/ttyUSB0 to your dongle if you do not want +to install the udev rule. -"rtlwmbus:868.95M" to have wmbusmeters spawn: -"rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus" -(you might have to tweak 868.95M to nearby frequencies depending -on the rtl-sdr dongle you are using, also when run as a daemon, -it uses /usr/bin/rtl_sdr and /usr/bin/rtl_wmbus instead.) - -"rtlwmbus:" to have wmbusmeters spawn -that commandline instead, its output is expected to be like rtl_wmbus. +As a you can also use: rtlwmbus +to spawn the background process: \"rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus\" +You can also use: rtlwmbus:868.9M to use this fq instead. Fq tuning can sometimes +be necessary. Or you can specify the entire background process command line: \"rtlwmbus:\" As meter quadruples you specify: a mnemonic for this particular meter @@ -195,14 +193,12 @@ void startUsingCommandline(Configuration *config) command = prefix+"rtl_sdr -f "+freq+" -s 16000000 - 2>/dev/null | "+prefix+"rtl_wmbus"; } verbose("(rtlwmbus) using command: %s\n", command.c_str()); - /* This will have to wait until I can differentiate between - shell childs that did mqtt/curl exits and the serial shell exit. - onChild([command,&manager](){ - warning("(rtlwmbus) child process exited! Command was: \"%s\"\n", command.c_str()); - manager.get()->stop(); - });*/ - wmbus = openRTLWMBUS(command, manager.get()); + wmbus = openRTLWMBUS(command, manager.get(), + [command](){ + warning("(rtlwmbus) child process exited! " + "Command was: \"%s\"\n", command.c_str()); + }); break; } case DEVICE_UNKNOWN: diff --git a/src/serial.cc b/src/serial.cc index 31154b8..52f0024 100644 --- a/src/serial.cc +++ b/src/serial.cc @@ -44,7 +44,8 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager { ~SerialCommunicationManagerImp() { } unique_ptr createSerialDeviceTTY(string dev, int baud_rate); - unique_ptr createSerialDeviceCommand(string command, vector args, vector envs); + unique_ptr createSerialDeviceCommand(string command, vector args, vector envs, + function on_exit); void listenTo(SerialDevice *sd, function cb); void stop(); @@ -69,6 +70,7 @@ private: struct SerialDeviceImp : public SerialDevice { int fd() { return fd_; } + bool working() { return true; } protected: @@ -197,8 +199,11 @@ int SerialDeviceTTY::receive(vector *data) return num_read; } -struct SerialDeviceCommand : public SerialDeviceImp { - SerialDeviceCommand(string command, vector args, vector envs, SerialCommunicationManagerImp *manager); +struct SerialDeviceCommand : public SerialDeviceImp +{ + SerialDeviceCommand(string command, vector args, vector envs, + SerialCommunicationManagerImp *manager, + function on_exit); ~SerialDeviceCommand(); bool open(bool fail_if_not_ok); @@ -206,6 +211,8 @@ struct SerialDeviceCommand : public SerialDeviceImp { bool send(vector &data); int receive(vector *data); int fd() { return fd_; } + bool working(); + SerialCommunicationManager *manager() { return manager_; } private: @@ -219,16 +226,20 @@ struct SerialDeviceCommand : public SerialDeviceImp { pthread_mutex_t write_lock_ = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t read_lock_ = PTHREAD_MUTEX_INITIALIZER; SerialCommunicationManagerImp *manager_; + function on_exit_; }; SerialDeviceCommand::SerialDeviceCommand(string command, vector args, vector envs, - SerialCommunicationManagerImp *manager) { + SerialCommunicationManagerImp *manager, + function on_exit) +{ command_ = command; args_ = args; envs_ = envs; manager_ = manager; + on_exit_ = on_exit; } SerialDeviceCommand::~SerialDeviceCommand() @@ -247,6 +258,12 @@ bool SerialDeviceCommand::open(bool fail_if_not_ok) void SerialDeviceCommand::close() { + if (pid_ == 0 && fd_ == -1) return; + if (pid_ && stillRunning(pid_)) + { + stopBackgroundShell(pid_); + pid_ = 0; + } ::flock(fd_, LOCK_UN); ::close(fd_); fd_ = -1; @@ -254,6 +271,16 @@ void SerialDeviceCommand::close() verbose("(serialcmd) closed %s\n", command_.c_str()); } +bool SerialDeviceCommand::working() +{ + if (!pid_) return false; + bool r = stillRunning(pid_); + if (r) return true; + close(); + on_exit_(); + return false; +} + bool SerialDeviceCommand::send(vector &data) { if (data.size() == 0) return true; @@ -328,7 +355,7 @@ SerialCommunicationManagerImp::SerialCommunicationManagerImp(time_t exit_after_s running_ = true; max_fd_ = 0; pthread_create(&thread_, NULL, startLoop, this); - //running_ = (rc == 0); + wakeMeUpOnSigChld(thread_); start_time_ = time(NULL); exit_after_seconds_ = exit_after_seconds; } @@ -344,9 +371,10 @@ unique_ptr SerialCommunicationManagerImp::createSerialDeviceTTY(st unique_ptr SerialCommunicationManagerImp::createSerialDeviceCommand(string command, vector args, - vector envs) + vector envs, + function on_exit) { - return unique_ptr(new SerialDeviceCommand(command, args, envs, this)); + return unique_ptr(new SerialDeviceCommand(command, args, envs, this, on_exit)); } void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function cb) { @@ -364,7 +392,7 @@ void SerialCommunicationManagerImp::stop() void SerialCommunicationManagerImp::waitForStop() { - while (running_) { usleep(1000*1000);} + while (running_) { usleep(1000*1000); } pthread_kill(thread_, SIGUSR1); pthread_join(thread_, NULL); for (SerialDevice *d : devices_) { @@ -405,7 +433,7 @@ void *SerialCommunicationManagerImp::eventLoop() { FD_SET(d->fd(), &readfds); } - struct timeval timeout { 3600, 0 }; + struct timeval timeout { 10, 0 }; if (exit_after_seconds_ > 0) { time_t curr = time(NULL); @@ -431,6 +459,12 @@ void *SerialCommunicationManagerImp::eventLoop() { } } } + for (SerialDevice *d : devices_) { + if (!d->working()) { + stop(); + break; + } + } } verbose("(serialtty) event loop stopped!\n"); return NULL; diff --git a/src/serial.h b/src/serial.h index 99582d3..7ae4899 100644 --- a/src/serial.h +++ b/src/serial.h @@ -29,19 +29,24 @@ using namespace std; struct SerialCommunicationManager; -struct SerialDevice { +struct SerialDevice +{ virtual bool open(bool fail_if_not_ok) = 0; virtual void close() = 0; virtual bool send(std::vector &data) = 0; virtual int receive(std::vector *data) = 0; virtual int fd() = 0; + virtual bool working() = 0; virtual SerialCommunicationManager *manager() = 0; virtual ~SerialDevice() = default; }; -struct SerialCommunicationManager { +struct SerialCommunicationManager +{ virtual unique_ptr createSerialDeviceTTY(string dev, int baud_rate) = 0; - virtual unique_ptr createSerialDeviceCommand(string command, vector args, vector envs) = 0; + virtual unique_ptr createSerialDeviceCommand(string command, vector args, + vector envs, + function on_exit) = 0; virtual void listenTo(SerialDevice *sd, function cb) = 0; virtual void stop() = 0; virtual void waitForStop() = 0; diff --git a/src/shell.cc b/src/shell.cc index 00e31d1..ff2781b 100644 --- a/src/shell.cc +++ b/src/shell.cc @@ -37,11 +37,11 @@ void invokeShell(string program, vector args, vector envs) strcpy(p, program.c_str()); argv[0] = p; int i = 1; - debug("exec \"%s\"\n", program.c_str()); + debug("(shell) exec \"%s\"\n", program.c_str()); for (auto &a : args) { argv[i] = a.c_str(); i++; - debug("arg \"%s\"\n", a.c_str()); + debug("(shell) arg \"%s\"\n", a.c_str()); } argv[i] = NULL; @@ -51,7 +51,7 @@ void invokeShell(string program, vector args, vector envs) for (auto &e : envs) { env[i] = e.c_str(); i++; - debug("env \"%s\"\n", e.c_str()); + debug("(shell) env \"%s\"\n", e.c_str()); } env[i] = NULL; @@ -68,20 +68,20 @@ void invokeShell(string program, vector args, vector envs) #endif perror("Execvp failed:"); - error("Invoking shell %s failed!\n", program.c_str()); + error("(shell) invoking %s failed!\n", program.c_str()); } else { if (pid == -1) { - error("Could not fork!\n"); + error("(shell) could not fork!\n"); } - debug("waiting for child %d.\n", pid); + debug("(shell) waiting for child %d to complete.\n", pid); // Wait for the child to finish! waitpid(pid, &status, 0); if (WIFEXITED(status)) { // Child exited properly. int rc = WEXITSTATUS(status); - debug("%s: return code %d\n", program.c_str(), rc); + debug("(shell) %s: return code %d\n", program.c_str(), rc); if (rc != 0) { - warning("%s exited with non-zero return code: %d\n", program.c_str(), rc); + warning("(shell) %s exited with non-zero return code: %d\n", program.c_str(), rc); } } } @@ -96,11 +96,11 @@ bool invokeBackgroundShell(string program, vector args, vector e strcpy(p, program.c_str()); argv[0] = p; int i = 1; - debug("exec background \"%s\"\n", program.c_str()); + debug("(bgshell) exec background \"%s\"\n", program.c_str()); for (auto &a : args) { argv[i] = a.c_str(); i++; - debug("arg \"%s\"\n", a.c_str()); + debug("(bgshell) arg \"%s\"\n", a.c_str()); } argv[i] = NULL; @@ -110,12 +110,12 @@ bool invokeBackgroundShell(string program, vector args, vector e for (auto &e : envs) { env[i] = e.c_str(); i++; - debug("env \"%s\"\n", e.c_str()); + debug("(bgshell) env \"%s\"\n", e.c_str()); } env[i] = NULL; if (pipe(link) == -1) { - error("Could not create pipe!\n"); + error("(bgshell) could not create pipe!\n"); } *pid = fork(); @@ -138,7 +138,7 @@ bool invokeBackgroundShell(string program, vector args, vector e #endif perror("Execvp failed:"); - warning("Invoking shell %s failed!\n", program.c_str()); + error("(bgshell) invoking %s failed!\n", program.c_str()); return false; } @@ -147,21 +147,65 @@ bool invokeBackgroundShell(string program, vector args, vector e return true; } +bool stillRunning(int pid) +{ + if (pid == 0) return false; + int status; + int p = waitpid(pid, &status, WNOHANG); + if (p == 0) { + // The pid has not exited yet. + return true; + } + if (p < 0) { + // No pid to wait for. + return false; + } + if (WIFEXITED(status)) { + // Child exited properly. + int rc = WEXITSTATUS(status); + debug("(bgshell) %d exited with return code %d\n", pid, rc); + } + else if (WIFSIGNALED(status)) { + // Child forcefully terminated + debug("(bgshell) %d terminated due to signal %d\n", pid, WTERMSIG(status)); + } else + { + // Exited for other reasons, whatever those may be. + debug("(bgshell) %d exited\n", pid); + } + return false; +} + void stopBackgroundShell(int pid) { assert(pid > 0); - kill(pid, SIGINT); - int status; - debug("waiting for child %d.\n", pid); + int rc = kill(pid, SIGINT); + if (rc < 0) { + debug("(bgshell) could not sigint pid %d, exited already?\n", pid); + return; + } // Wait for the child to finish! - waitpid(pid, &status, 0); + debug("(bgshell) sent sigint, now waiting for child %d to exit.\n", pid); + int status; + int p = waitpid(pid, &status, 0); + if (p < 0) { + debug("(bgshell) cannot stop pid %d, exited already?\n", pid); + return; + } if (WIFEXITED(status)) { // Child exited properly. int rc = WEXITSTATUS(status); - debug("bgshell: return code %d\n", rc); + debug("(bgshell) return code %d\n", rc); if (rc != 0) { - warning("bgshell: exited with non-zero return code: %d\n", rc); + warning("(bgshell) exited with non-zero return code: %d\n", rc); } } + if (WIFSIGNALED(status)) { + // Child forcefully terminated + debug("(bgshell) %d terminated due to signal %d\n", pid, WTERMSIG(status)); + } else + { + debug("(bgshell) %d exited\n", pid); + } } diff --git a/src/shell.h b/src/shell.h index 4dcf9a4..62278a3 100644 --- a/src/shell.h +++ b/src/shell.h @@ -22,4 +22,5 @@ using namespace std; void invokeShell(string program, vector args, vector envs); bool invokeBackgroundShell(string program, vector args, vector envs, int *out, int *pid); +bool stillRunning(int pid); void stopBackgroundShell(int pid); diff --git a/src/util.cc b/src/util.cc index f9e57c8..9227e3e 100644 --- a/src/util.cc +++ b/src/util.cc @@ -39,19 +39,22 @@ void exitHandler(int signum) if (exit_handler) exit_handler(); } -function child_handler; +pthread_t wake_me_up_on_sig_chld_ {}; -void childProcessDied(int signum) +void wakeMeUpOnSigChld(pthread_t t) { - if (child_handler) child_handler(); + wake_me_up_on_sig_chld_ = t; } -void doNothing(int signum) { +void doNothing(int signum) +{ } -void onChild(function cb) +void signalMyself(int signum) { - child_handler = cb; + if (wake_me_up_on_sig_chld_) { + pthread_kill(wake_me_up_on_sig_chld_, SIGUSR1); + } } void onExit(function cb) @@ -70,14 +73,15 @@ void onExit(function cb) sigaction (SIGTERM, NULL, &old_action); if (old_action.sa_handler != SIG_IGN) sigaction (SIGTERM, &new_action, NULL); - new_action.sa_handler = childProcessDied; + new_action.sa_handler = signalMyself; + sigemptyset (&new_action.sa_mask); + new_action.sa_flags = 0; sigaction (SIGCHLD, NULL, &old_action); if (old_action.sa_handler != SIG_IGN) sigaction (SIGCHLD, &new_action, NULL); new_action.sa_handler = doNothing; sigemptyset (&new_action.sa_mask); new_action.sa_flags = 0; - sigaction (SIGUSR1, NULL, &old_action); if (old_action.sa_handler != SIG_IGN) sigaction(SIGUSR1, &new_action, NULL); diff --git a/src/util.h b/src/util.h index 3844e64..71f7057 100644 --- a/src/util.h +++ b/src/util.h @@ -25,7 +25,7 @@ #include void onExit(std::function cb); -void onChild(std::function cb); +void wakeMeUpOnSigChld(pthread_t t); typedef unsigned char uchar; diff --git a/src/wmbus.cc b/src/wmbus.cc index 01ad3c3..5c0f09f 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -271,6 +271,7 @@ string mediaTypeJSON(int a_field_device_type) bool detectIM871A(string device, SerialCommunicationManager *handler); bool detectAMB8465(string device, SerialCommunicationManager *handler); +bool detectRTLSDR(string device, SerialCommunicationManager *handler); bool existsButWrongGroup(string device) { @@ -317,6 +318,13 @@ pair detectMBusDevice(string device, SerialCommunicationM error("You are not in the same group as the device /dev/amb8465\n"); } + if (detectRTLSDR("/dev/rtlsdr", handler)) + { + return { DEVICE_RTLWMBUS, "rtlwmbus" }; + } else if (existsButWrongGroup("/dev/rtlsdr")) { + error("You are not in the same group as the device /dev/rtlsdr\n"); + } + return { DEVICE_UNKNOWN, "" }; } diff --git a/src/wmbus.h b/src/wmbus.h index fed4190..4036548 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -145,7 +145,8 @@ pair detectMBusDevice(string device, SerialCommunicationM unique_ptr openIM871A(string device, SerialCommunicationManager *manager); unique_ptr openAMB8465(string device, SerialCommunicationManager *manager); struct WMBusSimulator; -unique_ptr openRTLWMBUS(string device, SerialCommunicationManager *manager); +unique_ptr openRTLWMBUS(string device, SerialCommunicationManager *manager, + std::function on_exit); unique_ptr openSimulator(string file, SerialCommunicationManager *manager); string manufacturer(int m_field); diff --git a/src/wmbus_rtlwmbus.cc b/src/wmbus_rtlwmbus.cc index 17d9f7e..e405a89 100644 --- a/src/wmbus_rtlwmbus.cc +++ b/src/wmbus_rtlwmbus.cc @@ -20,10 +20,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -60,13 +62,14 @@ private: SerialCommunicationManager *manager_ {}; }; -unique_ptr openRTLWMBUS(string command, SerialCommunicationManager *manager) +unique_ptr openRTLWMBUS(string command, SerialCommunicationManager *manager, + function on_exit) { vector args; vector envs; args.push_back("-c"); args.push_back(command); - auto serial = manager->createSerialDeviceCommand("/bin/sh", args, envs); + auto serial = manager->createSerialDeviceCommand("/bin/sh", args, envs, on_exit); WMBusRTLWMBUS *imp = new WMBusRTLWMBUS(std::move(serial), manager); return unique_ptr(imp); } @@ -189,3 +192,20 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector &data, return FullFrame; } + +bool detectRTLSDR(string device, SerialCommunicationManager *manager) +{ + // No more advanced test than that the /dev/rtlsdr link exists. + struct stat sb; + int rc = stat(device.c_str(), &sb); + if (rc) return false; + + struct group *g = getgrgid(sb.st_gid); + if (g && getegid() != g->gr_gid) + { + // Our group is not the same as the device. + return false; + } + + return true; +} diff --git a/XMLExtract.java b/utils/XMLExtract.java similarity index 100% rename from XMLExtract.java rename to utils/XMLExtract.java