kopia lustrzana https://github.com/weetmuts/wmbusmeters
Improve verbose messages when user is not member of dialout.
rodzic
ba5b37ab7a
commit
678a3a8a0a
4
CHANGES
4
CHANGES
|
@ -1,4 +1,8 @@
|
|||
|
||||
Improved verbose logging to show if you are not in the dialout
|
||||
group when trying to find dongles. Install now adds the current
|
||||
user to the dialout group as well.
|
||||
|
||||
Added support for the Hydrocal-M3 heating/cooling meter.
|
||||
Added support for the Apator uniSMART gas meter.
|
||||
|
||||
|
|
11
README.md
11
README.md
|
@ -656,14 +656,17 @@ and adds the user `wmbusmeters` with no login account.
|
|||
|
||||
# Common problems
|
||||
|
||||
If wmbusmeters detects no device, but you know you have plugged in your wmbus dongle, then
|
||||
run with `--verbose` to get more information on why the devices are not detected.
|
||||
Typically this is because you are not in the dialout (for usb-serial dongles) or plugdev (for rtlsdr) group.
|
||||
|
||||
Run `sudo make install` to add the current user to the dialout group and the wmbusmeters group.
|
||||
|
||||
If the daemon has started then the wmbus device will be taken and you cannot start wmbusmeters manually.
|
||||
|
||||
To run manually, first make sure the daemon is stopped `sudo stop wmbusmeters@-dev-im871a_0.server`
|
||||
To run manually, first make sure the daemon is stopped `sudo systemctl stop wmbusmeters`
|
||||
if this hangs, then do `sudo killall -9 wmbusmetersd` and/or `sudo killall -9 wmbusmeters`.
|
||||
|
||||
If you are using rtl_sdr/rtl_wmbus and you want to stop the daemon, do
|
||||
`sudo stop wmbusmeters@-dev-rtlsdr_3.server` followed by `sudo killall -9 rtl_sdr`.
|
||||
|
||||
## How to receive telegrams over longer distances
|
||||
|
||||
I only have personal experience of the im871a,amb8465 and an rtlsdr
|
||||
|
|
|
@ -58,3 +58,5 @@ ROOT=$ROOT /bin/sh ./scripts/prepare_logfiles.sh
|
|||
ROOT=$ROOT /bin/sh ./scripts/install_default_configuration.sh
|
||||
|
||||
ROOT=$ROOT /bin/sh ./scripts/install_systemd_service.sh
|
||||
|
||||
ROOT=$ROOT /bin/sh ./scripts/add_myself_to_dialout.sh
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ ! -z "$SUDO_USER" ]
|
||||
then
|
||||
if [ "$(getent group dialout | grep $SUDO_USER)" = "" ]
|
||||
then
|
||||
usermod -a -G dialout $SUDO_USER
|
||||
echo "group: added $SUDO_USER to group dialout"
|
||||
else
|
||||
echo "group: $SUDO_USER already member of dialout"
|
||||
fi
|
||||
|
||||
if [ "$(groups $SUDO_USER | grep -o wmbusmeters)" = "" ]
|
||||
then
|
||||
usermod -a -G wmbusmeters $SUDO_USER
|
||||
echo "group: added $SUDO_USER to group wmbusmeters"
|
||||
else
|
||||
echo "group: user $SUDO_USER already member of wmbusmeters"
|
||||
fi
|
||||
fi
|
31
src/admin.cc
31
src/admin.cc
|
@ -24,6 +24,7 @@
|
|||
#include"serial.h"
|
||||
#include"shell.h"
|
||||
#include"ui.h"
|
||||
#include"util.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
bool running_as_root_ = false;
|
||||
|
@ -99,6 +100,9 @@ int main(int argc, char **argv)
|
|||
enableSyslog();
|
||||
}
|
||||
|
||||
// Handle exit on signals...
|
||||
onExit(exitUI);
|
||||
|
||||
initUI();
|
||||
clear();
|
||||
|
||||
|
@ -160,6 +164,8 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
}
|
||||
} while (running);
|
||||
|
||||
exitUI();
|
||||
}
|
||||
|
||||
void alwaysOnScreen()
|
||||
|
@ -289,7 +295,7 @@ void resetWMBUSReceiver()
|
|||
}
|
||||
}
|
||||
|
||||
void probeFor(string type, AccessCheck (*check)(Detected*,shared_ptr<SerialCommunicationManager>))
|
||||
void probeFor(string type, AccessCheck (*probe)(Detected*,shared_ptr<SerialCommunicationManager>))
|
||||
{
|
||||
Detected detected {};
|
||||
vector<string> devices = handler->listSerialTTYs();
|
||||
|
@ -297,24 +303,33 @@ void probeFor(string type, AccessCheck (*check)(Detected*,shared_ptr<SerialCommu
|
|||
for (string& device : devices)
|
||||
{
|
||||
string tty = "?";
|
||||
AccessCheck ac = checkAccessAndDetect(
|
||||
handler,
|
||||
[&](string d, shared_ptr<SerialCommunicationManager> m){ detected.specified_device.file=d; return check(&detected, m);},
|
||||
type,
|
||||
device);
|
||||
AccessCheck ac = handler->checkAccess(device,
|
||||
handler,
|
||||
type,
|
||||
[&](string d, shared_ptr<SerialCommunicationManager> m){
|
||||
detected.found_file=d;
|
||||
detected.specified_device.file=d; return probe(&detected, m);});
|
||||
|
||||
if (ac == AccessCheck::AccessOK)
|
||||
{
|
||||
tty = device+" DETECTED "+type;
|
||||
}
|
||||
else if (ac == AccessCheck::NotThere)
|
||||
else if (ac == AccessCheck::NoSuchDevice)
|
||||
{
|
||||
tty = device+" nothing there";
|
||||
tty = device+" no such device";
|
||||
}
|
||||
else if (ac == AccessCheck::NoProperResponse)
|
||||
{
|
||||
tty = device+" no response";
|
||||
}
|
||||
else if (ac == AccessCheck::NotSameGroup)
|
||||
{
|
||||
tty = device+" not same group";
|
||||
}
|
||||
else if (ac == AccessCheck::NoPermission)
|
||||
{
|
||||
tty = device+" same group but wrong permissions";
|
||||
}
|
||||
entries.push_back(tty);
|
||||
}
|
||||
if (entries.size() == 0)
|
||||
|
|
|
@ -197,8 +197,8 @@ AccessCheck detectMBUS(Detected *detected, shared_ptr<SerialCommunicationManager
|
|||
// 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.
|
||||
auto serial = manager->createSerialDeviceTTY(tty.c_str(), bps, PARITY::EVEN, "detect mbus");
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
bool ok = serial->open(false);
|
||||
if (!ok) return AccessCheck::NoSuchDevice;
|
||||
|
||||
serial->close();
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ AccessCheck detectRTLSDR(string serialnr, Detected *detected)
|
|||
if (detected->specified_device.type != WMBusDeviceType::DEVICE_RTLWMBUS &&
|
||||
detected->specified_device.type != WMBusDeviceType::DEVICE_RTL433)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
uint32_t n = rtlsdr_get_device_count();
|
||||
|
@ -129,7 +129,7 @@ AccessCheck detectRTLSDR(string serialnr, Detected *detected)
|
|||
}
|
||||
|
||||
// Something is wrong.
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
126
src/serial.cc
126
src/serial.cc
|
@ -44,6 +44,8 @@
|
|||
#include <linux/serial.h>
|
||||
#endif
|
||||
|
||||
// return a positive integer (file descriptor) on success.
|
||||
// return -1 for failure to open. return -2 for already locked.
|
||||
static int openSerialTTY(const char *tty, int baud_rate, PARITY parity);
|
||||
static string showTTYSettings(int fd);
|
||||
|
||||
|
@ -94,6 +96,11 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
|
|||
int startRegularCallback(string name, int seconds, function<void()> callback);
|
||||
void stopRegularCallback(int id);
|
||||
|
||||
AccessCheck checkAccess(string device,
|
||||
shared_ptr<SerialCommunicationManager> manager,
|
||||
string extra_info,
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> extra_probe);
|
||||
|
||||
vector<string> listSerialTTYs();
|
||||
shared_ptr<SerialDevice> lookup(std::string device);
|
||||
bool removeNonWorking(std::string device);
|
||||
|
@ -285,7 +292,7 @@ struct SerialDeviceTTY : public SerialDeviceImp
|
|||
SerialDeviceTTY(string device, int baud_rate, PARITY parity, SerialCommunicationManagerImp * manager, string purpose);
|
||||
~SerialDeviceTTY();
|
||||
|
||||
AccessCheck open(bool fail_if_not_ok);
|
||||
bool open(bool fail_if_not_ok);
|
||||
void close();
|
||||
bool send(vector<uchar> &data);
|
||||
bool working();
|
||||
|
@ -313,39 +320,26 @@ SerialDeviceTTY::~SerialDeviceTTY()
|
|||
close();
|
||||
}
|
||||
|
||||
AccessCheck SerialDeviceTTY::open(bool fail_if_not_ok)
|
||||
bool SerialDeviceTTY::open(bool fail_if_not_ok)
|
||||
{
|
||||
assert(device_ != "");
|
||||
bool ok = checkCharacterDeviceExists(device_.c_str(), fail_if_not_ok);
|
||||
if (!ok) return AccessCheck::NotThere;
|
||||
if (!ok) return false;
|
||||
fd_ = openSerialTTY(device_.c_str(), baud_rate_, parity_);
|
||||
if (fd_ < 0)
|
||||
if (fd_ == -1)
|
||||
{
|
||||
if (fail_if_not_ok)
|
||||
{
|
||||
if (fd_ == -1)
|
||||
{
|
||||
error("Could not open %s with %d baud N81\n", device_.c_str(), baud_rate_);
|
||||
}
|
||||
else if (fd_ == -2)
|
||||
{
|
||||
error("Device %s is already in use and locked.\n", device_.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fd_ == -1)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
else if (fd_ == -2)
|
||||
{
|
||||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
}
|
||||
if (fail_if_not_ok) error("Could not open %s with %d baud N81\n", device_.c_str(), baud_rate_);
|
||||
verbose("(serialtty) could not open %s with %d baud N81\n", device_.c_str(), baud_rate_);
|
||||
return false;
|
||||
}
|
||||
if (fd_ == -2)
|
||||
{
|
||||
if (fail_if_not_ok) error("Device %s is already in use and locked.\n", device_.c_str());
|
||||
verbose("(serialtty) device %s is already in use and locked.\n", device_.c_str());
|
||||
return false;
|
||||
}
|
||||
verbose("(serialtty) opened %s fd %d (%s)\n", device_.c_str(), fd_, purpose_.c_str());
|
||||
return AccessCheck::AccessOK;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SerialDeviceTTY::close()
|
||||
|
@ -426,7 +420,7 @@ struct SerialDeviceCommand : public SerialDeviceImp
|
|||
string purpose);
|
||||
~SerialDeviceCommand();
|
||||
|
||||
AccessCheck open(bool fail_if_not_ok);
|
||||
bool open(bool fail_if_not_ok);
|
||||
void close();
|
||||
bool send(vector<uchar> &data);
|
||||
int available();
|
||||
|
@ -466,15 +460,15 @@ SerialDeviceCommand::~SerialDeviceCommand()
|
|||
close();
|
||||
}
|
||||
|
||||
AccessCheck SerialDeviceCommand::open(bool fail_if_not_ok)
|
||||
bool SerialDeviceCommand::open(bool fail_if_not_ok)
|
||||
{
|
||||
expectAscii();
|
||||
bool ok = invokeBackgroundShell("/bin/sh", args_, envs_, &fd_, &pid_);
|
||||
assert(fd_ >= 0);
|
||||
if (!ok) return AccessCheck::NotThere;
|
||||
if (!ok) return false;
|
||||
setIsStdin();
|
||||
verbose("(serialcmd) opened %s pid %d fd %d (%s)\n", command_.c_str(), pid_, fd_, purpose_.c_str());
|
||||
return AccessCheck::AccessOK;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SerialDeviceCommand::close()
|
||||
|
@ -553,7 +547,7 @@ struct SerialDeviceFile : public SerialDeviceImp
|
|||
SerialDeviceFile(string file, SerialCommunicationManagerImp *manager, string purpose);
|
||||
~SerialDeviceFile();
|
||||
|
||||
AccessCheck open(bool fail_if_not_ok);
|
||||
bool open(bool fail_if_not_ok);
|
||||
void close();
|
||||
bool working();
|
||||
bool send(vector<uchar> &data);
|
||||
|
@ -578,7 +572,7 @@ SerialDeviceFile::~SerialDeviceFile()
|
|||
close();
|
||||
}
|
||||
|
||||
AccessCheck SerialDeviceFile::open(bool fail_if_not_ok)
|
||||
bool SerialDeviceFile::open(bool fail_if_not_ok)
|
||||
{
|
||||
if (file_ == "stdin")
|
||||
{
|
||||
|
@ -592,25 +586,20 @@ AccessCheck SerialDeviceFile::open(bool fail_if_not_ok)
|
|||
else
|
||||
{
|
||||
bool ok = checkFileExists(file_.c_str());
|
||||
if (!ok) return AccessCheck::NotThere;
|
||||
if (!ok) return false;
|
||||
fd_ = ::open(file_.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd_ == -1)
|
||||
{
|
||||
if (fail_if_not_ok)
|
||||
{
|
||||
error("Could not open file %s for reading.\n", file_.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
if (fail_if_not_ok) error("Could not open file %s for reading.\n", file_.c_str());
|
||||
verbose("(serialdevicefile) could not open file %s for reading.\n", file_.c_str());
|
||||
return false;
|
||||
}
|
||||
setIsFile();
|
||||
verbose("(serialfile) reading from file %s (%s)\n", file_.c_str(), purpose_.c_str());
|
||||
}
|
||||
manager_->tickleEventLoop();
|
||||
|
||||
return AccessCheck::AccessOK;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SerialDeviceFile::close()
|
||||
|
@ -656,7 +645,7 @@ struct SerialDeviceSimulator : public SerialDeviceImp
|
|||
};
|
||||
~SerialDeviceSimulator() { };
|
||||
|
||||
AccessCheck open(bool fail_if_not_ok) { return AccessCheck::AccessOK; };
|
||||
bool open(bool fail_if_not_ok) { return true; };
|
||||
void close() { };
|
||||
bool readonly() { return true; }
|
||||
bool send(vector<uchar> &data) { return true; };
|
||||
|
@ -1602,3 +1591,52 @@ err:
|
|||
|
||||
return "error";
|
||||
}
|
||||
|
||||
AccessCheck SerialCommunicationManagerImp::checkAccess(string device,
|
||||
shared_ptr<SerialCommunicationManager> manager,
|
||||
string extra_info,
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> extra_probe)
|
||||
{
|
||||
assert(device != "");
|
||||
|
||||
if (extra_info == "")
|
||||
{
|
||||
extra_info = "serial";
|
||||
}
|
||||
|
||||
debug("(%s) check if %s can be accessed\n", extra_info.c_str(), device.c_str());
|
||||
|
||||
AccessCheck ac = checkIfExistsAndHasAccess(device);
|
||||
|
||||
if (ac == AccessCheck::AccessOK)
|
||||
{
|
||||
if (!extra_probe)
|
||||
{
|
||||
verbose("(%s) tty %s can be accessed\n", extra_info.c_str(), device.c_str());
|
||||
return AccessCheck::AccessOK;
|
||||
}
|
||||
verbose("(%s) tty %s can be accessed now probing...\n", extra_info.c_str(), device.c_str());
|
||||
ac = extra_probe(device, manager);
|
||||
verbose("(%s) probe returns %s\n", extra_info.c_str(), toString(ac));
|
||||
return ac;
|
||||
}
|
||||
|
||||
if (ac == AccessCheck::NoPermission)
|
||||
{
|
||||
verbose("(serial) you do not have the correct permissions to open the tty %s, but at least you share the same access group.\n",
|
||||
device.c_str());
|
||||
return AccessCheck::NoPermission;
|
||||
}
|
||||
|
||||
if (ac == AccessCheck::NotSameGroup)
|
||||
{
|
||||
verbose("(serial) you do not have the correct permissions to open the tty %s and you do not share the same access group.\n",
|
||||
device.c_str());
|
||||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
|
||||
verbose("(serial) cannot open/find tty %s.\n",
|
||||
device.c_str());
|
||||
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ enum class PARITY { NONE, EVEN, ODD };
|
|||
struct SerialDevice
|
||||
{
|
||||
// If fail_if_not_ok then forcefully exit the program if cannot be opened.
|
||||
virtual AccessCheck open(bool fail_if_not_ok) = 0;
|
||||
virtual bool open(bool fail_if_not_ok) = 0;
|
||||
virtual void close() = 0;
|
||||
// Explicitly closed fd == -1
|
||||
virtual bool isClosed() = 0;
|
||||
|
@ -106,6 +106,11 @@ struct SerialCommunicationManager
|
|||
virtual int startRegularCallback(std::string name, int seconds, function<void()> callback) = 0;
|
||||
virtual void stopRegularCallback(int id) = 0;
|
||||
|
||||
// Verify if the device can be accessed and verbose any failures.
|
||||
virtual AccessCheck checkAccess(std::string device,
|
||||
shared_ptr<SerialCommunicationManager> manager, // Silly but for now, needs shared pointer to itself....
|
||||
std::string extra_info = "",
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> extra_probe = NULL) = 0;
|
||||
// List all real serial devices (avoid pseudo ttys)
|
||||
virtual std::vector<std::string> listSerialTTYs() = 0;
|
||||
// Return a serial device for the given device, if it exists! Otherwise NULL.
|
||||
|
|
|
@ -42,6 +42,11 @@ void initUI()
|
|||
wbkgd(stdscr, COLOR_PAIR(BG_PAIR));
|
||||
}
|
||||
|
||||
void exitUI()
|
||||
{
|
||||
endwin();
|
||||
}
|
||||
|
||||
void registerUpdateCB(std::function<void()> cb)
|
||||
{
|
||||
update_cb_ = cb;
|
||||
|
|
1
src/ui.h
1
src/ui.h
|
@ -36,6 +36,7 @@
|
|||
#define HILIGHT_PAIR 4
|
||||
|
||||
void initUI();
|
||||
void exitUI();
|
||||
|
||||
void registerUpdateCB(std::function<void()> cb);
|
||||
|
||||
|
|
58
src/util.cc
58
src/util.cc
|
@ -1373,36 +1373,70 @@ void addMonths(struct tm *date, int months)
|
|||
date->tm_mday = day;
|
||||
}
|
||||
|
||||
AccessCheck checkIfExistsAndSameGroup(string device)
|
||||
const char* toString(AccessCheck ac)
|
||||
{
|
||||
struct stat sb;
|
||||
switch (ac)
|
||||
{
|
||||
case AccessCheck::NoSuchDevice: return "NoSuchDevice";
|
||||
case AccessCheck::NoProperResponse: return "NoProperResponse";
|
||||
case AccessCheck::NoPermission: return "NoPermission";
|
||||
case AccessCheck::NotSameGroup: return "NotSameGroup";
|
||||
case AccessCheck::AccessOK: return "AccessOK";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
int ok = stat(device.c_str(), &sb);
|
||||
AccessCheck checkIfExistsAndHasAccess(string device)
|
||||
{
|
||||
struct stat device_sb;
|
||||
|
||||
int ok = stat(device.c_str(), &device_sb);
|
||||
|
||||
// The file did not exist.
|
||||
if (ok) return AccessCheck::NotThere;
|
||||
if (ok) return AccessCheck::NoSuchDevice;
|
||||
|
||||
int r = access(device.c_str(), R_OK);
|
||||
int w = access(device.c_str(), W_OK);
|
||||
if (r == 0 && w == 0)
|
||||
{
|
||||
// We have read and write access!
|
||||
return AccessCheck::AccessOK;
|
||||
}
|
||||
|
||||
// We are not permitted to read and write to this tty. Why?
|
||||
// Lets check the group settings.
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
int groups[256];
|
||||
int my_groups[256];
|
||||
#else
|
||||
gid_t groups[256];
|
||||
gid_t my_groups[256];
|
||||
#endif
|
||||
int ngroups = 256;
|
||||
|
||||
struct passwd *p = getpwuid(getuid());
|
||||
|
||||
int rc = getgrouplist(p->pw_name, p->pw_gid, groups, &ngroups);
|
||||
// What are the groups I am member of?
|
||||
int rc = getgrouplist(p->pw_name, p->pw_gid, my_groups, &ngroups);
|
||||
if (rc < 0) {
|
||||
error("(wmbusmeters) cannot handle users with more than 256 groups\n");
|
||||
}
|
||||
struct group *g = getgrgid(sb.st_gid);
|
||||
|
||||
for (int i=0; i<ngroups; ++i) {
|
||||
if (groups[i] == g->gr_gid) {
|
||||
return AccessCheck::AccessOK;
|
||||
// What is the group of the tty?
|
||||
struct group *device_group = getgrgid(device_sb.st_gid);
|
||||
|
||||
// Go through my groups to see if the device's group is in there.
|
||||
for (int i=0; i<ngroups; ++i)
|
||||
{
|
||||
if (my_groups[i] == device_group->gr_gid)
|
||||
{
|
||||
// We belong to the same group as the tty. Typically dialout.
|
||||
// Then there is some other reason for the lack of access.
|
||||
return AccessCheck::NoPermission;
|
||||
}
|
||||
}
|
||||
|
||||
// We have examined all the groups that we belong to and yet not
|
||||
// found the device's group. We can at least conclude that we
|
||||
// being in the device's group would help, ie dialout.
|
||||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
|
||||
|
|
13
src/util.h
13
src/util.h
|
@ -174,10 +174,15 @@ void eatWhitespace(std::vector<char> &v, std::vector<char>::iterator &i, bool *e
|
|||
std::string eatToSkipWhitespace(std::vector<char> &v, std::vector<char>::iterator &i, int c, size_t max, bool *eof, bool *err);
|
||||
// Remove leading and trailing white space
|
||||
void trimWhitespace(std::string *s);
|
||||
// Returns true if device exists and this programs user, belongs
|
||||
// to the same group that the device belongs to.
|
||||
enum class AccessCheck { NotThere, NotSameGroup, Locked, AccessOK };
|
||||
AccessCheck checkIfExistsAndSameGroup(std::string device);
|
||||
// Returns AccessOK if device exists and is accessible.
|
||||
// NotSameGroup means that there is no permission and the groups do not match.
|
||||
// NoPermission means some other reason for no access. (missing rw etc)
|
||||
// Locked means that some other process has locked the tty.
|
||||
// NoSuchDevice means the tty does not exist.
|
||||
// NoProperResponse means that we talked to something, but we do not know what it is.
|
||||
enum class AccessCheck { NoSuchDevice, NoProperResponse, NoPermission, NotSameGroup, AccessOK };
|
||||
const char* toString(AccessCheck ac);
|
||||
AccessCheck checkIfExistsAndHasAccess(std::string device);
|
||||
// Count the number of 1:s in the binary number v.
|
||||
int countSetBits(int v);
|
||||
|
||||
|
|
81
src/wmbus.cc
81
src/wmbus.cc
|
@ -3693,9 +3693,9 @@ bool WMBusCommonImplementation::reset()
|
|||
usleep(3000*1000);
|
||||
}
|
||||
|
||||
AccessCheck rc = serial()->open(false);
|
||||
bool ok = serial()->open(false);
|
||||
|
||||
if (rc != AccessCheck::AccessOK)
|
||||
if (!ok)
|
||||
{
|
||||
// Ouch....
|
||||
return false;
|
||||
|
@ -4008,61 +4008,6 @@ LIST_OF_AFL_AUTH_TYPES
|
|||
return AFLAuthenticationType::Reserved1;
|
||||
}
|
||||
|
||||
AccessCheck findAndDetect(shared_ptr<SerialCommunicationManager> manager,
|
||||
string *out_device,
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> check,
|
||||
string dongle_name,
|
||||
string device_root)
|
||||
{
|
||||
string dev = device_root;
|
||||
debug("(%s) exists? %s\n", dongle_name.c_str(), dev.c_str());
|
||||
AccessCheck ac = checkIfExistsAndSameGroup(dev);
|
||||
*out_device = dev;
|
||||
if (ac == AccessCheck::AccessOK)
|
||||
{
|
||||
debug("(%s) checking %s\n", dongle_name.c_str(), dev.c_str());
|
||||
AccessCheck rc = check(dev, manager);
|
||||
if (rc == AccessCheck::AccessOK) return AccessCheck::AccessOK;
|
||||
}
|
||||
|
||||
if (ac == AccessCheck::NotSameGroup)
|
||||
{
|
||||
// Device exists, but you do not belong to its group!
|
||||
// This will short circuit testing for other devices.
|
||||
// But not being in the same group is such a problematic
|
||||
// situation, that we can stop early.
|
||||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
|
||||
*out_device = "";
|
||||
// No device found!
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
AccessCheck checkAccessAndDetect(shared_ptr<SerialCommunicationManager> manager,
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> check,
|
||||
string dongle_name,
|
||||
string device)
|
||||
{
|
||||
debug("(%s) exists? %s\n", dongle_name.c_str(), device.c_str());
|
||||
AccessCheck ac = checkIfExistsAndSameGroup(device);
|
||||
if (ac == AccessCheck::AccessOK)
|
||||
{
|
||||
debug("(%s) checking %s\n", dongle_name.c_str(), device.c_str());
|
||||
AccessCheck rc = check(device, manager);
|
||||
if (rc == AccessCheck::AccessOK) return AccessCheck::AccessOK;
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
if (ac == AccessCheck::NotSameGroup)
|
||||
{
|
||||
// Device exists, but you do not belong to its group!
|
||||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
|
||||
// No device found!
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
bool trimCRCsFrameFormatA(std::vector<uchar> &payload)
|
||||
{
|
||||
if (payload.size() < 12) {
|
||||
|
@ -4750,6 +4695,14 @@ Detected detectWMBusDeviceOnTTY(string tty,
|
|||
detected.specified_device.is_tty = true;
|
||||
detected.specified_device.linkmodes = desired_linkmodes;
|
||||
|
||||
AccessCheck ac = handler->checkAccess(tty, handler);
|
||||
if (ac != AccessCheck::AccessOK)
|
||||
{
|
||||
// Oups, some low level problem (permissions/groups etc) that means that we will not
|
||||
// be able to talk to the device. Lets stop here.
|
||||
return detected;
|
||||
}
|
||||
|
||||
// If im87a is tested first, a delay of 1s must be inserted
|
||||
// before amb8465 is tested, lest it will not respond properly.
|
||||
// It really should not matter, but perhaps is the uart of the amber
|
||||
|
@ -4790,8 +4743,8 @@ Detected detectWMBusDeviceOnTTY(string tty,
|
|||
}
|
||||
|
||||
Detected detectWMBusDeviceWithFileOrHex(SpecifiedDevice &specified_device,
|
||||
LinkModeSet default_linkmodes,
|
||||
shared_ptr<SerialCommunicationManager> handler)
|
||||
LinkModeSet default_linkmodes,
|
||||
shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
assert(specified_device.file != "" || specified_device.hex != "");
|
||||
assert(specified_device.command == "");
|
||||
|
@ -4901,23 +4854,23 @@ Detected detectWMBusDeviceWithCommand(SpecifiedDevice &specified_device,
|
|||
|
||||
AccessCheck detectUNKNOWN(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
AccessCheck detectSKIP(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
AccessCheck detectSIMULATION(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
AccessCheck detectAUTO(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
// Detection of auto is currently not implemented here, but elsewhere.
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
AccessCheck reDetectDevice(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
|
@ -4929,7 +4882,7 @@ LIST_OF_MBUS_DEVICES
|
|||
#undef X
|
||||
|
||||
assert(0);
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
bool usesRTLSDR(WMBusDeviceType t)
|
||||
|
|
11
src/wmbus.h
11
src/wmbus.h
|
@ -688,17 +688,6 @@ MeasurementType difMeasurementType(int dif);
|
|||
string linkModeName(LinkMode link_mode);
|
||||
string measurementTypeName(MeasurementType mt);
|
||||
|
||||
AccessCheck findAndDetect(shared_ptr<SerialCommunicationManager> manager,
|
||||
string *out_device,
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> check,
|
||||
string dongle_name,
|
||||
string device_root);
|
||||
|
||||
AccessCheck checkAccessAndDetect(shared_ptr<SerialCommunicationManager> manager,
|
||||
function<AccessCheck(string,shared_ptr<SerialCommunicationManager>)> check,
|
||||
string dongle_name,
|
||||
string device);
|
||||
|
||||
enum FrameStatus { PartialFrame, FullFrame, ErrorInFrame, TextAndNotFrame };
|
||||
|
||||
|
||||
|
|
|
@ -587,14 +587,16 @@ void WMBusAmber::handleMessage(int msgid, vector<uchar> &frame, int rssi_dbm)
|
|||
|
||||
AccessCheck detectAMB8465(Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||
{
|
||||
assert(detected->found_file != "");
|
||||
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(detected->found_file.c_str(), 9600, PARITY::NONE, "detect amb8465");
|
||||
serial->disableCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK)
|
||||
bool ok = serial->open(false);
|
||||
if (!ok)
|
||||
{
|
||||
debug("(amb8465) could not open tty for detection\n");
|
||||
return AccessCheck::NotThere;
|
||||
verbose("(amb8465) could not open tty %s for detection\n", detected->found_file.c_str());
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
vector<uchar> response;
|
||||
|
@ -659,7 +661,7 @@ AccessCheck detectAMB8465(Detected *detected, shared_ptr<SerialCommunicationMana
|
|||
debug("(amb8465) failed to sent query! Giving up!\n");
|
||||
verbose("(amb8465) are you there? no, nothing is there.\n");
|
||||
serial->close();
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
}
|
||||
} while (sent == false && count < 4);
|
||||
|
@ -676,7 +678,7 @@ AccessCheck detectAMB8465(Detected *detected, shared_ptr<SerialCommunicationMana
|
|||
{
|
||||
verbose("(amb8465) are you there? no.\n");
|
||||
serial->close();
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
debug("(amb8465) reading response... %d\n", count);
|
||||
|
||||
|
@ -725,10 +727,11 @@ static AccessCheck tryFactoryResetAMB8465(string device, shared_ptr<SerialCommun
|
|||
{
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), baud, PARITY::NONE, "reset amb8465");
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) {
|
||||
verbose("(amb8465) could not open device %s using baud %d\n", device.c_str(), baud);
|
||||
return AccessCheck::NotThere;
|
||||
bool ok = serial->open(false);
|
||||
if (!ok)
|
||||
{
|
||||
verbose("(amb8465) could not open device %s using baud %d for reset\n", device.c_str(), baud);
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
vector<uchar> data;
|
||||
|
@ -776,7 +779,7 @@ static AccessCheck tryFactoryResetAMB8465(string device, shared_ptr<SerialCommun
|
|||
data[4] != xorChecksum(data, 0, 4))
|
||||
{
|
||||
verbose("(amb8465) no response to factory reset %s using baud %d\n", device.c_str(), baud);
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
verbose("(amb8465) received proper factory reset response %s using baud %d\n", device.c_str(), baud);
|
||||
return AccessCheck::AccessOK;
|
||||
|
@ -786,7 +789,7 @@ int bauds[] = { 1200, 2400, 4800, 9600, 19200, 38400, 56000, 115200, 0 };
|
|||
|
||||
AccessCheck factoryResetAMB8465(string device, shared_ptr<SerialCommunicationManager> manager, int *was_baud)
|
||||
{
|
||||
AccessCheck rc = AccessCheck::NotThere;
|
||||
AccessCheck rc = AccessCheck::NoSuchDevice;
|
||||
|
||||
for (int i=0; bauds[i] != 0; ++i)
|
||||
{
|
||||
|
@ -798,5 +801,5 @@ AccessCheck factoryResetAMB8465(string device, shared_ptr<SerialCommunicationMan
|
|||
}
|
||||
}
|
||||
*was_baud = 0;
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
|
|
@ -382,8 +382,8 @@ AccessCheck detectCUL(Detected *detected, shared_ptr<SerialCommunicationManager>
|
|||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(detected->found_file.c_str(), 38400, PARITY::NONE, "detect cul");
|
||||
serial->disableCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
bool ok = serial->open(false);
|
||||
if (!ok) return AccessCheck::NoSuchDevice;
|
||||
|
||||
bool found = false;
|
||||
for (int i=0; i<3; ++i)
|
||||
|
@ -401,7 +401,7 @@ AccessCheck detectCUL(Detected *detected, shared_ptr<SerialCommunicationManager>
|
|||
if (!ok)
|
||||
{
|
||||
verbose("(cul) are you there? no\n");
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
// Wait for 200ms so that the USB stick have time to prepare a response.
|
||||
|
@ -422,7 +422,7 @@ AccessCheck detectCUL(Detected *detected, shared_ptr<SerialCommunicationManager>
|
|||
if (!found)
|
||||
{
|
||||
verbose("(cul) are you there? no\n");
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
|
||||
detected->setAsFound("", WMBusDeviceType::DEVICE_CUL, 38400, false, detected->specified_device.linkmodes);
|
||||
|
|
|
@ -966,11 +966,17 @@ bool WMBusIM871aIM170A::sendTelegram(ContentStartsWith starts_with, vector<uchar
|
|||
|
||||
AccessCheck detectIM871AIM170A(Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||
{
|
||||
assert(detected->found_file != "");
|
||||
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(detected->found_file.c_str(), 57600, PARITY::NONE, "detect im871a");
|
||||
serial->disableCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
bool ok = serial->open(false);
|
||||
if (!ok)
|
||||
{
|
||||
verbose("(im871a) could not open tty %s for detection\n", detected->found_file.c_str());
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
||||
vector<uchar> response;
|
||||
// First clear out any data in the queue.
|
||||
|
@ -1000,7 +1006,7 @@ AccessCheck detectIM871AIM170A(Detected *detected, shared_ptr<SerialCommunicatio
|
|||
{
|
||||
verbose("(im871a/im170a) are you there? no.\n");
|
||||
serial->close();
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
|
||||
vector<uchar> payload;
|
||||
|
@ -1047,7 +1053,7 @@ AccessCheck detectIM871AIM170A(Detected *detected, shared_ptr<SerialCommunicatio
|
|||
{
|
||||
verbose("(im871a/im170a) are you there? no.\n");
|
||||
serial->close();
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
|
||||
serial->close();
|
||||
|
|
|
@ -235,8 +235,8 @@ AccessCheck detectRAWTTY(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
// 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.
|
||||
auto serial = manager->createSerialDeviceTTY(tty.c_str(), bps, PARITY::NONE, "detect rawtty");
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
bool ok = serial->open(false);
|
||||
if (!ok) return AccessCheck::NoSuchDevice;
|
||||
|
||||
serial->close();
|
||||
|
||||
|
|
|
@ -163,6 +163,8 @@ private:
|
|||
|
||||
shared_ptr<WMBus> openRC1180(Detected detected, shared_ptr<SerialCommunicationManager> manager, shared_ptr<SerialDevice> serial_override)
|
||||
{
|
||||
assert(detected.found_file != "");
|
||||
|
||||
string bus_alias = detected.specified_device.bus_alias;
|
||||
string device = detected.found_file;
|
||||
assert(device != "");
|
||||
|
@ -341,8 +343,8 @@ AccessCheck detectRC1180(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(detected->found_file.c_str(), 19200, PARITY::NONE, "detect rc1180");
|
||||
serial->disableCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
bool ok = serial->open(false);
|
||||
if (!ok) return AccessCheck::NoSuchDevice;
|
||||
|
||||
vector<uchar> data;
|
||||
vector<uchar> msg(1);
|
||||
|
@ -360,7 +362,7 @@ AccessCheck detectRC1180(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
// no RC1180 device detected
|
||||
serial->close();
|
||||
verbose("(rc1180) are you there? no.\n");
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
|
||||
data.clear();
|
||||
|
@ -375,7 +377,7 @@ AccessCheck detectRC1180(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
serial->receive(&data);
|
||||
|
||||
ConfigRC1180 co;
|
||||
bool ok = co.decode(data);
|
||||
ok = co.decode(data);
|
||||
if (!ok || co.uart_bps != 5)
|
||||
{
|
||||
// Decode must be ok and the uart bps must be 5,
|
||||
|
@ -383,7 +385,7 @@ AccessCheck detectRC1180(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
// If not 5, then this is not a rc1180 dongle.
|
||||
serial->close();
|
||||
verbose("(rc1180) are you there? no.\n");
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoProperResponse;
|
||||
}
|
||||
|
||||
debug("(rc1180) config: %s\n", co.str().c_str());
|
||||
|
|
|
@ -367,5 +367,5 @@ FrameStatus WMBusRTL433::checkRTL433Frame(vector<uchar> &data,
|
|||
AccessCheck detectRTL433(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
assert(0);
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
|
|
@ -420,5 +420,5 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector<uchar> &data,
|
|||
AccessCheck detectRTLWMBUS(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
assert(0);
|
||||
return AccessCheck::NotThere;
|
||||
return AccessCheck::NoSuchDevice;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue