Exit and print info when background rtl_wmbus process fails to start.

pull/22/head
weetmuts 2019-04-03 17:31:51 +02:00
rodzic 7aae7aa6c2
commit 43f0d9b051
15 zmienionych plików z 221 dodań i 86 usunięć

18
CHANGES
Wyświetl plik

@ -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,

Wyświetl plik

@ -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++

Wyświetl plik

@ -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} <device> ( [meter_name] [meter_type] [meter_id] [meter_key] )*
As <options> you can use:
@ -91,19 +95,18 @@ As <options> you can use:
--useconfig=<dir> load config files from dir/etc
--verbose for more information
As a <device> you can use:
As a <device> 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 <device> 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:<commandline>" to have wmbusmeters spawn
that commandline instead, the output is expected to be like rtl_wmbus.
As a <device> 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:<commandline>"
As meter quadruples you specify:
<meter_name> 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.

Wyświetl plik

@ -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 <<EOF > $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

Wyświetl plik

@ -68,20 +68,18 @@ As <options> you can use:
--useconfig=<dir> load config files from dir/etc
--verbose for more information
As a <device> you can use:
As a <device> 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 <device> 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:<commandline>" to have wmbusmeters spawn
that commandline instead, its output is expected to be like rtl_wmbus.
As a <device> 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:<commandline>\"
As meter quadruples you specify:
<meter_name> 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:

Wyświetl plik

@ -44,7 +44,8 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager {
~SerialCommunicationManagerImp() { }
unique_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate);
unique_ptr<SerialDevice> createSerialDeviceCommand(string command, vector<string> args, vector<string> envs);
unique_ptr<SerialDevice> createSerialDeviceCommand(string command, vector<string> args, vector<string> envs,
function<void()> on_exit);
void listenTo(SerialDevice *sd, function<void()> 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<uchar> *data)
return num_read;
}
struct SerialDeviceCommand : public SerialDeviceImp {
SerialDeviceCommand(string command, vector<string> args, vector<string> envs, SerialCommunicationManagerImp *manager);
struct SerialDeviceCommand : public SerialDeviceImp
{
SerialDeviceCommand(string command, vector<string> args, vector<string> envs,
SerialCommunicationManagerImp *manager,
function<void()> on_exit);
~SerialDeviceCommand();
bool open(bool fail_if_not_ok);
@ -206,6 +211,8 @@ struct SerialDeviceCommand : public SerialDeviceImp {
bool send(vector<uchar> &data);
int receive(vector<uchar> *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<void()> on_exit_;
};
SerialDeviceCommand::SerialDeviceCommand(string command,
vector<string> args,
vector<string> envs,
SerialCommunicationManagerImp *manager) {
SerialCommunicationManagerImp *manager,
function<void()> 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<uchar> &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<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceTTY(st
unique_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceCommand(string command,
vector<string> args,
vector<string> envs)
vector<string> envs,
function<void()> on_exit)
{
return unique_ptr<SerialDevice>(new SerialDeviceCommand(command, args, envs, this));
return unique_ptr<SerialDevice>(new SerialDeviceCommand(command, args, envs, this, on_exit));
}
void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function<void()> 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;

Wyświetl plik

@ -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<uchar> &data) = 0;
virtual int receive(std::vector<uchar> *data) = 0;
virtual int fd() = 0;
virtual bool working() = 0;
virtual SerialCommunicationManager *manager() = 0;
virtual ~SerialDevice() = default;
};
struct SerialCommunicationManager {
struct SerialCommunicationManager
{
virtual unique_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate) = 0;
virtual unique_ptr<SerialDevice> createSerialDeviceCommand(string command, vector<string> args, vector<string> envs) = 0;
virtual unique_ptr<SerialDevice> createSerialDeviceCommand(string command, vector<string> args,
vector<string> envs,
function<void()> on_exit) = 0;
virtual void listenTo(SerialDevice *sd, function<void()> cb) = 0;
virtual void stop() = 0;
virtual void waitForStop() = 0;

Wyświetl plik

@ -37,11 +37,11 @@ void invokeShell(string program, vector<string> args, vector<string> 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<string> args, vector<string> 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<string> args, vector<string> 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<string> args, vector<string> 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<string> args, vector<string> 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<string> args, vector<string> 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<string> args, vector<string> 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);
}
}

Wyświetl plik

@ -22,4 +22,5 @@ using namespace std;
void invokeShell(string program, vector<string> args, vector<string> envs);
bool invokeBackgroundShell(string program, vector<string> args, vector<string> envs, int *out, int *pid);
bool stillRunning(int pid);
void stopBackgroundShell(int pid);

Wyświetl plik

@ -39,19 +39,22 @@ void exitHandler(int signum)
if (exit_handler) exit_handler();
}
function<void()> 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<void()> 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<void()> cb)
@ -70,14 +73,15 @@ void onExit(function<void()> 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);

Wyświetl plik

@ -25,7 +25,7 @@
#include<vector>
void onExit(std::function<void()> cb);
void onChild(std::function<void()> cb);
void wakeMeUpOnSigChld(pthread_t t);
typedef unsigned char uchar;

Wyświetl plik

@ -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<MBusDeviceType,string> 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, "" };
}

Wyświetl plik

@ -145,7 +145,8 @@ pair<MBusDeviceType,string> detectMBusDevice(string device, SerialCommunicationM
unique_ptr<WMBus> openIM871A(string device, SerialCommunicationManager *manager);
unique_ptr<WMBus> openAMB8465(string device, SerialCommunicationManager *manager);
struct WMBusSimulator;
unique_ptr<WMBus> openRTLWMBUS(string device, SerialCommunicationManager *manager);
unique_ptr<WMBus> openRTLWMBUS(string device, SerialCommunicationManager *manager,
std::function<void()> on_exit);
unique_ptr<WMBus> openSimulator(string file, SerialCommunicationManager *manager);
string manufacturer(int m_field);

Wyświetl plik

@ -20,10 +20,12 @@
#include<assert.h>
#include<fcntl.h>
#include<grp.h>
#include<pthread.h>
#include<semaphore.h>
#include<string.h>
#include<sys/errno.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
@ -60,13 +62,14 @@ private:
SerialCommunicationManager *manager_ {};
};
unique_ptr<WMBus> openRTLWMBUS(string command, SerialCommunicationManager *manager)
unique_ptr<WMBus> openRTLWMBUS(string command, SerialCommunicationManager *manager,
function<void()> on_exit)
{
vector<string> args;
vector<string> 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<WMBus>(imp);
}
@ -189,3 +192,20 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector<uchar> &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;
}