Detect and start wmbus dongles from within wmbusmeters.

pull/170/head
Fredrik Öhrström 2020-08-30 21:33:48 +02:00
rodzic 78a353de59
commit 69df7f022a
54 zmienionych plików z 1088 dodań i 1063 usunięć

Wyświetl plik

@ -192,8 +192,8 @@ $(BUILD)/main.o: $(BUILD)/short_manual.h $(BUILD)/version.h
$(BUILD)/wmbusmeters: $(METER_OBJS) $(BUILD)/main.o $(BUILD)/short_manual.h
$(CXX) -o $(BUILD)/wmbusmeters $(METER_OBJS) $(BUILD)/main.o $(LDFLAGS) -lpthread
$(BUILD)/wmbusmeters-admin: $(METER_OBJS) $(BUILD)/admin.o $(BUILD)/short_manual.h
$(CXX) -o $(BUILD)/wmbusmeters-admin $(METER_OBJS) $(BUILD)/admin.o $(LDFLAGS) -lmenu -lncurses -lpthread
$(BUILD)/wmbusmeters-admin: $(METER_OBJS) $(BUILD)/admin.o $(BUILD)/ui.o $(BUILD)/short_manual.h
$(CXX) -o $(BUILD)/wmbusmeters-admin $(METER_OBJS) $(BUILD)/admin.o $(BUILD)/ui.o $(LDFLAGS) -lmenu -lform -lncurses -lpthread
$(BUILD)/short_manual.h: README.md
echo 'R"MANUAL(' > $(BUILD)/short_manual.h

Wyświetl plik

@ -7,7 +7,6 @@ then
Options:
--no-adduser Do not add wmbusmeters user
--no-udev-rules Do not add udev rules
"
exit 0
fi
@ -33,7 +32,6 @@ fi
SRC=$1
ROOT="${2%/}"
ADDUSER=true
ADDUDEVRULES=true
while [ $# -ne 0 ]
do
@ -43,10 +41,6 @@ do
--no-adduser)
ADDUSER=false
;;
--no-udev-rules)
ADDUDEVRULES=false
shift
;;
esac
done
@ -94,7 +88,7 @@ fi
if [ "$ADDUSER" = "true" ]
then
if [ "$ID" = "" ]
if [ -z "$ID" ]
then
# Create the wmbusmeters user
useradd --system --shell $USERSHELL --groups dialout wmbusmeters
@ -102,6 +96,15 @@ then
else
echo user: wmbusmeters unmodified
fi
if [ "$(groups wmbusmeters | grep -o dialout)" = "" ]
then
# Add the wmbusmeters user to dialout
usermod -a -G dialout wmbusmeters
echo user: added wmbusmeters to dialout group
else
echo user: wmbusmeters already added to dialout
fi
if [ ! -z "$SUDO_USER" ]
then
if [ "$(groups $SUDO_USER | grep -o wmbusmeters)" = "" ]
@ -110,7 +113,15 @@ then
usermod -a -G wmbusmeters $SUDO_USER
echo user: added $SUDO_USER to group wmbusmeters
else
echo user: user $SUDO_USER already added group wmbusmeters
echo user: $SUDO_USER already added group wmbusmeters
fi
if [ "$(groups $SUDO_USER | grep -o dialout)" = "" ]
then
# Add user to the dialout group.
usermod -a -G dialout $SUDO_USER
echo user: added $SUDO_USER to group dialout
else
echo user: $SUDO_USER already added group dialout
fi
fi
fi
@ -268,88 +279,26 @@ OLD_WMBAS=~/old.wmbusmeters@.service.backup
CURR_WMBAS="$ROOT"/lib/systemd/system/wmbusmeters@.service
if [ -f $CURR_WMBAS ]
then
echo systemd: removing $CURR_WMBAS
echo systemd: backing up $CURR_WMBAS to here: $OLD_WMBAS
cp $CURR_WMBAS $OLD_WMBAS 2>/dev/null
fi
# Create service file that needs an argument eg.
# sudo systemctl start wmbusmeters@/dev/im871a_1.service
cat <<'EOF' > "$ROOT"/lib/systemd/system/wmbusmeters@.service
[Unit]
Description="wmbusmeters service (udev triggered by %I)"
Documentation=https://github.com/weetmuts/wmbusmeters
Documentation=man:wmbusmeters(1)
After=network.target
StopWhenUnneeded=true
StartLimitIntervalSec=10
StartLimitInterval=10
StartLimitBurst=3
[Service]
Type=forking
PrivateTmp=yes
User=wmbusmeters
Group=wmbusmeters
Restart=always
RestartSec=1
# Run ExecStartPre with root-permissions
PermissionsStartOnly=true
ExecStartPre=-/bin/mkdir -p /var/log/wmbusmeters/meter_readings
ExecStartPre=/bin/chown -R wmbusmeters:wmbusmeters /var/log/wmbusmeters
ExecStartPre=-/bin/mkdir -p /run/wmbusmeters
ExecStartPre=/bin/chown -R wmbusmeters:wmbusmeters /run/wmbusmeters
ExecStart=/usr/sbin/wmbusmetersd --device='%I' /run/wmbusmeters/wmbusmeters-%i.pid
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/run/wmbusmeters/wmbusmeters-%i.pid
[Install]
WantedBy=multi-user.target
EOF
if diff $OLD_WMBAS $CURR_WMBAS 1>/dev/null
then
echo systemd: no changes to $CURR_WMBAS
else
echo systemd: updated $CURR_WMBAS
rm $CURR_WMBAS
SYSTEMD_NEEDS_RELOAD=true
fi
####################################################################
##
## Create /etc/udev/rules.d/99-wmbus-usb-serial.rules
## Remove any existing /etc/udev/rules.d/99-wmbus-usb-serial.rules
## The new wmbuseters daemon is not going to use these.
##
UDEV_NEEDS_RELOAD=false
if [ "$ADDUDEVRULES" = "true" ]
if [ -f "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ]
then
if [ -f "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ]
then
echo udev: removing "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
echo udev: backup stored here: ~/old.wmbusmeters-wmbus-usb-serial.rules.backup
cp "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ~/old.wmbusmeters-wmbus-usb-serial.rules.backup
rm "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
UDEV_NEEDS_RELOAD=true
fi
if [ ! -f "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ]
then
mkdir -p "$ROOT"/etc/udev/rules.d
# Create service file
cat <<EOF > "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",SYMLINK+="im871a_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/im871a_%n.service"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",SYMLINK+="amb8465_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/amb8465_%n.service"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838",SYMLINK+="rtlsdr_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/rtlsdr_%n.service"
SUBSYSTEM=="usb", ATTRS{idVendor}=="2047", ATTRS{idProduct}=="0863",SYMLINK+="rfmrx2_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/rfmrx2_%n.service"
EOF
echo udev: installed "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
else
echo udev: "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules unchanged
fi
echo udev: removing "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
echo udev: backup stored here: ~/old.wmbusmeters-wmbus-usb-serial.rules.backup
cp "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ~/old.wmbusmeters-wmbus-usb-serial.rules.backup
rm "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
UDEV_NEEDS_RELOAD=true
fi
if [ "$SYSTEMD_NEEDS_RELOAD" = "true" ]
@ -362,13 +311,9 @@ fi
if [ "$UDEV_NEEDS_RELOAD" = "true" ]
then
D=$(diff "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ~/old.wmbusmeters-wmbus-usb-serial.rules.backup)
if [ "$D" != "" ]
then
echo
echo
echo You need to reload udev configuration! Please do:
echo "sudo udevadm control --reload-rules"
echo "sudo udevadm trigger"
fi
echo
echo
echo You need to reload udev configuration! Please do:
echo "sudo udevadm control --reload-rules"
echo "sudo udevadm trigger"
fi

Wyświetl plik

@ -15,24 +15,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include<curses.h>
#include<menu.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include <syslog.h>
#include<syslog.h>
#include"serial.h"
#include"shell.h"
#include"ui.h"
#include"wmbus.h"
#define BG_PAIR 1
#define WIN_PAIR 2
#define TITLE_PAIR 3
#define HILIGHT_PAIR 4
#include <menu.h>
bool running_as_root_ = false;
bool member_of_dialout_ = false;
@ -78,30 +70,24 @@ LIST_OF_WMBUS_RECEIVERS
};
bool detectIfRoot();
string userName();
bool detectIfMemberOfGroup(string group);
void detectProcesses(string cmd, vector<int> *pids);
void detectWMBUSReceiver();
void resetWMBUSReceiver();
void probeFor(string type, AccessCheck(*func)(string,SerialCommunicationManager*));
void probeFor(string type, AccessCheck(*func)(string,Detected*,SerialCommunicationManager*));
void printAt(WINDOW *win, int y, int x, const char *str, chtype color);
void printMiddle(WINDOW *win, int y, int width, const char *str, chtype color);
void stopDaemon();
void startDaemon();
void alwaysOnScreen();
int selectFromMenu(const char *title, const char *menu[]);
int selectFromMenu(const char *title, vector<string> menu);
void displayInformationAndWait(string title, vector<string> entries, int px=-1, int py=-1);
void displayInformationNoWait(WINDOW **win, string title, vector<string> entries, int px=-1, int py=-1);
void notImplementedYet(string msg);
int screen_width, screen_height;
unique_ptr<SerialCommunicationManager> handler;
WINDOW *status_window;
WINDOW *serial_ports_window;
WINDOW *processes_window;
void alwaysOnScreen();
int main(int argc, char **argv)
{
if (argc == 2 && (!strcmp(argv[1], "--debug") || !strcmp(argv[1], "--trace")))
@ -112,27 +98,33 @@ int main(int argc, char **argv)
enableSyslog();
}
initUI();
clear();
refresh();
int x=0;
int y=0;
for (int i=0;i<10; ++i) {
printAt(stdscr, y, x, "HEJSAN", COLOR_PAIR(BG_PAIR));
y++;
x++;
};
refresh();
for(;;) {}
endwin();
return 0;
/*
running_as_root_ = detectIfRoot();
member_of_dialout_ = detectIfMemberOfGroup("dialout");
handler = createSerialCommunicationManager(0, 0, false);
initscr();
getmaxyx(stdscr, screen_height, screen_width);
start_color();
cbreak();
curs_set(0);
noecho();
keypad(stdscr, TRUE);
init_pair(BG_PAIR, COLOR_WHITE, COLOR_BLUE);
init_pair(WIN_PAIR, COLOR_BLACK, COLOR_WHITE);
init_pair(TITLE_PAIR, COLOR_WHITE, COLOR_CYAN);
init_pair(HILIGHT_PAIR, COLOR_WHITE, COLOR_RED);
wbkgd(stdscr, COLOR_PAIR(BG_PAIR));
initUI();
bool running = true;
registerUpdateCB(alwaysOnScreen);
alwaysOnScreen();
do
@ -157,84 +149,23 @@ int main(int argc, char **argv)
notImplementedYet("Edit meters");
break;
case MainMenuType::STOP_DAEMON:
notImplementedYet("Stop daemon");
stopDaemon();
break;
case MainMenuType::START_DAEMON:
notImplementedYet("Start daemon");
startDaemon();
break;
case MainMenuType::EXIT_ADMIN:
running = false;
break;
}
} while (running);
endwin();
}
void printAt(WINDOW *win, int y, int x, const char *str, chtype color)
{
wattron(win, color);
mvwprintw(win, y, x, "%s", str);
wattroff(win, color);
refresh();
}
void printMiddle(WINDOW *win, int y, int width, const char *str, chtype color)
{
int len = strlen(str);
int wh, ww;
getyx(win, wh, ww);
((void)wh);
int x = (width-len)/2;
wattron(win, color);
mvwprintw(win, y, x, "%s", str);
wattroff(win, color);
refresh();
}
int countEntries(const char *entries[])
{
int i = 0;
for (; entries[i] != 0; ++i);
return i+1;
}
int maxWidth(const char *entries[])
{
int max = 0;
for (int i=0; entries[i] != 0; ++i)
{
int n = strlen(entries[i]);
if (max < n) max = n;
}
return max;
}
int maxWidth(vector<string> entries)
{
int max = 0;
for (string& s : entries)
{
int n = s.length();
if (max < n) max = n;
}
return max;
*/
}
void alwaysOnScreen()
{
static uchar ticktock = 0;
vector<string> info;
ticktock++;
if (running_as_root_ == false)
{
info.push_back("Not running as root!");
}
if (member_of_dialout_ == false)
{
info.push_back("Not member of dialout!");
@ -268,7 +199,17 @@ void alwaysOnScreen()
}
}
displayInformationNoWait(&status_window, (ticktock%2==0)?"Status ":"Status.", info, 1, 1);
vector<string> status;
time_t now = time(NULL);
struct tm nowt {};
localtime_r(&now, &nowt);
status.push_back("wmbusmeters-admin");
status.push_back(strdatetimesec(&nowt));
string name = "["+userName()+"]";
status.push_back(name);
displayStatusLineNoWait(&status_window, status, 0, 0);
displayInformationNoWait(&status_window, "Problems", info, 2, 2);
vector<string> devices = handler->listSerialDevices();
if (devices.size() == 0)
@ -280,252 +221,8 @@ void alwaysOnScreen()
displayInformationNoWait(&serial_ports_window, "Serial ports", devices, 1, 15);
erase();
redrawwin(status_window);
redrawwin(serial_ports_window);
}
int selectFromMenu(const char *title, const char *entries[])
{
vector<string> menu;
int n_choices = countEntries(entries);
for (int i=0; i<n_choices; ++i)
{
if (entries[i] == NULL) break;
menu.push_back(entries[i]);
}
return selectFromMenu(title, menu);
}
int selectFromMenu(const char *title, vector<string> entries)
{
int selected = -1;
ITEM **menu_items;
int c;
MENU *menu;
WINDOW *frame_window, *menu_window;
int n_choices, i;
n_choices = entries.size()+1;
menu_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
for(i = 0; i < n_choices-1; ++i)
{
menu_items[i] = new_item(entries[i].c_str(), NULL);
}
menu_items[n_choices-1] = NULL;
menu = new_menu(menu_items);
int mw = 0;
int mh = 0;
scale_menu(menu, &mh, &mw);
int w = mw+2;
int h = mh+4;
if (w-2 < (int)strlen(title))
{
w = (int)strlen(title)+2;
}
int x = screen_width/2-w/2;
int y = screen_height/2-h/2;
frame_window = newwin(h, w, y, x);
int mx = (w-mw)/2;
int my = 3;
menu_window = derwin(frame_window, mh, mw, my, mx);
set_menu_fore(menu, COLOR_PAIR(HILIGHT_PAIR));
set_menu_back(menu, COLOR_PAIR(WIN_PAIR));
set_menu_grey(menu, COLOR_PAIR(3));
keypad(frame_window, TRUE);
set_menu_win(menu, frame_window);
set_menu_sub(menu, menu_window);
set_menu_mark(menu, ">");
box(frame_window, 0, 0);
wbkgd(frame_window, COLOR_PAIR(WIN_PAIR));
printMiddle(frame_window, 1, w, title, COLOR_PAIR(WIN_PAIR));
mvwaddch(frame_window, 2, 0, ACS_LTEE);
mvwhline(frame_window, 2, 1, ACS_HLINE, 38);
mvwaddch(frame_window, 2, w-1, ACS_RTEE);
refresh();
post_menu(menu);
wrefresh(frame_window);
alwaysOnScreen();
wtimeout(frame_window, 1000);
bool running = true;
do
{
c = wgetch(frame_window);
ITEM *cur = current_item(menu);
selected = item_index(cur);
switch(c)
{
case ERR:
alwaysOnScreen();
redrawwin(frame_window);
break;
case KEY_DOWN:
if (selected < n_choices-2)
{
menu_driver(menu, REQ_DOWN_ITEM);
}
else
{
menu_driver(menu, REQ_FIRST_ITEM);
}
break;
case KEY_UP:
if (selected > 0)
{
menu_driver(menu, REQ_UP_ITEM);
}
else
{
menu_driver(menu, REQ_LAST_ITEM);
}
break;
case '\n':
running = false;
break;
}
wrefresh(frame_window);
} while (running);
unpost_menu(menu);
free_menu(menu);
delwin(frame_window);
erase();
refresh();
for(i = 0; i < n_choices; ++i)
{
free_item(menu_items[i]);
}
return selected;
}
void displayInformationAndWait(string title, vector<string> entries, int px, int py)
{
WINDOW *frame_window;
alwaysOnScreen();
int mw = maxWidth(entries)+1;
int mh = entries.size();
int w = mw+2;
int h = mh+4;
if (w-2 < (int)title.length())
{
w = (int)title.length()+2;
}
int x = screen_width/2-w/2;
int y = screen_height/2-h/2;
if (px != -1)
{
x = px;
}
if (py != -1)
{
y = py;
}
frame_window = newwin(h, w, y, x);
keypad(frame_window, TRUE);
box(frame_window, 0, 0);
wbkgd(frame_window, COLOR_PAIR(WIN_PAIR));
printMiddle(frame_window, 1, w, title.c_str(), COLOR_PAIR(WIN_PAIR));
mvwaddch(frame_window, 2, 0, ACS_LTEE);
mvwhline(frame_window, 2, 1, ACS_HLINE, 38);
mvwaddch(frame_window, 2, w-1, ACS_RTEE);
//refresh();
int r = 3;
for (string e : entries)
{
printAt(frame_window, r, 1, e.c_str(), COLOR_PAIR(WIN_PAIR));
r++;
}
wrefresh(frame_window);
wtimeout(frame_window, 1000);
bool running = true;
do
{
int c = wgetch(frame_window);
switch(c)
{
case ERR:
alwaysOnScreen();
redrawwin(frame_window);
break;
case 27:
case '\n':
running = false;
break;
}
wrefresh(frame_window);
} while (running);
delwin(frame_window);
erase();
refresh();
}
void displayInformationNoWait(WINDOW **winp, string title, vector<string> entries, int px, int py)
{
WINDOW *win = *winp;
if (win != NULL)
{
delwin(win);
*winp = NULL;
}
int mw = maxWidth(entries)+1;
int mh = entries.size();
int w = mw+2;
int h = mh+4;
if (w-2 < (int)title.length())
{
w = (int)title.length()+2;
}
int x = screen_width/2-w/2;
int y = screen_height/2-h/2;
if (px != -1)
{
x = px;
}
if (py != -1)
{
y = py;
}
win = newwin(h, w, y, x);
*winp = win;
box(win, 0, 0);
wbkgd(win, COLOR_PAIR(WIN_PAIR));
printMiddle(win, 1, w, title.c_str(), COLOR_PAIR(WIN_PAIR));
mvwaddch(win, 2, 0, ACS_LTEE);
mvwhline(win, 2, 1, ACS_HLINE, 38);
mvwaddch(win, 2, w-1, ACS_RTEE);
// refresh();
int r = 3;
for (string e : entries)
{
printAt(win, r, 1, e.c_str(), COLOR_PAIR(WIN_PAIR));
r++;
}
wrefresh(win);
wrefresh(status_window);
wrefresh(serial_ports_window);
}
void detectWMBUSReceiver()
@ -586,15 +283,9 @@ void resetWMBUSReceiver()
}
}
void notImplementedYet(string msg)
{
vector<string> entries;
entries.push_back(msg);
displayInformationAndWait("Not implemented yet", entries);
}
void probeFor(string type, AccessCheck (*check)(string,SerialCommunicationManager*))
void probeFor(string type, AccessCheck (*check)(string,Detected*,SerialCommunicationManager*))
{
Detected detected {};
vector<string> devices = handler->listSerialDevices();
vector<string> entries;
for (string& device : devices)
@ -602,7 +293,7 @@ void probeFor(string type, AccessCheck (*check)(string,SerialCommunicationManage
string tty = "?";
AccessCheck ac = checkAccessAndDetect(
handler.get(),
[=](string d, SerialCommunicationManager* m){ return check(d, m);},
[&](string d, SerialCommunicationManager* m){ return check(d, &detected, m);},
type,
device);
@ -638,6 +329,18 @@ bool detectIfRoot()
return out == "0\n";
}
string userName()
{
vector<string> args;
vector<string> envs;
args.push_back("-u");
args.push_back("-n");
string out;
invokeShellCaptureOutput("/usr/bin/id", args, envs, &out, true);
return out;
}
bool detectIfMemberOfGroup(string group)
{
vector<string> args;
@ -674,3 +377,49 @@ void detectProcesses(string cmd, vector<int> *pids)
pch = strtok (NULL, " \n");
}
}
void stopDaemon()
{
vector<string> info;
info.push_back("Enter sudo password to execute:");
info.push_back("systemctl stop wmbusmeters");
debug("(passowrd) calling inputfield\n");
string pwd = inputField("Stop daemon", info, "Password");
debug("(passowrd) GOT %s\n", pwd.c_str());
//string pwd = displayInformationAndInput("Stop daemon", info, 1, 1);
//vector<string> args;
//vector<string> envs;
//args.push_back("gurka");
// string out;
// invokeShellCaptureOutput("systemctl stop wmbusmeters", args, envs, &out, true);
}
void startDaemon()
{
}
/*
static char* trim_whitespaces(char *str)
{
char *end;
// trim leading space
while(isspace(*str))
str++;
if(*str == 0) // all spaces?
return str;
// trim trailing space
end = str + strnlen(str, 128) - 1;
while(end > str && isspace(*end))
end--;
// write new null terminator
*(end+1) = '\0';
return str;
}
*/

Wyświetl plik

@ -16,7 +16,6 @@
*/
#include"cmdline.h"
#include"config.h"
#include"meters.h"
#include"util.h"
@ -68,7 +67,8 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
c->need_help = true;
return unique_ptr<Configuration>(c);
}
while (argv[i] && argv[i][0] == '-') {
while (argv[i] && argv[i][0] == '-')
{
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
c->need_help = true;
return unique_ptr<Configuration>(c);
@ -96,6 +96,12 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
i++;
continue;
}
if (!strcmp(argv[i], "--trace")) {
c->debug = true;
c->trace = true;
i++;
continue;
}
if (!strcmp(argv[i], "--internaltesting")) {
c->internaltesting = true;
i++;
@ -438,18 +444,17 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
error("Unknown option \"%s\"\n", argv[i]);
}
char *extra = argv[i] ? strchr(argv[i], ':') : NULL ;
if (extra) {
*extra = 0;
extra++;
c->device_extra = extra;
while (argv[i])
{
Device device;
bool ok = isPossibleDevice(argv[i], &device);
if (!ok) break;
c->wmbus_devices.push_back(device);
i++;
}
if (argv[i]) {
c->device = argv[i];
}
i++;
if (c->device.length() == 0) {
error("You must supply the usb device to which the wmbus dongle is connected.\n");
if (c->wmbus_devices.size() == 0) {
error("You must supply at least one device to receive wmbus telegrams.\n");
}
if ((argc-i) % 4 != 0) {

Wyświetl plik

@ -189,20 +189,18 @@ void handleInternalTesting(Configuration *c, string value)
}
}
void handleDevice(Configuration *c, string device)
void handleDevice(Configuration *c, string devicefile)
{
// device can be:
// /dev/ttyUSB00
// auto
// rtlwmbus:/usr/bin/rtl_sdr -f 868.9M -s 1600000 - | /usr/bin/rtl_wmbus
// simulation....txt (read telegrams from file)
size_t p = device.find (':');
if (p != string::npos)
Device device;
bool ok = isPossibleDevice(devicefile, &device);
if (ok)
{
c->device_extra = device.substr(p+1);
c->device = device.substr(0,p);
} else {
c->device = device;
c->wmbus_devices.push_back(device);
}
}

Wyświetl plik

@ -79,8 +79,8 @@ struct Configuration
bool oneshot {};
int exitafter {}; // Seconds to exit.
int reopenafter {}; // Re-open the serial device repeatedly. Silly dongle.
string device; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus
string device_extra; // The frequency or the command line that will start rtlwmbus
std::vector<Device> wmbus_devices; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus, /dev/ttyUSB1:9600
std::vector<Device> mbus_devices; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus, /dev/ttyUSB1:9600
string telegram_reader;
// A set of all link modes (union) that the user requests the wmbus dongle to listen to.
LinkModeSet listen_to_link_modes;

Wyświetl plik

@ -1,5 +1,5 @@
/*
Copyright (C) 2017-2019 Fredrik Öhrström
Copyright (C) 2017-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
@ -24,8 +24,7 @@
#include"version.h"
#include"wmbus.h"
#include<string.h>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
@ -38,21 +37,49 @@
using namespace std;
void oneshotCheck(Configuration *cmdline, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> &meters);
bool startUsingCommandline(Configuration *cmdline);
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> *meters);
void setupLogFile(Configuration *config);
void setupMeters(Configuration *config, vector<unique_ptr<Meter>> *meters);
void attachMetersToPrinter(Configuration *config, vector<unique_ptr<Meter>> *meters, Printer *printer);
void detectAndConfigureWMBusDevices(Configuration *config, SerialCommunicationManager *manager, vector<unique_ptr<WMBus>> *devices);
unique_ptr<Printer> createPrinter(Configuration *config);
void logStartInformation(Configuration *config);
bool start(Configuration *config);
void startUsingConfigFiles(string root, bool is_daemon, string device_override, string listento_override);
void startDaemon(string pid_file, string device_override, string listento_override); // Will use config files.
// The serial communication manager takes care of
// monitoring the file descrtiptors for the ttys,
// background shells. It also invokes regular callbacks
// used for monitoring alarms and detecting new devices.
unique_ptr<SerialCommunicationManager> manager_;
// Registered meters to decode and relay.
// This does not change during runtime.
vector<unique_ptr<Meter>> meters_;
// Current active set of wmbus devices that can receive telegrams.
// This can change during runtime, plugging/unplugging wmbus dongles.
vector<unique_ptr<WMBus>> devices_;
pthread_mutex_t devices_lock_ = PTHREAD_MUTEX_INITIALIZER;
// Rendering the telegrams to json,fields or shell calls is
// done by the printer.
unique_ptr<Printer> printer_;
// Set as true when the warning for no detected wmbus devices has been printed.
bool printed_warning_ = false;
int main(int argc, char **argv)
{
auto cmdline = parseCommandLine(argc, argv);
auto config = parseCommandLine(argc, argv);
if (cmdline->version) {
if (config->version) {
printf("wmbusmeters: " VERSION "\n");
printf(COMMIT "\n");
exit(0);
}
if (cmdline->license) {
if (config->license) {
const char * license = R"LICENSE(
Copyright (C) 2017-2020 Fredrik Öhrström
@ -77,129 +104,79 @@ provided you with this binary. Read the full license for all details.
puts(license);
exit(0);
}
if (cmdline->need_help) {
if (config->need_help) {
printf("wmbusmeters version: " VERSION "\n");
const char *short_manual =
#include"short_manual.h"
puts(short_manual);
}
else
if (cmdline->daemon) {
startDaemon(cmdline->pid_file, cmdline->device_override, cmdline->listento_override);
if (config->daemon) {
startDaemon(config->pid_file, config->device_override, config->listento_override);
exit(0);
}
else
if (cmdline->useconfig) {
startUsingConfigFiles(cmdline->config_root, false, cmdline->device_override, cmdline->listento_override);
if (config->useconfig) {
startUsingConfigFiles(config->config_root, false, config->device_override, config->listento_override);
exit(0);
}
else {
// We want the data visible in the log file asap!
setbuf(stdout, NULL);
startUsingCommandline(cmdline.get());
start(config.get());
exit(0);
}
error("(main) internal error\n");
}
bool startUsingCommandline(Configuration *config)
unique_ptr<WMBus> createWMBusDeviceFrom(Detected *detected, Configuration *config, SerialCommunicationManager *manager)
{
if (config->use_logfile)
{
verbose("(wmbusmeters) using log file %s\n", config->logfile.c_str());
bool ok = enableLogfile(config->logfile, config->daemon);
if (!ok) {
if (config->daemon) {
warning("Could not open log file, will use syslog instead.\n");
} else {
error("Could not open log file.\n");
}
}
}
else
{
disableLogfile();
}
warningSilenced(config->silence);
verboseEnabled(config->verbose);
logTelegramsEnabled(config->logtelegrams);
debugEnabled(config->debug);
internalTestingEnabled(config->internaltesting);
traceEnabled(config->trace);
stderrEnabled(config->use_stderr);
setAlarmShells(config->alarm_shells);
debug("(wmbusmeters) version: " VERSION "\n");
if (config->exitafter != 0) {
verbose("(config) wmbusmeters will exit after %d seconds\n", config->exitafter);
}
if (config->reopenafter != 0) {
verbose("(config) wmbusmeters close/open the wmbus dongle fd after every %d seconds\n", config->reopenafter);
}
if (config->meterfiles) {
verbose("(config) store meter files in: \"%s\"\n", config->meterfiles_dir.c_str());
}
verbose("(config) using device: %s\n", config->device.c_str());
if (config->device_extra.length() > 0) {
verbose("(config) with: %s\n", config->device_extra.c_str());
}
verbose("(config) number of meters: %d\n", config->meters.size());
auto manager = createSerialCommunicationManager(config->exitafter, config->reopenafter);
onExit(call(manager.get(),stop));
Detected settings = detectWMBusDeviceSetting(config->device, config->device_extra, manager.get());
unique_ptr<WMBus> wmbus;
unique_ptr<SerialDevice> serial_override;
bool link_modes_matter = true;
if (settings.override_tty)
if (detected->override_tty)
{
serial_override = manager->createSerialDeviceFile(settings.devicefile);
verbose("(serial) override with devicefile: %s\n", settings.devicefile.c_str());
serial_override = manager->createSerialDeviceFile(detected->device.file);
verbose("(serial) override with devicefile: %s\n", detected->device.file.c_str());
link_modes_matter = false;
}
unique_ptr<WMBus> wmbus;
switch (settings.type)
switch (detected->type)
{
case DEVICE_IM871A:
verbose("(im871a) on %s\n", settings.devicefile.c_str());
wmbus = openIM871A(settings.devicefile, manager.get(), std::move(serial_override));
verbose("(im871a) on %s\n", detected->device.file.c_str());
wmbus = openIM871A(detected->device.file, manager, std::move(serial_override));
break;
case DEVICE_AMB8465:
verbose("(amb8465) on %s\n", settings.devicefile.c_str());
wmbus = openAMB8465(settings.devicefile, manager.get(), std::move(serial_override));
verbose("(amb8465) on %s\n", detected->device.file.c_str());
wmbus = openAMB8465(detected->device.file, manager, std::move(serial_override));
break;
case DEVICE_SIMULATOR:
verbose("(simulator) in %s\n", settings.devicefile.c_str());
wmbus = openSimulator(settings.devicefile, manager.get(), std::move(serial_override));
verbose("(simulator) in %s\n", detected->device.file.c_str());
wmbus = openSimulator(detected->device.file, manager, std::move(serial_override));
link_modes_matter = false;
break;
case DEVICE_RAWTTY:
verbose("(rawtty) on %s\n", settings.devicefile.c_str());
wmbus = openRawTTY(settings.devicefile, settings.baudrate, manager.get(), std::move(serial_override));
verbose("(rawtty) on %s\n", detected->device.file.c_str());
wmbus = openRawTTY(detected->device.file, detected->baudrate, manager, std::move(serial_override));
link_modes_matter = false;
break;
case DEVICE_RFMRX2:
verbose("(rfmrx2) on %s\n", settings.devicefile.c_str());
verbose("(rfmrx2) on %s\n", detected->device.file.c_str());
if (config->reopenafter == 0)
{
manager->setReopenAfter(600); // Close and reopen the fd, because of some bug in the device.
}
wmbus = openRawTTY(settings.devicefile, 38400, manager.get(), std::move(serial_override));
wmbus = openRawTTY(detected->device.file, 38400, manager, std::move(serial_override));
break;
case DEVICE_RTLWMBUS:
{
string command;
if (!settings.override_tty)
if (!detected->override_tty)
{
command = config->device_extra;
command = detected->device.suffix;
string freq = "868.95M";
string prefix = "";
if (isFrequency(command)) {
@ -226,7 +203,7 @@ bool startUsingCommandline(Configuration *config)
}
verbose("(rtlwmbus) using command: %s\n", command.c_str());
}
wmbus = openRTLWMBUS(command, manager.get(),
wmbus = openRTLWMBUS(command, manager,
[command](){
warning("(rtlwmbus) child process exited! "
"Command was: \"%s\"\n", command.c_str());
@ -237,9 +214,9 @@ bool startUsingCommandline(Configuration *config)
case DEVICE_RTL433:
{
string command;
if (!settings.override_tty)
if (!detected->override_tty)
{
command = config->device_extra;
command = detected->device.suffix;
string freq = "868.95M";
string prefix = "";
if (isFrequency(command)) {
@ -262,7 +239,7 @@ bool startUsingCommandline(Configuration *config)
}
verbose("(rtl433) using command: %s\n", command.c_str());
}
wmbus = openRTL433(command, manager.get(),
wmbus = openRTL433(command, manager,
[command](){
warning("(rtl433) child process exited! "
"Command was: \"%s\"\n", command.c_str());
@ -272,20 +249,20 @@ bool startUsingCommandline(Configuration *config)
}
case DEVICE_CUL:
{
verbose("(cul) on %s\n", settings.devicefile.c_str());
wmbus = openCUL(settings.devicefile, manager.get(), std::move(serial_override));
verbose("(cul) on %s\n", detected->device.file.c_str());
wmbus = openCUL(detected->device.file, manager, std::move(serial_override));
break;
}
case DEVICE_D1TC:
{
verbose("(d1tc) on %s\n", settings.devicefile.c_str());
wmbus = openD1TC(settings.devicefile, manager.get(), std::move(serial_override));
verbose("(d1tc) on %s\n", detected->device.file.c_str());
wmbus = openD1TC(detected->device.file, manager, std::move(serial_override));
break;
}
case DEVICE_WMB13U:
{
verbose("(wmb13u) on %s\n", settings.devicefile.c_str());
wmbus = openWMB13U(settings.devicefile, manager.get(), std::move(serial_override));
verbose("(wmb13u) on %s\n", detected->device.file.c_str());
wmbus = openWMB13U(detected->device.file, manager, std::move(serial_override));
break;
}
case DEVICE_UNKNOWN:
@ -302,127 +279,301 @@ bool startUsingCommandline(Configuration *config)
if (lmcr.type != LinkModeCalculationResultType::Success) {
error("%s\n", lmcr.msg.c_str());
}
return wmbus;
}
auto output = unique_ptr<Printer>(new Printer(config->json, config->fields,
config->separator, config->meterfiles, config->meterfiles_dir,
config->use_logfile, config->logfile,
config->telegram_shells,
config->meterfiles_action == MeterFileType::Overwrite,
config->meterfiles_naming,
config->meterfiles_timestamp));
vector<unique_ptr<Meter>> meters;
if (config->meters.size() > 0)
void setupLogFile(Configuration *config)
{
if (config->use_logfile)
{
for (auto &m : config->meters)
{
const char *keymsg = (m.key[0] == 0) ? "not-encrypted" : "encrypted";
switch (toMeterType(m.type))
{
#define X(mname,link,info,type,cname) \
case MeterType::type: \
meters.push_back(create##cname(wmbus.get(), m)); \
verbose("(wmbusmeters) configured \"%s\" \"" #mname "\" \"%s\" %s\n", \
m.name.c_str(), m.id.c_str(), keymsg); \
meters.back()->addConversions(config->conversions); \
break;
LIST_OF_METERS
#undef X
case MeterType::UNKNOWN:
error("No such meter type \"%s\"\n", m.type.c_str());
break;
verbose("(wmbusmeters) using log file %s\n", config->logfile.c_str());
bool ok = enableLogfile(config->logfile, config->daemon);
if (!ok) {
if (config->daemon) {
warning("Could not open log file, will use syslog instead.\n");
} else {
error("Could not open log file.\n");
}
if (config->list_shell_envs)
{
string ignore1, ignore2, ignore3;
vector<string> envs;
Telegram t;
meters.back()->printMeter(&t,
&ignore1,
&ignore2, config->separator,
&ignore3,
&envs,
&config->jsons,
&config->selected_fields);
printf("Environment variables provided to shell for meter %s:\n", m.type.c_str());
for (auto &e : envs) {
int p = e.find('=');
string key = e.substr(0,p);
printf("%s\n", key.c_str());
}
exit(0);
}
if (config->list_fields)
{
printf("Fields produced by meter %s:\n", m.type.c_str());
printf("id\n");
printf("name\n");
printf("timestamp\n");
for (auto &f : meters.back()->fields())
{
printf("%s\n", f.c_str());
}
exit(0);
}
meters.back()->onUpdate([&](Telegram*t,Meter* meter)
{
output->print(t,meter,&config->jsons,&config->selected_fields);
});
meters.back()->onUpdate([&](Telegram*t, Meter* meter)
{
oneshotCheck(config, manager.get(), t, meter, meters);
});
}
}
else
{
notice("No meters configured. Printing id:s of all telegrams heard!\n\n");
disableLogfile();
}
}
wmbus->onTelegram([](vector<uchar> frame){
Telegram t;
MeterKeys mk;
t.parserNoWarnings(); // Try a best effort parse, do not print any warnings.
t.parse(frame, &mk);
t.print();
t.explainParse("(wmbus)",0);
logTelegram("(wmbus)", t.frame, 0, 0);
return true;
});
void setupMeters(Configuration *config, vector<unique_ptr<Meter>> *meters)
{
for (auto &m : config->meters)
{
const char *keymsg = (m.key[0] == 0) ? "not-encrypted" : "encrypted";
switch (toMeterType(m.type))
{
#define X(mname,link,info,type,cname) \
case MeterType::type: \
meters->push_back(create##cname(m)); \
verbose("(wmbusmeters) configured \"%s\" \"" #mname "\" \"%s\" %s\n", \
m.name.c_str(), m.id.c_str(), keymsg); \
meters->back()->addConversions(config->conversions); \
break;
LIST_OF_METERS
#undef X
case MeterType::UNKNOWN:
error("No such meter type \"%s\"\n", m.type.c_str());
break;
}
if (config->list_shell_envs)
{
string ignore1, ignore2, ignore3;
vector<string> envs;
Telegram t;
meters->back()->printMeter(&t,
&ignore1,
&ignore2, config->separator,
&ignore3,
&envs,
&config->jsons,
&config->selected_fields);
printf("Environment variables provided to shell for meter %s:\n", m.type.c_str());
for (auto &e : envs) {
int p = e.find('=');
string key = e.substr(0,p);
printf("%s\n", key.c_str());
}
exit(0);
}
if (config->list_fields)
{
printf("Fields produced by meter %s:\n", m.type.c_str());
printf("id\n");
printf("name\n");
printf("timestamp\n");
for (auto &f : meters->back()->fields())
{
printf("%s\n", f.c_str());
}
exit(0);
}
}
}
void attachMetersToPrinter(Configuration *config, vector<unique_ptr<Meter>> *meters, Printer *printer)
{
for (auto &meter : *meters)
{
meter->onUpdate([&](Telegram*t,Meter* meter)
{
printer->print(t,meter,&config->jsons,&config->selected_fields);
});
meter->onUpdate([&](Telegram*t, Meter* meter)
{
oneshotCheck(config, manager_.get(), t, meter, meters);
});
}
}
void detectAndConfigureWMBusDevices(Configuration *config, SerialCommunicationManager *manager, vector<unique_ptr<WMBus>> *devices)
{
trace("(trace main) checking for dead wmbus devices...\n");
LOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
vector<WMBus*> not_working;
for (auto &w : devices_)
{
if (!w->isWorking())
{
not_working.push_back(w.get());
}
}
wmbus->setMeters(&meters);
wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
manager->startEventLoop();
wmbus->setLinkModes(config->listen_to_link_modes);
string using_link_modes = wmbus->getLinkModes().hr();
verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
if (settings.type == DEVICE_SIMULATOR) {
wmbus->simulate();
for (auto w : not_working)
{
auto i = devices_.begin();
while (i != devices_.end())
{
if (w == (*i).get())
{
// The erased unique_ptr will delete the WMBus object.
devices_.erase(i);
break;
}
i++;
}
}
if (config->daemon) {
if (devices_.size() == 0)
{
if (!printed_warning_)
{
info("(main) no wmbus devices detected.\n");
printed_warning_ = true;
}
}
else
{
printed_warning_ = false;
}
UNLOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
trace("(trace main) checking for new wmbus devices...\n");
vector<string> ds = manager->listSerialDevices();
for (string& device : ds)
{
trace("(trace main) serial device %s\n", device.c_str());
SerialDevice *sd = manager->lookup(device);
if (sd == NULL)
{
debug("(main) device %s not currently used, detect contents...\n", device.c_str());
// This serial device is not in use.
Detected detected = detectImstAmberCul(device, "", manager);
if (detected.type != DEVICE_UNKNOWN)
{
info("(main) detected %s on %s\n", toString(detected.type), device.c_str());
LOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
unique_ptr<WMBus> w = createWMBusDeviceFrom(&detected, config, manager);
devices->push_back(std::move(w));
WMBus *wmbus = devices->back().get();
UNLOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
wmbus->setLinkModes(config->listen_to_link_modes);
}
}
}
}
unique_ptr<Printer> createPrinter(Configuration *config)
{
return unique_ptr<Printer>(new Printer(config->json, config->fields,
config->separator, config->meterfiles, config->meterfiles_dir,
config->use_logfile, config->logfile,
config->telegram_shells,
config->meterfiles_action == MeterFileType::Overwrite,
config->meterfiles_naming,
config->meterfiles_timestamp));
}
void logStartInformation(Configuration *config)
{
verbose("(wmbusmeters) version: " VERSION "\n");
if (config->exitafter != 0) {
verbose("(config) wmbusmeters will exit after %d seconds\n", config->exitafter);
}
if (config->reopenafter != 0) {
verbose("(config) wmbusmeters close/open the wmbus dongle fd after every %d seconds\n", config->reopenafter);
}
if (config->meterfiles) {
verbose("(config) store meter files in: \"%s\"\n", config->meterfiles_dir.c_str());
}
for (auto &device : config->wmbus_devices)
{
verbose("(config) using device: %s %s\n", device.file.c_str(), device.suffix.c_str());
}
verbose("(config) number of meters: %d\n", config->meters.size());
}
bool start(Configuration *config)
{
// Configure where the logging information should end up.
setupLogFile(config);
// Configure settings.
warningSilenced(config->silence);
verboseEnabled(config->verbose);
logTelegramsEnabled(config->logtelegrams);
debugEnabled(config->debug);
internalTestingEnabled(config->internaltesting);
traceEnabled(config->trace);
stderrEnabled(config->use_stderr);
setAlarmShells(config->alarm_shells);
logStartInformation(config);
// Create the manager monitoring all filedescriptors and invoking callbacks.
manager_ = createSerialCommunicationManager(config->exitafter, config->reopenafter);
// If our software unexpectedly exits, then stop the manager, to try
// to achive a nice shutdown.
onExit(call(manager_.get(),stop));
// Create the printer object that knows how to translate
// telegrams into json, fields that are written into log files
// or sent to shell invocations.
printer_ = createPrinter(config);
// Create the Meter objects from the configuration.
setupMeters(config, &meters_);
// Attach a received-telegram-callback from the meter and
// attach it to the printer.
attachMetersToPrinter(config, &meters_, printer_.get());
manager_->startEventLoop();
// Detect and initialize any devices.
// Future changes are triggered through this callback.
printed_warning_ = true;
detectAndConfigureWMBusDevices(config, manager_.get(), &devices_);
if (devices_.size() == 0)
{
info("(main) no wmbus devices detected.\n");
}
// Every 2 seconds, perform the exact same call again and again.
manager_->startRegularCallback("device_detector",
2,
[&](){
detectAndConfigureWMBusDevices(config, manager_.get(), &devices_);
});
//wmbus->setMeters(&meters);
//wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
//wmbus->setLinkModes(config->listen_to_link_modes);
//string using_link_modes = wmbus->getLinkModes().hr();
//verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
//if (detected.type == DEVICE_SIMULATOR) {
//wmbus->simulate();
//}
if (config->daemon)
{
notice("(wmbusmeters) waiting for telegrams\n");
}
manager->waitForStop();
if (config->daemon) {
// This thread now sleeps waiting for the serial communication manager to stop.
// The manager has already started one thread that performs select and then callbacks
// to decoding the telegrams, finally invoking the printer.
// The regular callback invoked to detect changes in the wmbus devices and
// the alarm checks, is started in a separate thread.
manager_->waitForStop();
if (config->daemon)
{
notice("(wmbusmeters) shutting down\n");
}
// Destroy any remaining allocated objects.
devices_.clear();
meters_.clear();
printer_.reset();
manager_.reset();
restoreSignalHandlers();
return gotHupped();
}
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> &meters)
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> *meters)
{
if (!config->oneshot) return;
for (auto &m : meters) {
for (auto &m : *meters)
{
if (m->numUpdates() == 0) return;
}
// All meters have received at least one update! Stop!
@ -507,7 +658,7 @@ void startUsingConfigFiles(string root, bool is_daemon, string device_override,
{
unique_ptr<Configuration> config = loadConfiguration(root, device_override, listento_override);
config->daemon = is_daemon;
restart = startUsingCommandline(config.get());
restart = start(config.get());
if (restart)
{
notice("(wmbusmeters) HUP received, restarting and reloading config files.\n");

Wyświetl plik

@ -23,7 +23,7 @@
#include"util.h"
struct MeterAmiplus : public virtual ElectricityMeter, public virtual MeterCommonImplementation {
MeterAmiplus(WMBus *bus, MeterInfo &mi);
MeterAmiplus(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
double currentPowerConsumption(Unit u);
@ -41,8 +41,8 @@ private:
string device_date_time_;
};
MeterAmiplus::MeterAmiplus(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::AMIPLUS, 0)
MeterAmiplus::MeterAmiplus(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::AMIPLUS, 0)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -86,9 +86,9 @@ MeterAmiplus::MeterAmiplus(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<ElectricityMeter> createAmiplus(WMBus *bus, MeterInfo &mi)
unique_ptr<ElectricityMeter> createAmiplus(MeterInfo &mi)
{
return unique_ptr<ElectricityMeter>(new MeterAmiplus(bus, mi));
return unique_ptr<ElectricityMeter>(new MeterAmiplus(mi));
}
double MeterAmiplus::totalEnergyConsumption(Unit u)

Wyświetl plik

@ -25,7 +25,7 @@ using namespace std;
struct MeterApator08 : public virtual WaterMeter, public virtual MeterCommonImplementation
{
MeterApator08(WMBus *bus, MeterInfo &mi);
MeterApator08(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -38,13 +38,13 @@ private:
double total_water_consumption_m3_ {};
};
unique_ptr<WaterMeter> createApator08(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createApator08(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterApator08(bus, mi));
return unique_ptr<WaterMeter>(new MeterApator08(mi));
}
MeterApator08::MeterApator08(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::APATOR08, 0x8614) // Not compliant! Will decode to APT.
MeterApator08::MeterApator08(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::APATOR08, 0x8614) // Not compliant! Will decode to APT.
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -24,7 +24,7 @@
using namespace std;
struct MeterApator162 : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterApator162(WMBus *bus, MeterInfo &mi);
MeterApator162(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -37,13 +37,13 @@ private:
double total_water_consumption_m3_ {};
};
unique_ptr<WaterMeter> createApator162(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createApator162(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterApator162(bus, mi));
return unique_ptr<WaterMeter>(new MeterApator162(mi));
}
MeterApator162::MeterApator162(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::APATOR162, MANUFACTURER_APA)
MeterApator162::MeterApator162(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::APATOR162, MANUFACTURER_APA)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -22,7 +22,7 @@
#include"wmbus_utils.h"
struct MeterCMa12w : public virtual TempHygroMeter, public virtual MeterCommonImplementation {
MeterCMa12w(WMBus *bus, MeterInfo &mi);
MeterCMa12w(MeterInfo &mi);
double currentTemperature(Unit u);
double currentRelativeHumidity();
@ -35,8 +35,8 @@ private:
double average_temperature_1h_c_;
};
MeterCMa12w::MeterCMa12w(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::CMA12W, MANUFACTURER_ELV)
MeterCMa12w::MeterCMa12w(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::CMA12W, MANUFACTURER_ELV)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -57,9 +57,9 @@ MeterCMa12w::MeterCMa12w(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<TempHygroMeter> createCMa12w(WMBus *bus, MeterInfo &mi)
unique_ptr<TempHygroMeter> createCMa12w(MeterInfo &mi)
{
return unique_ptr<TempHygroMeter>(new MeterCMa12w(bus, mi));
return unique_ptr<TempHygroMeter>(new MeterCMa12w(mi));
}
double MeterCMa12w::currentTemperature(Unit u)

Wyświetl plik

@ -24,7 +24,7 @@
struct MeterEBZWMBE : public virtual ElectricityMeter, public virtual MeterCommonImplementation
{
MeterEBZWMBE(WMBus *bus, MeterInfo &mi);
MeterEBZWMBE(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
double currentPowerConsumption(Unit u);
@ -44,8 +44,8 @@ private:
string customer_;
};
MeterEBZWMBE::MeterEBZWMBE(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::EBZWMBE, MANUFACTURER_EBZ)
MeterEBZWMBE::MeterEBZWMBE(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::EBZWMBE, MANUFACTURER_EBZ)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV);
@ -87,9 +87,9 @@ MeterEBZWMBE::MeterEBZWMBE(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<ElectricityMeter> createEBZWMBE(WMBus *bus, MeterInfo &mi)
unique_ptr<ElectricityMeter> createEBZWMBE(MeterInfo &mi)
{
return unique_ptr<ElectricityMeter>(new MeterEBZWMBE(bus, mi));
return unique_ptr<ElectricityMeter>(new MeterEBZWMBE(mi));
}
double MeterEBZWMBE::totalEnergyConsumption(Unit u)

Wyświetl plik

@ -24,7 +24,7 @@
struct MeterEHZP : public virtual ElectricityMeter, public virtual MeterCommonImplementation
{
MeterEHZP(WMBus *bus, MeterInfo &mi);
MeterEHZP(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
double currentPowerConsumption(Unit u);
@ -42,8 +42,8 @@ private:
double on_time_h_ {};
};
MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::EHZP, MANUFACTURER_EMH)
MeterEHZP::MeterEHZP(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::EHZP, MANUFACTURER_EMH)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV);
@ -75,9 +75,9 @@ MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<ElectricityMeter> createEHZP(WMBus *bus, MeterInfo &mi)
unique_ptr<ElectricityMeter> createEHZP(MeterInfo &mi)
{
return unique_ptr<ElectricityMeter>(new MeterEHZP(bus, mi));
return unique_ptr<ElectricityMeter>(new MeterEHZP(mi));
}
double MeterEHZP::totalEnergyConsumption(Unit u)

Wyświetl plik

@ -26,7 +26,7 @@
struct MeterESYSWM : public virtual ElectricityMeter, public virtual MeterCommonImplementation
{
MeterESYSWM(WMBus *bus, MeterInfo &mi);
MeterESYSWM(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
double totalEnergyConsumptionTariff1(Unit u);
@ -61,8 +61,8 @@ private:
string fabrication_no_;
};
MeterESYSWM::MeterESYSWM(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::ESYSWM, MANUFACTURER_ESY)
MeterESYSWM::MeterESYSWM(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::ESYSWM, MANUFACTURER_ESY)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV);
@ -134,9 +134,9 @@ MeterESYSWM::MeterESYSWM(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<ElectricityMeter> createESYSWM(WMBus *bus, MeterInfo &mi)
unique_ptr<ElectricityMeter> createESYSWM(MeterInfo &mi)
{
return unique_ptr<ElectricityMeter>(new MeterESYSWM(bus, mi));
return unique_ptr<ElectricityMeter>(new MeterESYSWM(mi));
}
double MeterESYSWM::totalEnergyConsumption(Unit u)

Wyświetl plik

@ -22,7 +22,7 @@
#include"wmbus_utils.h"
struct MeterEurisII : public virtual HeatCostMeter, public virtual MeterCommonImplementation {
MeterEurisII(WMBus *bus, MeterInfo &mi);
MeterEurisII(MeterInfo &mi);
double currentConsumption(Unit u);
string setDate();
@ -41,8 +41,8 @@ private:
uint16_t error_flags_;
};
MeterEurisII::MeterEurisII(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::EURISII, MANUFACTURER_INE)
MeterEurisII::MeterEurisII(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::EURISII, MANUFACTURER_INE)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -84,9 +84,9 @@ MeterEurisII::MeterEurisII(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<HeatCostMeter> createEurisII(WMBus *bus, MeterInfo &mi)
unique_ptr<HeatCostMeter> createEurisII(MeterInfo &mi)
{
return unique_ptr<HeatCostMeter>(new MeterEurisII(bus, mi));
return unique_ptr<HeatCostMeter>(new MeterEurisII(mi));
}
double MeterEurisII::currentConsumption(Unit u)

Wyświetl plik

@ -26,7 +26,7 @@
struct MeterFHKVDataIII : public virtual HeatCostMeter, public virtual MeterCommonImplementation
{
MeterFHKVDataIII(WMBus *bus, MeterInfo &mi);
MeterFHKVDataIII(MeterInfo &mi);
double currentPeriodEnergyConsumption(Unit u);
string currentPeriodDate();
@ -49,14 +49,14 @@ struct MeterFHKVDataIII : public virtual HeatCostMeter, public virtual MeterComm
double temp_radiator_ {};
};
unique_ptr<HeatCostMeter> createFHKVDataIII(WMBus *bus, MeterInfo &mi)
unique_ptr<HeatCostMeter> createFHKVDataIII(MeterInfo &mi)
{
return unique_ptr<HeatCostMeter>(new MeterFHKVDataIII(bus, mi));
return unique_ptr<HeatCostMeter>(new MeterFHKVDataIII(mi));
}
MeterFHKVDataIII::MeterFHKVDataIII(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::FHKVDATAIII, MANUFACTURER_TCH)
MeterFHKVDataIII::MeterFHKVDataIII(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::FHKVDATAIII, MANUFACTURER_TCH)
{
addMedia(0x80); // T telegrams
addExpectedVersion(0x69);

Wyświetl plik

@ -25,7 +25,7 @@
using namespace std;
struct MeterHydrodigit : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterHydrodigit(WMBus *bus, MeterInfo &mi);
MeterHydrodigit(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -38,13 +38,13 @@ private:
string meter_datetime_;
};
unique_ptr<WaterMeter> createHydrodigit(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createHydrodigit(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterHydrodigit(bus, mi));
return unique_ptr<WaterMeter>(new MeterHydrodigit(mi));
}
MeterHydrodigit::MeterHydrodigit(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::HYDRODIGIT, MANUFACTURER_BMT)
MeterHydrodigit::MeterHydrodigit(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::HYDRODIGIT, MANUFACTURER_BMT)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -24,7 +24,7 @@
using namespace std;
struct MeterHydrus : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterHydrus(WMBus *bus, MeterInfo &mi);
MeterHydrus(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -44,8 +44,8 @@ private:
double flow_temperature_c_ { 127 };
};
MeterHydrus::MeterHydrus(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::HYDRUS, MANUFACTURER_DME)
MeterHydrus::MeterHydrus(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::HYDRUS, MANUFACTURER_DME)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -81,9 +81,9 @@ MeterHydrus::MeterHydrus(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<WaterMeter> createHydrus(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createHydrus(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterHydrus(bus, mi));
return unique_ptr<WaterMeter>(new MeterHydrus(mi));
}
void MeterHydrus::processContent(Telegram *t)

Wyświetl plik

@ -25,7 +25,7 @@
using namespace std;
struct MeterIperl : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterIperl(WMBus *bus, MeterInfo &mi);
MeterIperl(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -40,8 +40,8 @@ private:
double max_flow_m3h_ {};
};
MeterIperl::MeterIperl(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::IPERL, MANUFACTURER_SEN)
MeterIperl::MeterIperl(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::IPERL, MANUFACTURER_SEN)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -64,9 +64,9 @@ MeterIperl::MeterIperl(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<WaterMeter> createIperl(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createIperl(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterIperl(bus, mi));
return unique_ptr<WaterMeter>(new MeterIperl(mi));
}
void MeterIperl::processContent(Telegram *t)

Wyświetl plik

@ -45,7 +45,7 @@ typedef struct _izar_alarms {
} izar_alarms;
struct MeterIzar : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterIzar(WMBus *bus, MeterInfo &mi);
MeterIzar(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -75,13 +75,13 @@ private:
vector<uint32_t> keys;
};
unique_ptr<WaterMeter> createIzar(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createIzar(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterIzar(bus, mi));
return unique_ptr<WaterMeter>(new MeterIzar(mi));
}
MeterIzar::MeterIzar(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::IZAR, MANUFACTURER_SAP)
MeterIzar::MeterIzar(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::IZAR, MANUFACTURER_SAP)
{
addManufacturer(MANUFACTURER_DME);

Wyświetl plik

@ -25,7 +25,7 @@
#define INFO_CODE_OPEN 0x0055
struct MeterLansenDW : public virtual DoorWindowDetector, public virtual MeterCommonImplementation {
MeterLansenDW(WMBus *bus, MeterInfo &mi);
MeterLansenDW(MeterInfo &mi);
string status();
bool open();
@ -40,8 +40,8 @@ private:
};
MeterLansenDW::MeterLansenDW(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::LANSENSM, MANUFACTURER_LAS)
MeterLansenDW::MeterLansenDW(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::LANSENSM, MANUFACTURER_LAS)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -57,9 +57,9 @@ MeterLansenDW::MeterLansenDW(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<DoorWindowDetector> createLansenDW(WMBus *bus, MeterInfo &mi)
unique_ptr<DoorWindowDetector> createLansenDW(MeterInfo &mi)
{
return unique_ptr<DoorWindowDetector>(new MeterLansenDW(bus, mi));
return unique_ptr<DoorWindowDetector>(new MeterLansenDW(mi));
}
bool MeterLansenDW::open()

Wyświetl plik

@ -22,7 +22,7 @@
#include"wmbus_utils.h"
struct MeterLansenPU : public virtual PulseCounter, public virtual MeterCommonImplementation {
MeterLansenPU(WMBus *bus, MeterInfo &mi);
MeterLansenPU(MeterInfo &mi);
double counterA();
double counterB();
@ -38,8 +38,8 @@ private:
};
MeterLansenPU::MeterLansenPU(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::LANSENPU, MANUFACTURER_LAS)
MeterLansenPU::MeterLansenPU(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::LANSENPU, MANUFACTURER_LAS)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -60,9 +60,9 @@ MeterLansenPU::MeterLansenPU(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<PulseCounter> createLansenPU(WMBus *bus, MeterInfo &mi)
unique_ptr<PulseCounter> createLansenPU(MeterInfo &mi)
{
return unique_ptr<PulseCounter>(new MeterLansenPU(bus, mi));
return unique_ptr<PulseCounter>(new MeterLansenPU(mi));
}
double MeterLansenPU::counterA()

Wyświetl plik

@ -25,7 +25,7 @@
#define INFO_CODE_TEST 0x0008
struct MeterLansenSM : public virtual SmokeDetector, public virtual MeterCommonImplementation {
MeterLansenSM(WMBus *bus, MeterInfo &mi);
MeterLansenSM(MeterInfo &mi);
string status();
bool smokeDetected();
@ -40,8 +40,8 @@ private:
};
MeterLansenSM::MeterLansenSM(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::LANSENSM, MANUFACTURER_LAS)
MeterLansenSM::MeterLansenSM(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::LANSENSM, MANUFACTURER_LAS)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -57,9 +57,9 @@ MeterLansenSM::MeterLansenSM(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<SmokeDetector> createLansenSM(WMBus *bus, MeterInfo &mi)
unique_ptr<SmokeDetector> createLansenSM(MeterInfo &mi)
{
return unique_ptr<SmokeDetector>(new MeterLansenSM(bus, mi));
return unique_ptr<SmokeDetector>(new MeterLansenSM(mi));
}
bool MeterLansenSM::smokeDetected()

Wyświetl plik

@ -22,7 +22,7 @@
#include"wmbus_utils.h"
struct MeterLansenTH : public virtual TempHygroMeter, public virtual MeterCommonImplementation {
MeterLansenTH(WMBus *bus, MeterInfo &mi);
MeterLansenTH(MeterInfo &mi);
double currentTemperature(Unit u);
double currentRelativeHumidity();
@ -39,8 +39,8 @@ private:
double average_relative_humidity_24h_rh_ {};
};
MeterLansenTH::MeterLansenTH(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::LANSENTH, MANUFACTURER_LAS)
MeterLansenTH::MeterLansenTH(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::LANSENTH, MANUFACTURER_LAS)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -81,9 +81,9 @@ MeterLansenTH::MeterLansenTH(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<TempHygroMeter> createLansenTH(WMBus *bus, MeterInfo &mi)
unique_ptr<TempHygroMeter> createLansenTH(MeterInfo &mi)
{
return unique_ptr<TempHygroMeter>(new MeterLansenTH(bus, mi));
return unique_ptr<TempHygroMeter>(new MeterLansenTH(mi));
}
double MeterLansenTH::currentTemperature(Unit u)

Wyświetl plik

@ -26,7 +26,7 @@ using namespace std;
struct MKRadio3 : public virtual WaterMeter, public virtual MeterCommonImplementation
{
MKRadio3(WMBus *bus, MeterInfo &mi);
MKRadio3(MeterInfo &mi);
double totalWaterConsumption(Unit u);
bool hasTotalWaterConsumption();
@ -40,8 +40,8 @@ private:
double target_water_consumption_m3_ {};
};
MKRadio3::MKRadio3(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::MKRADIO3, MANUFACTURER_TCH)
MKRadio3::MKRadio3(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::MKRADIO3, MANUFACTURER_TCH)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -63,9 +63,9 @@ MKRadio3::MKRadio3(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<WaterMeter> createMKRadio3(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createMKRadio3(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MKRadio3(bus, mi));
return unique_ptr<WaterMeter>(new MKRadio3(mi));
}
void MKRadio3::processContent(Telegram *t)

Wyświetl plik

@ -39,7 +39,7 @@ using namespace std;
#define INFO_CODE_BURST_SHIFT (4+9)
struct MeterMultical21 : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterMultical21(WMBus *bus, MeterInfo &mi, MeterType mt);
MeterMultical21(MeterInfo &mi, MeterType mt);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -91,8 +91,8 @@ private:
int expected_version_ {}; // 0x1b for Multical21 and 0x1d for FlowIQ3100
};
MeterMultical21::MeterMultical21(WMBus *bus, MeterInfo &mi, MeterType mt) :
MeterCommonImplementation(bus, mi, mt, MANUFACTURER_KAM)
MeterMultical21::MeterMultical21(MeterInfo &mi, MeterType mt) :
MeterCommonImplementation(mi, mt, MANUFACTURER_KAM)
{
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
@ -219,22 +219,22 @@ bool MeterMultical21::hasExternalTemperature()
return has_external_temperature_;
}
unique_ptr<WaterMeter> createMulticalWaterMeter(WMBus *bus, MeterInfo &mi, MeterType mt)
unique_ptr<WaterMeter> createMulticalWaterMeter(MeterInfo &mi, MeterType mt)
{
if (mt != MeterType::MULTICAL21 && mt != MeterType::FLOWIQ3100) {
error("Internal error! Not a proper meter type when creating a multical21 style meter.\n");
}
return unique_ptr<WaterMeter>(new MeterMultical21(bus,mi,mt));
return unique_ptr<WaterMeter>(new MeterMultical21(mi,mt));
}
unique_ptr<WaterMeter> createMultical21(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createMultical21(MeterInfo &mi)
{
return createMulticalWaterMeter(bus, mi, MeterType::MULTICAL21);
return createMulticalWaterMeter(mi, MeterType::MULTICAL21);
}
unique_ptr<WaterMeter> createFlowIQ3100(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createFlowIQ3100(MeterInfo &mi)
{
return createMulticalWaterMeter(bus, mi, MeterType::FLOWIQ3100);
return createMulticalWaterMeter(mi, MeterType::FLOWIQ3100);
}
void MeterMultical21::processContent(Telegram *t)

Wyświetl plik

@ -31,7 +31,7 @@
#define INFO_CODE_VOLTAGE_TOO_LOW 128
struct MeterMultical302 : public virtual HeatMeter, public virtual MeterCommonImplementation {
MeterMultical302(WMBus *bus, MeterInfo &mi);
MeterMultical302(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
double targetEnergyConsumption(Unit u);
@ -51,8 +51,8 @@ private:
string target_date_ {};
};
MeterMultical302::MeterMultical302(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::MULTICAL302, MANUFACTURER_KAM)
MeterMultical302::MeterMultical302(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::MULTICAL302, MANUFACTURER_KAM)
{
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
@ -92,8 +92,8 @@ MeterMultical302::MeterMultical302(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<HeatMeter> createMultical302(WMBus *bus, MeterInfo &mi) {
return unique_ptr<HeatMeter>(new MeterMultical302(bus, mi));
unique_ptr<HeatMeter> createMultical302(MeterInfo &mi) {
return unique_ptr<HeatMeter>(new MeterMultical302(mi));
}
double MeterMultical302::totalEnergyConsumption(Unit u)

Wyświetl plik

@ -33,7 +33,7 @@
#define INFO_CODE_TEMP_DIFF_WRONG_POLARITY 128
struct MeterMultical403 : public virtual HeatMeter, public virtual MeterCommonImplementation {
MeterMultical403(WMBus *bus, MeterInfo &mi);
MeterMultical403(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
string status();
@ -60,8 +60,8 @@ private:
string target_date_ {};
};
MeterMultical403::MeterMultical403(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::MULTICAL403, MANUFACTURER_KAM)
MeterMultical403::MeterMultical403(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::MULTICAL403, MANUFACTURER_KAM)
{
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
@ -108,8 +108,8 @@ MeterMultical403::MeterMultical403(WMBus *bus, MeterInfo &mi) :
true, true);
}
unique_ptr<HeatMeter> createMultical403(WMBus *bus, MeterInfo &mi) {
return unique_ptr<HeatMeter>(new MeterMultical403(bus, mi));
unique_ptr<HeatMeter> createMultical403(MeterInfo &mi) {
return unique_ptr<HeatMeter>(new MeterMultical403(mi));
}
double MeterMultical403::totalEnergyConsumption(Unit u)

Wyświetl plik

@ -23,7 +23,7 @@
#include"util.h"
struct MeterOmnipower : public virtual ElectricityMeter, public virtual MeterCommonImplementation {
MeterOmnipower(WMBus *bus, MeterInfo &mi);
MeterOmnipower(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
@ -34,13 +34,13 @@ private:
double total_energy_kwh_ {};
};
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, MeterInfo &mi)
unique_ptr<ElectricityMeter> createOmnipower(MeterInfo &mi)
{
return unique_ptr<ElectricityMeter>(new MeterOmnipower(bus, mi));
return unique_ptr<ElectricityMeter>(new MeterOmnipower(mi));
}
MeterOmnipower::MeterOmnipower(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::OMNIPOWER, MANUFACTURER_KAM)
MeterOmnipower::MeterOmnipower(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::OMNIPOWER, MANUFACTURER_KAM)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -25,7 +25,7 @@
using namespace std;
struct MeterQ400 : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterQ400(WMBus *bus, MeterInfo &mi);
MeterQ400(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -42,13 +42,13 @@ private:
double consumption_at_set_date_m3_ {};
};
unique_ptr<WaterMeter> createQ400(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createQ400(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterQ400(bus, mi));
return unique_ptr<WaterMeter>(new MeterQ400(mi));
}
MeterQ400::MeterQ400(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::Q400, MANUFACTURER_AXI)
MeterQ400::MeterQ400(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::Q400, MANUFACTURER_AXI)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -22,7 +22,7 @@
#include"wmbus_utils.h"
struct MeterQCaloric : public virtual HeatCostMeter, public virtual MeterCommonImplementation {
MeterQCaloric(WMBus *bus, MeterInfo &mi);
MeterQCaloric(MeterInfo &mi);
double currentConsumption(Unit u);
string setDate();
@ -45,8 +45,8 @@ private:
string device_date_time_;
};
MeterQCaloric::MeterQCaloric(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::QCALORIC, MANUFACTURER_QDS)
MeterQCaloric::MeterQCaloric(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::QCALORIC, MANUFACTURER_QDS)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -102,9 +102,9 @@ MeterQCaloric::MeterQCaloric(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, MeterInfo &mi)
unique_ptr<HeatCostMeter> createQCaloric(MeterInfo &mi)
{
return unique_ptr<HeatCostMeter>(new MeterQCaloric(bus, mi));
return unique_ptr<HeatCostMeter>(new MeterQCaloric(mi));
}
double MeterQCaloric::currentConsumption(Unit u)

Wyświetl plik

@ -22,7 +22,7 @@
#include"wmbus_utils.h"
struct MeterRfmAmb : public virtual TempHygroMeter, public virtual MeterCommonImplementation {
MeterRfmAmb(WMBus *bus, MeterInfo &mi);
MeterRfmAmb(MeterInfo &mi);
double currentTemperature(Unit u);
double maximumTemperature(Unit u);
@ -58,8 +58,8 @@ private:
string device_date_time_;
};
MeterRfmAmb::MeterRfmAmb(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::RFMAMB, MANUFACTURER_BMT)
MeterRfmAmb::MeterRfmAmb(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::RFMAMB, MANUFACTURER_BMT)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
@ -145,9 +145,9 @@ MeterRfmAmb::MeterRfmAmb(WMBus *bus, MeterInfo &mi) :
false, true);
}
unique_ptr<TempHygroMeter> createRfmAmb(WMBus *bus, MeterInfo &mi)
unique_ptr<TempHygroMeter> createRfmAmb(MeterInfo &mi)
{
return unique_ptr<TempHygroMeter>(new MeterRfmAmb(bus, mi));
return unique_ptr<TempHygroMeter>(new MeterRfmAmb(mi));
}
double MeterRfmAmb::currentTemperature(Unit u)

Wyświetl plik

@ -25,7 +25,7 @@
using namespace std;
struct MeterRfmTX1 : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterRfmTX1(WMBus *bus, MeterInfo &mi);
MeterRfmTX1(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -38,13 +38,13 @@ private:
string meter_datetime_;
};
unique_ptr<WaterMeter> createRfmTX1(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createRfmTX1(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterRfmTX1(bus, mi));
return unique_ptr<WaterMeter>(new MeterRfmTX1(mi));
}
MeterRfmTX1::MeterRfmTX1(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::RFMTX1, MANUFACTURER_BMT)
MeterRfmTX1::MeterRfmTX1(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::RFMTX1, MANUFACTURER_BMT)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -25,7 +25,7 @@
using namespace std;
struct MeterSupercom587 : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterSupercom587(WMBus *bus, MeterInfo &mi);
MeterSupercom587(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -37,13 +37,13 @@ private:
double total_water_consumption_m3_ {};
};
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createSupercom587(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterSupercom587(bus, mi));
return unique_ptr<WaterMeter>(new MeterSupercom587(mi));
}
MeterSupercom587::MeterSupercom587(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::SUPERCOM587, MANUFACTURER_SON)
MeterSupercom587::MeterSupercom587(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::SUPERCOM587, MANUFACTURER_SON)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -25,7 +25,7 @@
struct MeterVario451 : public virtual HeatMeter, public virtual MeterCommonImplementation
{
MeterVario451(WMBus *bus, MeterInfo &mi);
MeterVario451(MeterInfo &mi);
double totalEnergyConsumption(Unit u);
double currentPeriodEnergyConsumption(Unit u);
@ -40,13 +40,13 @@ struct MeterVario451 : public virtual HeatMeter, public virtual MeterCommonImple
double prev_energy_gj_ {};
};
unique_ptr<HeatMeter> createVario451(WMBus *bus, MeterInfo &mi)
unique_ptr<HeatMeter> createVario451(MeterInfo &mi)
{
return unique_ptr<HeatMeter>(new MeterVario451(bus, mi));
return unique_ptr<HeatMeter>(new MeterVario451(mi));
}
MeterVario451::MeterVario451(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::VARIO451, MANUFACTURER_TCH)
MeterVario451::MeterVario451(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::VARIO451, MANUFACTURER_TCH)
{
addMedia(0x04); // C telegrams
addMedia(0xC3); // T telegrams

Wyświetl plik

@ -25,7 +25,7 @@
using namespace std;
struct MeterWaterstarM : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterWaterstarM(WMBus *bus, MeterInfo &mi);
MeterWaterstarM(MeterInfo &mi);
// Total water counted through the meter
double totalWaterConsumption(Unit u);
@ -44,13 +44,13 @@ private:
string parameter_set_ {};
};
unique_ptr<WaterMeter> createWaterstarM(WMBus *bus, MeterInfo &mi)
unique_ptr<WaterMeter> createWaterstarM(MeterInfo &mi)
{
return unique_ptr<WaterMeter>(new MeterWaterstarM(bus, mi));
return unique_ptr<WaterMeter>(new MeterWaterstarM(mi));
}
MeterWaterstarM::MeterWaterstarM(WMBus *bus, MeterInfo &mi) :
MeterCommonImplementation(bus, mi, MeterType::WATERSTARM, MANUFACTURER_DWZ)
MeterWaterstarM::MeterWaterstarM(MeterInfo &mi) :
MeterCommonImplementation(mi, MeterType::WATERSTARM, MANUFACTURER_DWZ)
{
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);

Wyświetl plik

@ -25,19 +25,20 @@
#include<memory.h>
#include<time.h>
MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, MeterInfo &mi,
MeterType type, int manufacturer) :
type_(type), name_(mi.name), bus_(bus)
MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi,
MeterType type,
int manufacturer) :
type_(type), name_(mi.name)
{
ids_ = splitMatchExpressions(mi.id);
if (mi.key.length() > 0)
{
hex2bin(mi.key, &meter_keys_.confidentiality_key);
}
if (bus->type() == DEVICE_SIMULATOR)
/*if (bus->type() == DEVICE_SIMULATOR)
{
meter_keys_.simulation = true;
}
}*/
if (manufacturer) {
manufacturers_.insert(manufacturer);
}
@ -47,7 +48,7 @@ MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, MeterInfo &mi,
for (auto j : mi.jsons) {
addJson(j);
}
MeterCommonImplementation::bus()->onTelegram([this](vector<uchar>input_frame){return this->handleTelegram(input_frame);});
//MeterCommonImplementation::bus()->onTelegram([this](vector<uchar>input_frame){return this->handleTelegram(input_frame);});
}
void MeterCommonImplementation::addConversions(std::vector<Unit> cs)
@ -139,11 +140,6 @@ string MeterCommonImplementation::name()
return name_;
}
WMBus *MeterCommonImplementation::bus()
{
return bus_;
}
void MeterCommonImplementation::onUpdate(function<void(Telegram*,Meter*)> cb)
{
on_update_.push_back(cb);

Wyświetl plik

@ -101,7 +101,6 @@ struct Meter
virtual string name() = 0;
virtual MeterType type() = 0;
virtual vector<int> media() = 0;
virtual WMBus *bus() = 0;
virtual string datetimeOfUpdateHumanReadable() = 0;
virtual string datetimeOfUpdateRobot() = 0;
@ -222,36 +221,36 @@ struct GenericMeter : public virtual Meter {
string toMeterName(MeterType mt);
MeterType toMeterType(string& type);
LinkModeSet toMeterLinkModeSet(string& type);
unique_ptr<WaterMeter> createMultical21(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createFlowIQ3100(WMBus *bus, MeterInfo &m);
unique_ptr<HeatMeter> createMultical302(WMBus *bus, MeterInfo &m);
unique_ptr<HeatMeter> createMultical403(WMBus *bus, MeterInfo &m);
unique_ptr<HeatMeter> createVario451(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createWaterstarM(WMBus *bus, MeterInfo &m);
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, MeterInfo &m);
unique_ptr<ElectricityMeter> createAmiplus(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createMKRadio3(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createApator08(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createApator162(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createIperl(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createHydrus(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createHydrodigit(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createIzar(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createQ400(WMBus *bus, MeterInfo &m);
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, MeterInfo &m);
unique_ptr<HeatCostMeter> createEurisII(WMBus *bus, MeterInfo &m);
unique_ptr<HeatCostMeter> createFHKVDataIII(WMBus *bus, MeterInfo &m);
unique_ptr<TempHygroMeter> createLansenTH(WMBus *bus, MeterInfo &m);
unique_ptr<SmokeDetector> createLansenSM(WMBus *bus, MeterInfo &m);
unique_ptr<PulseCounter> createLansenPU(WMBus *bus, MeterInfo &m);
unique_ptr<DoorWindowDetector> createLansenDW(WMBus *bus, MeterInfo &m);
unique_ptr<TempHygroMeter> createCMa12w(WMBus *bus, MeterInfo &m);
unique_ptr<TempHygroMeter> createRfmAmb(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createRfmTX1(WMBus *bus, MeterInfo &m);
unique_ptr<ElectricityMeter> createEHZP(WMBus *bus, MeterInfo &m);
unique_ptr<ElectricityMeter> createESYSWM(WMBus *bus, MeterInfo &m);
unique_ptr<ElectricityMeter> createEBZWMBE(WMBus *bus, MeterInfo &m);
GenericMeter *createGeneric(WMBus *bus, MeterInfo &m);
unique_ptr<WaterMeter> createMultical21(MeterInfo &m);
unique_ptr<WaterMeter> createFlowIQ3100(MeterInfo &m);
unique_ptr<HeatMeter> createMultical302(MeterInfo &m);
unique_ptr<HeatMeter> createMultical403(MeterInfo &m);
unique_ptr<HeatMeter> createVario451(MeterInfo &m);
unique_ptr<WaterMeter> createWaterstarM(MeterInfo &m);
unique_ptr<ElectricityMeter> createOmnipower(MeterInfo &m);
unique_ptr<ElectricityMeter> createAmiplus(MeterInfo &m);
unique_ptr<WaterMeter> createSupercom587(MeterInfo &m);
unique_ptr<WaterMeter> createMKRadio3(MeterInfo &m);
unique_ptr<WaterMeter> createApator08(MeterInfo &m);
unique_ptr<WaterMeter> createApator162(MeterInfo &m);
unique_ptr<WaterMeter> createIperl(MeterInfo &m);
unique_ptr<WaterMeter> createHydrus(MeterInfo &m);
unique_ptr<WaterMeter> createHydrodigit(MeterInfo &m);
unique_ptr<WaterMeter> createIzar(MeterInfo &m);
unique_ptr<WaterMeter> createQ400(MeterInfo &m);
unique_ptr<HeatCostMeter> createQCaloric(MeterInfo &m);
unique_ptr<HeatCostMeter> createEurisII(MeterInfo &m);
unique_ptr<HeatCostMeter> createFHKVDataIII(MeterInfo &m);
unique_ptr<TempHygroMeter> createLansenTH(MeterInfo &m);
unique_ptr<SmokeDetector> createLansenSM(MeterInfo &m);
unique_ptr<PulseCounter> createLansenPU(MeterInfo &m);
unique_ptr<DoorWindowDetector> createLansenDW(MeterInfo &m);
unique_ptr<TempHygroMeter> createCMa12w(MeterInfo &m);
unique_ptr<TempHygroMeter> createRfmAmb(MeterInfo &m);
unique_ptr<WaterMeter> createRfmTX1(MeterInfo &m);
unique_ptr<ElectricityMeter> createEHZP(MeterInfo &m);
unique_ptr<ElectricityMeter> createESYSWM(MeterInfo &m);
unique_ptr<ElectricityMeter> createEBZWMBE(MeterInfo &m);
GenericMeter *createGeneric(MeterInfo &m);
#endif

Wyświetl plik

@ -43,7 +43,6 @@ struct MeterCommonImplementation : public virtual Meter
string name();
MeterType type();
vector<int> media();
WMBus *bus();
ELLSecurityMode expectedELLSecurityMode();
TPLSecurityMode expectedTPLSecurityMode();
@ -61,8 +60,7 @@ struct MeterCommonImplementation : public virtual Meter
double getRecordAsDouble(std::string record);
uint16_t getRecordAsUInt16(std::string record);
MeterCommonImplementation(WMBus *bus, MeterInfo &mi,
MeterType type, int manufacturer);
MeterCommonImplementation(MeterInfo &mi, MeterType type, int manufacturer);
~MeterCommonImplementation() = default;

Wyświetl plik

@ -1,5 +1,5 @@
/*
Copyright (C) 2017-2019 Fredrik Öhrström
Copyright (C) 2017-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
@ -76,6 +76,7 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
unique_ptr<SerialDevice> createSerialDeviceSimulator();
void listenTo(SerialDevice *sd, function<void()> cb);
void onDisappear(SerialDevice *sd, function<void()> cb);
void stop();
void startEventLoop();
void waitForStop();
@ -87,13 +88,13 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
void closeAll();
time_t reopenAfter() { return reopen_after_seconds_; }
int startRegularCallback(int seconds, function<void()> callback, string name);
int startRegularCallback(string name, int seconds, function<void()> callback);
void stopRegularCallback(int id);
void resetInitiated() { debug("(serial) initiate reset\n"); resetting_ = true; }
void resetCompleted() { debug("(serial) reset completed\n"); resetting_ = false; }
vector<string> listSerialDevices();
SerialDevice *lookup(std::string device);
private:
@ -118,8 +119,9 @@ private:
pthread_mutex_t devices_lock_ = PTHREAD_MUTEX_INITIALIZER;
vector<SerialDeviceImp*> devices_;
vector<Timer> timers_;
pthread_mutex_t timer_lock_ = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t timers_lock_ = PTHREAD_MUTEX_INITIALIZER;
bool calling_timers_ {};
pthread_mutex_t timer_thread_lock_ = PTHREAD_MUTEX_INITIALIZER;
};
SerialCommunicationManagerImp::~SerialCommunicationManagerImp()
@ -129,14 +131,15 @@ SerialCommunicationManagerImp::~SerialCommunicationManagerImp()
// Stop the event loop.
stop();
// Grab the event_loop_lock. This can only be done when the eventLoop has stopped running.
pthread_mutex_lock(&event_loop_lock_);
LOCK("(serial)", "destructor", event_loop_lock_);
// Now we can be sure the eventLoop has stopped and it is safe to
// free this Manager object.
}
struct SerialDeviceImp : public SerialDevice
{
int fd() { return fd_; }
void doNotUseCallbacks() { no_callbacks_ = true; }
bool skippingCallbacks() { return no_callbacks_; }
void fill(vector<uchar> &data) {};
int receive(vector<uchar> *data);
bool working() { return fd_ != -1; }
@ -146,16 +149,19 @@ struct SerialDeviceImp : public SerialDevice
void setIsFile() { is_file_ = true; }
void setIsStdin() { is_stdin_ = true; }
string device() { return ""; }
int fd() { return fd_; }
protected:
pthread_mutex_t read_lock_ = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t write_lock_ = PTHREAD_MUTEX_INITIALIZER;
function<void()> on_data_;
function<void()> on_disappear_;
int fd_ = -1;
bool expecting_ascii_ {}; // If true, print using safeString instead if bin2hex
bool is_file_ = false;
bool is_stdin_ = false;
bool no_callbacks_ = false;
friend struct SerialCommunicationManagerImp;
@ -166,7 +172,7 @@ int SerialDeviceImp::receive(vector<uchar> *data)
{
bool close_me = false;
pthread_mutex_lock(&read_lock_);
LOCK("(serial)", "receive", read_lock_);
data->clear();
int num_read = 0;
@ -216,7 +222,7 @@ int SerialDeviceImp::receive(vector<uchar> *data)
}
}
pthread_mutex_unlock(&read_lock_);
UNLOCK("(serial)", "receive", read_lock_);
if (close_me) close();
@ -302,6 +308,11 @@ void SerialDeviceTTY::close()
::flock(fd_, LOCK_UN);
::close(fd_);
fd_ = -1;
if (on_disappear_)
{
on_disappear_();
on_disappear_ = NULL;
}
manager_->closed(this);
verbose("(serialtty) closed %s\n", device_.c_str());
}
@ -348,7 +359,7 @@ bool SerialDeviceTTY::send(vector<uchar> &data)
{
if (data.size() == 0) return true;
pthread_mutex_lock(&write_lock_);
LOCK("(serial)", "send", write_lock_);
bool rc = true;
int n = data.size();
@ -370,7 +381,7 @@ bool SerialDeviceTTY::send(vector<uchar> &data)
}
end:
pthread_mutex_unlock(&write_lock_);
UNLOCK("(serial)", "send", write_lock_);
return rc;
}
@ -476,7 +487,7 @@ bool SerialDeviceCommand::send(vector<uchar> &data)
{
if (data.size() == 0) return true;
pthread_mutex_lock(&write_lock_);
LOCK("(serial)", "sendcmd", write_lock_);
bool rc = true;
int n = data.size();
@ -498,7 +509,7 @@ bool SerialDeviceCommand::send(vector<uchar> &data)
}
end:
pthread_mutex_unlock(&write_lock_);
UNLOCK("(serial)", "sendcmd", write_lock_);
return rc;
}
@ -629,7 +640,7 @@ SerialCommunicationManagerImp::SerialCommunicationManagerImp(time_t exit_after_s
// Block the event loop until everything is configured.
if (start_event_loop)
{
pthread_mutex_lock(&event_loop_lock_);
LOCK("(serial)", "constructor", event_loop_lock_);
pthread_create(&select_thread_, NULL, startLoop, this);
}
wakeMeUpOnSigChld(select_thread_);
@ -649,7 +660,8 @@ void *SerialCommunicationManagerImp::runTimers(void *a)
auto t = (SerialCommunicationManagerImp*)a;
t->executeTimerCallbacks();
t->calling_timers_ = false;
pthread_mutex_unlock(&t->timer_lock_);
// Now unlock the previously trylocked mutex.
UNLOCK("(serial)", "runTimers", t->timer_thread_lock_);
return NULL;
}
@ -688,6 +700,17 @@ void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function<void()>
si->on_data_ = cb;
}
void SerialCommunicationManagerImp::onDisappear(SerialDevice *sd, function<void()> cb)
{
if (sd == NULL) return;
SerialDeviceImp *si = dynamic_cast<SerialDeviceImp*>(sd);
if (!si)
{
error("Internal error: Invalid serial device passed to onDisappear.\n");
}
si->on_disappear_ = cb;
}
void SerialCommunicationManagerImp::stop()
{
// Notify the main waitForStop thread that we are stopped!
@ -709,20 +732,20 @@ void SerialCommunicationManagerImp::stop()
void SerialCommunicationManagerImp::startEventLoop()
{
// Release the event loop!
pthread_mutex_unlock(&event_loop_lock_);
UNLOCK("(serial)", "startEventLoop", event_loop_lock_);
}
void SerialCommunicationManagerImp::waitForStop()
{
debug("(serial) waiting for stop\n");
expect_devices_to_work_ = true;
//expect_devices_to_work_ = true;
main_thread_ = pthread_self();
while (running_)
{
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "waitForStop", devices_lock_);
size_t s = devices_.size();
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "waitForStop", devices_lock_);
if (s == 0) {
break;
@ -751,19 +774,19 @@ void SerialCommunicationManagerImp::setReopenAfter(int seconds)
void SerialCommunicationManagerImp::opened(SerialDeviceImp *sd)
{
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "opened", devices_lock_);
max_fd_ = max(sd->fd(), max_fd_);
devices_.push_back(sd);
if (signalsInstalled())
{
if (select_thread_) pthread_kill(select_thread_, SIGUSR1);
}
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "opened", devices_lock_);
}
void SerialCommunicationManagerImp::closed(SerialDeviceImp *sd)
{
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "closed", devices_lock_);
auto p = find(devices_.begin(), devices_.end(), sd);
if (p != devices_.end())
{
@ -782,17 +805,23 @@ void SerialCommunicationManagerImp::closed(SerialDeviceImp *sd)
debug("(serial) no devices working emergency exit!\n");
stop();
}
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "opened", devices_lock_);
}
void SerialCommunicationManagerImp::closeAll()
{
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "closeAll", devices_lock_);
vector<SerialDeviceImp*> copy = devices_;
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "closeAll", devices_lock_);
for (SerialDeviceImp *d : copy)
{
if (d->on_disappear_)
{
d->on_disappear_();
d->on_disappear_ = NULL;
}
closed(d);
}
}
@ -800,7 +829,11 @@ void SerialCommunicationManagerImp::closeAll()
void SerialCommunicationManagerImp::executeTimerCallbacks()
{
time_t curr = time(NULL);
for (Timer &t : timers_)
LOCK("(serial)", "executeTimerCallbacks", timers_lock_);
vector<Timer> timers_copy = timers_;
UNLOCK("(serial)", "executeTimerCallbacks", timers_lock_);
for (Timer &t : timers_copy)
{
if (t.isTime(curr))
{
@ -831,69 +864,57 @@ void *SerialCommunicationManagerImp::eventLoop()
{
fd_set readfds;
pthread_mutex_lock(&event_loop_lock_);
LOCK("(serial)", "eventLoop", event_loop_lock_);
while (running_)
{
FD_ZERO(&readfds);
bool all_working = true;
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "opened", devices_lock_);
for (SerialDevice *d : devices_)
{
FD_SET(d->fd(), &readfds);
if (!d->skippingCallbacks())
{
FD_SET(d->fd(), &readfds);
}
if (!d->working()) all_working = false;
}
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "opened", devices_lock_);
if (!all_working && resetting_ == false)
if (!all_working && expect_devices_to_work_ && resetting_ == false)
{
debug("(serial) not all devices working, emergency exit!\n");
stop();
break;
}
int default_timeout = isInternalTestingEnabled() ? CHECKSTATUS_TIMER_INTERNAL_TESTING : CHECKSTATUS_TIMER;
struct timeval timeout { default_timeout, 0 };
// Perform a select call every second.
struct timeval timeout { 1, 0 };
time_t curr = time(NULL);
// Default timeout is once every 10 seconds. See timings.h
// This means that we will poll the status of tty:s and commands
// once every 10 seconds.
// However sometimes the timeout should be shorter.
// We might have an exit coming up...
if (exit_after_seconds_ > 0)
{
time_t diff = curr-start_time_;
if (diff > exit_after_seconds_) {
if (diff > exit_after_seconds_)
{
// Running time limit hit, now stop.
verbose("(serial) exit after %ld seconds\n", diff);
stop();
break;
}
timeout.tv_sec = exit_after_seconds_ - diff;
if (timeout.tv_sec < 0) timeout.tv_sec = 0;
}
// We might have a regular timer callback coming up.
if (timers_.size() > 0 && !calling_timers_)
{
time_t remaining = calculateTimeToNearestTimerCallback(curr);
if (remaining < 0) remaining = 1;
if (timeout.tv_sec > remaining) timeout.tv_sec = remaining;
}
trace("(trace serial) select timeout %d s\n", timeout.tv_sec);
bool num_devices = 0;
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "eventLoop2", devices_lock_);
for (SerialDevice *d : devices_)
{
d->checkIfShouldReopen();
}
num_devices = devices_.size();
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "eventLoop2", devices_lock_);
if (num_devices == 0 && expect_devices_to_work_ && resetting_ == false)
{
@ -912,7 +933,7 @@ void *SerialCommunicationManagerImp::eventLoop()
{
// Something has happened that caused the sleeping select to wake up.
vector<SerialDeviceImp*> to_be_notified;
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "eventLoop3", devices_lock_);
for (SerialDevice *d : devices_)
{
if (FD_ISSET(d->fd(), &readfds))
@ -921,7 +942,7 @@ void *SerialCommunicationManagerImp::eventLoop()
to_be_notified.push_back(si);
}
}
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "eventLoop3", devices_lock_);
for (SerialDeviceImp *si : to_be_notified)
{
@ -933,12 +954,12 @@ void *SerialCommunicationManagerImp::eventLoop()
}
vector<SerialDeviceImp*> non_working;
pthread_mutex_lock(&devices_lock_);
LOCK("(serial)", "eventLoop4", devices_lock_);
for (SerialDeviceImp *d : devices_)
{
if (!d->working()) non_working.push_back(d);
}
pthread_mutex_unlock(&devices_lock_);
UNLOCK("(serial)", "eventLoop4", devices_lock_);
for (SerialDeviceImp *d : non_working)
{
@ -954,7 +975,7 @@ void *SerialCommunicationManagerImp::eventLoop()
if (timer_found)
{
int rc = pthread_mutex_trylock(&timer_lock_);
int rc = pthread_mutex_trylock(&timer_thread_lock_);
// Only start timer thread if it is not running already.
if (rc == 0)
{
@ -969,7 +990,7 @@ void *SerialCommunicationManagerImp::eventLoop()
}
}
if (non_working.size() > 0 && resetting_ == false)
if (non_working.size() > 0 && expect_devices_to_work_ && resetting_ == false)
{
debug("(serial) non working devices found, exiting.\n");
stop();
@ -977,7 +998,7 @@ void *SerialCommunicationManagerImp::eventLoop()
}
}
verbose("(serial) event loop stopped!\n");
pthread_mutex_unlock(&event_loop_lock_);
UNLOCK("(serial)", "eventLoop", event_loop_lock_);
return NULL;
}
@ -1077,26 +1098,42 @@ SerialCommunicationManager::~SerialCommunicationManager()
{
}
int SerialCommunicationManagerImp::startRegularCallback(int seconds, function<void()> callback, string name)
int SerialCommunicationManagerImp::startRegularCallback(string name, int seconds, function<void()> callback)
{
Timer t = { (int)timers_.size(), seconds, time(NULL), callback, name };
LOCK("(serial)", "startRegularCallback", timers_lock_);
timers_.push_back(t);
UNLOCK("(serial)", "startRegularCallback", timers_lock_);
debug("(serial) registered regular callback %d %s every %d seconds\n", t.id, name.c_str(), seconds);
return t.id;
}
void SerialCommunicationManagerImp::stopRegularCallback(int id)
{
debug("(serial) stopping regular callback %d\n", id);
LOCK("(serial)", "stopRegularCallback", timers_lock_);
for (auto i = timers_.begin(); i != timers_.end(); ++i)
{
if ((*i).id == id)
{
timers_.erase(i);
return;
break;
}
}
UNLOCK("(serial)", "startRegularCallback", timers_lock_);
}
SerialDevice *SerialCommunicationManagerImp::lookup(string device)
{
for (auto sd : devices_)
{
if (sd->device() == device) return sd;
}
return NULL;
}
#if defined(__APPLE__)
vector<string> SerialCommunicationManagerImp::listSerialDevices()
{
@ -1201,7 +1238,11 @@ vector<string> SerialCommunicationManagerImp::listSerialDevices()
{
string name = entries[i]->d_name;
if (name == ".." || name == ".") continue;
if (name == ".." || name == ".")
{
free(entries[i]);
continue;
}
string tty = sysdir+name;
check_if_serial(tty, &found_serials, &found_8250s);

Wyświetl plik

@ -1,5 +1,5 @@
/*
Copyright (C) 2017-2019 Fredrik Öhrström
Copyright (C) 2017-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
@ -36,6 +36,7 @@ struct SerialCommunicationManager;
*/
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 void close() = 0;
// Send will return true only if sending on a tty.
@ -46,6 +47,9 @@ struct SerialDevice
virtual bool working() = 0;
// Used when connecting stdin to a tty driver for testing.
virtual bool readonly() = 0;
// Mark this device so that it is ignored by the select/callback event loop.
virtual void doNotUseCallbacks() = 0;
virtual bool skippingCallbacks() = 0;
// Return underlying device as string.
virtual std::string device() = 0;
@ -70,7 +74,10 @@ struct SerialCommunicationManager
// A serial device simulator used for internal testing.
virtual unique_ptr<SerialDevice> createSerialDeviceSimulator() = 0;
// Invoke cb callback when data arrives on the serial device.
virtual void listenTo(SerialDevice *sd, function<void()> cb) = 0;
// Invoke cb callback when the serial device has disappeared!
virtual void onDisappear(SerialDevice *sd, function<void()> cb) = 0;
virtual void stop() = 0;
virtual void startEventLoop() = 0;
virtual void waitForStop() = 0;
@ -78,7 +85,7 @@ struct SerialCommunicationManager
virtual void setReopenAfter(int seconds) = 0;
// Register a new timer that regularly, every seconds, invokes the callback.
// Returns an id for the timer.
virtual int startRegularCallback(int seconds, function<void()> callback, std::string name) = 0;
virtual int startRegularCallback(std::string name, int seconds, function<void()> callback) = 0;
virtual void stopRegularCallback(int id) = 0;
virtual void resetInitiated() = 0;
@ -86,6 +93,8 @@ struct SerialCommunicationManager
// List all real serial devices.
virtual std::vector<std::string> listSerialDevices() = 0;
// Return a serial device for the given device, if it exists! Otherwise NULL.
virtual SerialDevice *lookup(std::string device) = 0;
virtual ~SerialCommunicationManager();
};

Wyświetl plik

@ -35,6 +35,7 @@ int test_linkmodes();
void test_ids();
void test_kdf();
void test_periods();
void test_devices();
int main(int argc, char **argv)
{
@ -50,6 +51,7 @@ int main(int argc, char **argv)
test_ids();
test_kdf();
test_periods();
test_devices();
return 0;
}
@ -491,3 +493,28 @@ void test_periods()
testp(t, "thu(00-00)", false);
testp(t, "thu(01-01)", true);
}
void testd(string arg, string xf, string xs, string xl, bool xok)
{
Device d;
bool ok = isPossibleDevice(arg, &d);
if (ok != xok)
{
printf("ERROR in device parsing \"%s\"\n", arg.c_str());
return;
}
if (ok == false) return;
if (xf != d.file ||
xs != d.suffix ||
xl != d.linkmodes)
{
printf("ERROR in device parsing parts \"%s\"\n", arg.c_str());
}
}
void test_devices()
{
testd("auto", "auto", "", "", true);
testd("/dev/ttyUSB0:9600", "/dev/ttyUSB0", "9600", "", true);
testd("auto:gurka", "", "", "", false);
}

Wyświetl plik

@ -18,10 +18,8 @@
#ifndef TIMINGS_H
#define TIMINGS_H
// Default select timeout, every 10 seconds if no other timer/timeout cuts it short.
#define SELECT_TIMEOUT 10
// When running internal tests on timeouts use 5 seconds instead.
#define SELECT_TIMEOUT_INTERNAL_TESTING 5
// Default select timeout one second.
#define SELECT_TIMEOUT 1
// Default checkStatus callback frequency every 60 seconds, when an alarmtimeout has been set.
#define CHECKSTATUS_TIMER 60

Wyświetl plik

@ -1055,6 +1055,13 @@ string strdatetime(struct tm *datetime)
return string(buf);
}
string strdatetimesec(struct tm *datetime)
{
char buf[256];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", datetime);
return string(buf);
}
AccessCheck checkIfExistsAndSameGroup(string device)
{
struct stat sb;

Wyświetl plik

@ -49,8 +49,11 @@ std::string safeString(std::vector<uchar> &target);
void strprintf(std::string &s, const char* fmt, ...);
// Return for example: 2010-03-21
std::string strdate(struct tm *date);
// Return for example: 2010-03-21 15:22:03
// Return for example: 2010-03-21 15:22
std::string strdatetime(struct tm *date);
// Return for example: 2010-03-21 15:22:03
std::string strdatetimesec(struct tm *date);
void xorit(uchar *srca, uchar *srcb, uchar *dest, int len);
void shiftLeft(uchar *srca, uchar *srcb, int len);
@ -163,4 +166,7 @@ bool startsWith(std::string s, std::vector<uchar> &data);
// Sum the memory used by the heap and stack.
size_t memoryUsage();
#define LOCK(module,func,x) { trace("TRACE " module " " func " locking " #x "\n"); pthread_mutex_lock(&x); trace(module " " func " locked " #x "\n"); }
#define UNLOCK(module,func,x) { trace("TRACE " module " " func " unlocking " #x "\n"); pthread_mutex_unlock(&x); trace(module " " func " unlocked " #x "\n"); }
#endif

Wyświetl plik

@ -512,6 +512,9 @@ Detected detectAuto(string devicefile,
{
assert(devicefile == "auto");
Detected detected;
detected.device = { devicefile, suffix };
if (suffix != "")
{
error("You cannot have a suffix appended to auto.\n");
@ -520,68 +523,71 @@ Detected detectAuto(string devicefile,
AccessCheck ac;
ac = findAndDetect(handler, &devicefile,
[](string d, SerialCommunicationManager* m){ return detectIM871A(d, m);},
[&](string d, SerialCommunicationManager* m){ return detectIM871A(d, &detected, m);},
"im871a",
"/dev/im871a");
if (ac == AccessCheck::AccessOK)
{
return { DEVICE_IM871A, devicefile, 0, false };
return detected;
}
CHECK_SAME_GROUP
ac = findAndDetect(handler, &devicefile,
[](string d, SerialCommunicationManager* m){ return detectAMB8465(d, m);},
[&](string d, SerialCommunicationManager* m){ return detectAMB8465(d, &detected, m);},
"amb8465",
"/dev/amb8465");
if (ac == AccessCheck::AccessOK)
{
return { DEVICE_AMB8465, devicefile, false };
return detected;
}
CHECK_SAME_GROUP
ac = findAndDetect(handler, &devicefile,
[](string d, SerialCommunicationManager* m){ return detectRawTTY(d, 38400, m);},
[&](string d, SerialCommunicationManager* m){ return detectRawTTY(d, 38400, &detected, m);},
"rfmrx2",
"/dev/rfmrx2");
if (ac == AccessCheck::AccessOK)
{
return { DEVICE_RFMRX2, devicefile, false };
return detected;
}
CHECK_SAME_GROUP
ac = findAndDetect(handler, &devicefile,
[](string d, SerialCommunicationManager* m){ return detectCUL(d, m);},
[&](string d, SerialCommunicationManager* m){ return detectCUL(d, &detected, m);},
"cul",
"/dev/ttyUSB0");
if (ac == AccessCheck::AccessOK)
{
return { DEVICE_CUL, "/dev/ttyUSB0" };
return detected;
}
CHECK_SAME_GROUP
ac = findAndDetect(handler, &devicefile,
[](string d, SerialCommunicationManager* m){ return detectRTLSDR(d, m);},
[&](string d, SerialCommunicationManager* m){ return detectRTLSDR(d, &detected, m);},
"rtlsdr",
"/dev/rtlsdr");
if (ac == AccessCheck::AccessOK)
{
return { DEVICE_RTLWMBUS, "rtlwmbus" };
return detected;
}
CHECK_SAME_GROUP
// We could not auto-detect any device.
return { DEVICE_UNKNOWN, "", false };
return { { devicefile, "", ""}, DEVICE_UNKNOWN, 0, false };
}
Detected detectImstAmberCul(string devicefile,
Detected detectImstAmberCul(string file,
string suffix,
SerialCommunicationManager *handler)
{
Detected detected {};
detected.device = { file, suffix };
// 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
@ -591,35 +597,37 @@ Detected detectImstAmberCul(string devicefile,
// Talk amb8465 with it...
// assumes this device is configured for 9600 bps, which seems to be the default.
if (detectAMB8465(devicefile, handler) == AccessCheck::AccessOK)
if (detectAMB8465(file, &detected, handler) == AccessCheck::AccessOK)
{
return { DEVICE_AMB8465, devicefile, false };
return detected;
}
// Talk im871a with it...
// assumes this device is configured for 57600 bps, which seems to be the default.
if (detectIM871A(devicefile, handler) == AccessCheck::AccessOK)
if (detectIM871A(file, &detected, handler) == AccessCheck::AccessOK)
{
return { DEVICE_IM871A, devicefile, false };
return detected;
}
// Talk CUL with it...
// assumes this device is configured for 38400 bps, which seems to be the default.
if (detectCUL(devicefile, handler) == AccessCheck::AccessOK)
if (detectCUL(file, &detected, handler) == AccessCheck::AccessOK)
{
return { DEVICE_CUL, devicefile, false };
return detected;
}
// We could not auto-detect either.
return { DEVICE_UNKNOWN, "", false };
return { { file, suffix }, DEVICE_UNKNOWN, 0, false };
}
/**
The devicefile can be:
auto (to autodetect the device)
/dev/ttyUSB0 (to use this character device)
auto (to autodetect the devices)
/dev/ttyUSB0 (to use this serial device, probe for the exact device.)
/dev/ttyUSB0:9600 (listen to this serial device set to this baudrate N81, no probing.)
/home/me/simulation.txt or /home/me/simulation_foo.txt (to use the wmbusmeters telegram=|....|+32 format)
/home/me/telegram.raw (to read bytes from this file)
stdin (to read bytes from stdin)
/home/me/telegram.raw (to read raw binary wmbus bytes from this file)
stdin (to read raw binary wmbus bytes from stdin)
If a suffix the suffix can be:
im871a
@ -632,69 +640,69 @@ Detected detectImstAmberCul(string devicefile,
simulation: assume the devicefile produces telegram=|....|+xx lines. This can also pace the simulated telegrams in time.
a baud rate like 38400: assume the devicefile is a raw tty character device.
*/
Detected detectWMBusDeviceSetting(string devicefile,
Detected detectWMBusDeviceSetting(string file,
string suffix,
SerialCommunicationManager *handler)
{
debug("(detect) \"%s\" \"%s\"\n", devicefile.c_str(), suffix.c_str());
debug("(detect) \"%s\" \"%s\"\n", file.c_str(), suffix.c_str());
// Look for /dev/im871a /dev/amb8465 /dev/rfmrx2 /dev/rtlsdr
if (devicefile == "auto")
if (file == "auto")
{
debug("(detect) driver: auto\n");
return detectAuto(devicefile, suffix, handler);
return detectAuto(file, suffix, handler);
}
// If the devicefile is rtlwmbus then the suffix can be a frequency
// or the actual command line to use.
// E.g. rtlwmbus rtlwmbux:868.95M rtlwmbus:rtl_sdr | rtl_wmbus
if (devicefile == "rtlwmbus")
if (file == "rtlwmbus")
{
debug("(detect) driver: rtlwmbus\n");
return { DEVICE_RTLWMBUS, "", false };
return { { file, suffix }, DEVICE_RTLWMBUS, 0, false };
}
if (devicefile == "rtl433")
if (file == "rtl433")
{
debug("(detect) driver: rtl433\n");
return { DEVICE_RTL433, "", false };
return { { file, suffix}, DEVICE_RTL433, 0, false };
}
// Is it a file named simulation_xxx.txt ?
if (checkIfSimulationFile(devicefile.c_str()))
if (checkIfSimulationFile(file.c_str()))
{
debug("(detect) driver: simulation file\n");
return { DEVICE_SIMULATOR, devicefile, false };
return { { file, suffix }, DEVICE_SIMULATOR, 0, false };
}
bool is_tty = checkCharacterDeviceExists(devicefile.c_str(), false);
bool is_stdin = devicefile == "stdin";
bool is_file = checkFileExists(devicefile.c_str());
bool is_tty = checkCharacterDeviceExists(file.c_str(), false);
bool is_stdin = file == "stdin";
bool is_file = checkFileExists(file.c_str());
debug("(detect) is_tty=%d is_stdin=%d is_file=%d\n", is_tty, is_stdin, is_file);
if (!is_tty && !is_stdin && !is_file)
{
debug("(detect) not a valid device file %s\n", devicefile.c_str());
debug("(detect) not a valid device file %s\n", file.c_str());
// Oups, not a valid devicefile.
return { DEVICE_UNKNOWN, "", false };
return { { file, suffix }, DEVICE_UNKNOWN, 0, false };
}
bool override_tty = !is_tty;
if (suffix == "amb8465") return { DEVICE_AMB8465, devicefile, 0, override_tty };
if (suffix == "im871a") return { DEVICE_IM871A, devicefile, 0, override_tty };
if (suffix == "rfmrx2") return { DEVICE_RFMRX2, devicefile, 0, override_tty };
if (suffix == "rtlwmbus") return { DEVICE_RTLWMBUS, devicefile, 0, override_tty };
if (suffix == "rtl433") return { DEVICE_RTL433, devicefile, 0, override_tty };
if (suffix == "cul") return { DEVICE_CUL, devicefile, 0, override_tty };
if (suffix == "d1tc") return { DEVICE_D1TC, devicefile, 0, override_tty };
if (suffix == "wmb13u") return { DEVICE_WMB13U, devicefile, 0, override_tty };
if (suffix == "simulation") return { DEVICE_SIMULATOR, devicefile, 0, override_tty };
if (suffix == "amb8465") return { { file, suffix }, DEVICE_AMB8465, 0, override_tty };
if (suffix == "im871a") return { { file, suffix }, DEVICE_IM871A, 0, override_tty };
if (suffix == "rfmrx2") return { { file, suffix }, DEVICE_RFMRX2, 0, override_tty };
if (suffix == "rtlwmbus") return { { file, suffix }, DEVICE_RTLWMBUS, 0, override_tty };
if (suffix == "rtl433") return { { file, suffix}, DEVICE_RTL433, 0, override_tty };
if (suffix == "cul") return { { file, suffix}, DEVICE_CUL, 0, override_tty };
if (suffix == "d1tc") return { { file, suffix}, DEVICE_D1TC, 0, override_tty };
if (suffix == "wmb13u") return { { file, suffix}, DEVICE_WMB13U, 0, override_tty };
if (suffix == "simulation") return { { file, suffix}, DEVICE_SIMULATOR, 0, override_tty };
// If the suffix is a number, then assume that it is a baud rate.
if (isNumber(suffix)) return { DEVICE_RAWTTY, devicefile, atoi(suffix.c_str()), override_tty };
if (isNumber(suffix)) return { { file, suffix} , DEVICE_RAWTTY, atoi(suffix.c_str()), override_tty };
// If the suffix is empty and its not a tty, then read raw telegrams from stdin or the file.
if (suffix == "" && !is_tty) return { DEVICE_RAWTTY, devicefile, 0, true };
if (suffix == "" && !is_tty) return { { file, suffix}, DEVICE_RAWTTY, 0, true };
if (suffix != "")
{
@ -704,7 +712,7 @@ Detected detectWMBusDeviceSetting(string devicefile,
// Ok, we are left with a single /dev/ttyUSB0 lets talk to it
// to figure out what is connected to it. We currently only
// know how to detect Imst, Amber or CUL dongles.
return detectImstAmberCul(devicefile, suffix, handler);
return detectImstAmberCul(file, suffix, handler);
}
/*
@ -3319,10 +3327,16 @@ bool Telegram::findFormatBytesFromKnownMeterSignatures(vector<uchar> *format_byt
return ok;
}
WMBusCommonImplementation::~WMBusCommonImplementation()
{
info("(wmbus) deleted %s\n", toString(type()));
}
WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t,
SerialCommunicationManager *manager,
unique_ptr<SerialDevice> serial)
: manager_(manager),
is_working_(true),
type_(t),
serial_(std::move(serial))
{
@ -3331,7 +3345,7 @@ WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t,
// Invoke the check status once per minute. Unless internal testing, then it is every 2 seconds.
int default_timer = isInternalTestingEnabled() ? CHECKSTATUS_TIMER_INTERNAL_TESTING : CHECKSTATUS_TIMER;
manager_->startRegularCallback(default_timer, call(this,checkStatus), toString(t));
manager_->startRegularCallback(toString(t), default_timer, call(this,checkStatus));
}
WMBusDeviceType WMBusCommonImplementation::type()
@ -3437,6 +3451,20 @@ bool WMBusCommonImplementation::reset()
return true;
}
void WMBusCommonImplementation::disconnectedFromDevice()
{
if (is_working_)
{
info("(wmbus) lost %s closing %s\n", device().c_str(), toString(type()));
is_working_ = false;
}
}
bool WMBusCommonImplementation::isWorking()
{
return is_working_;
}
void WMBusCommonImplementation::checkStatus()
{
if (protocol_error_count_ >= 20)
@ -3673,6 +3701,7 @@ AccessCheck findAndDetect(SerialCommunicationManager *manager,
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!
@ -3682,27 +3711,6 @@ AccessCheck findAndDetect(SerialCommunicationManager *manager,
return AccessCheck::NotSameGroup;
}
for (int n=0; n < 9; ++n)
{
dev = device_root+"_"+to_string(n);
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 we get here, the device /dev/im871a_0 could be locked
// try /dev/im871a_1 etc...
}
if (ac == AccessCheck::NotSameGroup)
{
// Device exists, but you do not belong to its group!
return AccessCheck::NotSameGroup;
}
}
*out_device = "";
// No device found!
return AccessCheck::NotThere;
@ -3935,3 +3943,33 @@ LIST_OF_MBUS_DEVICES
}
return "?";
}
bool isPossibleDevice(string arg, Device *device)
{
size_t colon = arg.find(":");
if (colon == string::npos)
{
device->file = arg;
device->suffix = "";
device->linkmodes = "";
return true;
}
device->file = arg.substr(0, colon);
string rest = arg.substr(colon+1);
colon = rest.find(":");
if (colon == string::npos)
{
device->suffix = rest;
device->linkmodes = "";
return true;
}
device->suffix = rest.substr(0, colon);
device->linkmodes = rest.substr(colon+1);
return true;
}

Wyświetl plik

@ -30,6 +30,56 @@
bool trimCRCsFrameFormatA(std::vector<uchar> &payload);
bool trimCRCsFrameFormatB(std::vector<uchar> &payload);
struct Device
{
// A typical device is:
// /dev/ttyUSB0:im871a:c1,t1
// /dev/ttyUSB1:amb8465
// /rtlwmbus::any
std::string file; // /dev/ttyUSB0, simulation_meter.txt, stdin file.raw
std::string suffix; // rtlwmbus im871a amb8465 38400 rtl433
std::string linkmodes; // c1,t1,s1
};
#define LIST_OF_MBUS_DEVICES \
X(DEVICE_UNKNOWN) \
X(DEVICE_CUL)\
X(DEVICE_D1TC)\
X(DEVICE_IM871A)\
X(DEVICE_AMB8465)\
X(DEVICE_RFMRX2)\
X(DEVICE_SIMULATOR)\
X(DEVICE_RTLWMBUS)\
X(DEVICE_RTL433)\
X(DEVICE_RAWTTY)\
X(DEVICE_WMB13U)
enum WMBusDeviceType {
#define X(name) name,
LIST_OF_MBUS_DEVICES
#undef X
};
const char *toString(WMBusDeviceType t);
struct Detected
{
Device device; // Device information.
WMBusDeviceType type; // IM871A, AMB8465 etc.
int baudrate; // Baudrate to tty.
// If the override_tty is true, then do not allow the wmbus driver to open the device->file as a tty,
// instead open the device->file as a file instead . This is to allows feeding the wmbus drivers
// using stdin or a file. This is primarily used for internal testing.
bool override_tty;
void set(WMBusDeviceType t, int br, bool ot)
{
type = t;
baudrate = br;
override_tty = ot;
}
};
#define LIST_OF_LINK_MODES \
X(Any,any,--anylinkmode,0xffff) \
X(C1,c1,--c1,0x1) \
@ -390,27 +440,6 @@ private:
struct Meter;
#define LIST_OF_MBUS_DEVICES \
X(DEVICE_UNKNOWN) \
X(DEVICE_CUL)\
X(DEVICE_D1TC)\
X(DEVICE_IM871A)\
X(DEVICE_AMB8465)\
X(DEVICE_RFMRX2)\
X(DEVICE_SIMULATOR)\
X(DEVICE_RTLWMBUS)\
X(DEVICE_RTL433)\
X(DEVICE_RAWTTY)\
X(DEVICE_WMB13U)
enum WMBusDeviceType {
#define X(name) name,
LIST_OF_MBUS_DEVICES
#undef X
};
const char *toString(WMBusDeviceType t);
struct WMBus
{
virtual WMBusDeviceType type() = 0;
@ -426,7 +455,9 @@ struct WMBus
virtual void onTelegram(function<bool(vector<uchar>)> cb) = 0;
virtual SerialDevice *serial() = 0;
virtual void simulate() = 0;
// This will check if the wmbus devices needs reset.
// Return true if underlying device is ok and device in general seems to be working.
virtual bool isWorking() = 0;
// This will check if the wmbus devices needs a reset and then immediately perform the reset.
virtual void checkStatus() = 0;
// Close any underlying ttys or software and restart/reinitialize.
// Return true if ok.
@ -438,21 +469,12 @@ struct WMBus
virtual ~WMBus() = 0;
};
struct Detected
{
WMBusDeviceType type; // IM871A, AMB8465 etc
string devicefile; // /dev/ttyUSB0 /dev/ttyACM0 stdin simulation_abc.txt telegrams.raw
int baudrate; // If the suffix is a number, store the number here.
// If the override_tty is true, then do not allow the wmbus driver to open the tty,
// instead open the devicefile first. This is to allow feeding the wmbus drivers using stdin
// or a file or for internal testing.
bool override_tty;
};
Detected detectWMBusDeviceSetting(string devicefile, string suffix,
SerialCommunicationManager *manager);
bool isPossibleDevice(string arg, Device *device);
unique_ptr<WMBus> openIM871A(string device, SerialCommunicationManager *manager,
unique_ptr<SerialDevice> serial_override);
unique_ptr<WMBus> openAMB8465(string device, SerialCommunicationManager *manager,
@ -518,15 +540,19 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
int *payload_len_out,
int *payload_offset);
AccessCheck detectIM871A(string device, SerialCommunicationManager *handler);
AccessCheck detectAMB8465(string device, SerialCommunicationManager *handler);
AccessCheck detectRawTTY(string device, int baud, SerialCommunicationManager *handler);
AccessCheck detectRTLSDR(string device, SerialCommunicationManager *handler);
AccessCheck detectCUL(string device, SerialCommunicationManager *handler);
AccessCheck detectWMB13U(string device, SerialCommunicationManager *handler);
AccessCheck detectIM871A(string file, Detected *detected, SerialCommunicationManager *handler);
AccessCheck detectAMB8465(string file, Detected *detected, SerialCommunicationManager *handler);
AccessCheck detectRawTTY(string file, int baud, Detected *detected, SerialCommunicationManager *handler);
AccessCheck detectRTLSDR(string file, Detected *detected, SerialCommunicationManager *handler);
AccessCheck detectCUL(string file, Detected *detected, SerialCommunicationManager *handler);
AccessCheck detectWMB13U(string file, Detected *detected, SerialCommunicationManager *handler);
// Try to factory reset an AMB8465 by trying all possible serial speeds and
// restore to factory settings.
AccessCheck factoryResetAMB8465(string device, SerialCommunicationManager *handler, int *was_baud);
Detected detectImstAmberCul(string file,
string suffix,
SerialCommunicationManager *handler);
#endif

Wyświetl plik

@ -109,6 +109,7 @@ WMBusAmber::WMBusAmber(unique_ptr<SerialDevice> serial, SerialCommunicationManag
{
sem_init(&command_wait_, 0, 0);
manager_->listenTo(this->serial(),call(this,processSerialData));
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
rssi_expected_ = true;
reset();
}
@ -131,9 +132,9 @@ bool WMBusAmber::ping()
{
if (serial()->readonly()) return true; // Feeding from stdin or file.
pthread_mutex_lock(&command_lock_);
LOCK("(amb8465)", "ping", command_lock_);
// Ping it...
pthread_mutex_unlock(&command_lock_);
UNLOCK("(amb8465)", "ping", command_lock_);
return true;
}
@ -142,7 +143,7 @@ uint32_t WMBusAmber::getDeviceId()
{
if (serial()->readonly()) { return 0; } // Feeding from stdin or file.
pthread_mutex_lock(&command_lock_);
LOCK("(amb8465)", "getDeviceId", command_lock_);
vector<uchar> msg(4);
msg[0] = AMBER_SERIAL_SOF;
@ -172,7 +173,7 @@ uint32_t WMBusAmber::getDeviceId()
}
}
pthread_mutex_unlock(&command_lock_);
UNLOCK("(amb8465)", "getDeviceId", command_lock_);
return id;
}
@ -190,7 +191,7 @@ void WMBusAmber::getConfiguration()
{
if (serial()->readonly()) { return; } // Feeding from stdin or file.
pthread_mutex_lock(&command_lock_);
LOCK("(amb8465)", "getConfiguration", command_lock_);
vector<uchar> msg(6);
msg[0] = AMBER_SERIAL_SOF;
@ -207,7 +208,7 @@ void WMBusAmber::getConfiguration()
if (!sent)
{
pthread_mutex_unlock(&command_lock_);
UNLOCK("(amb8465)", "getConfiguration", command_lock_);
return;
}
@ -233,7 +234,7 @@ void WMBusAmber::getConfiguration()
verbose("(amb8465) config: mode Preselect %02x\n", received_payload_[70+2]);
}
pthread_mutex_unlock(&command_lock_);
UNLOCK("(amb8465)", "getConfiguration", command_lock_);
}
void WMBusAmber::deviceSetLinkModes(LinkModeSet lms)
@ -246,7 +247,7 @@ void WMBusAmber::deviceSetLinkModes(LinkModeSet lms)
error("(amb8465) setting link mode(s) %s is not supported for amb8465\n", modes.c_str());
}
pthread_mutex_lock(&command_lock_);
LOCK("(amb8465)", "deviceSetLinkModes", command_lock_);
vector<uchar> msg(8);
msg[0] = AMBER_SERIAL_SOF;
@ -281,7 +282,7 @@ void WMBusAmber::deviceSetLinkModes(LinkModeSet lms)
if (sent) waitForResponse();
link_modes_ = lms;
pthread_mutex_unlock(&command_lock_);
UNLOCK("(amb8465)", "deviceSetLinkModes", command_lock_);
}
void WMBusAmber::waitForResponse()
@ -518,10 +519,11 @@ void WMBusAmber::handleMessage(int msgid, vector<uchar> &frame)
}
}
AccessCheck detectAMB8465(string device, SerialCommunicationManager *manager)
AccessCheck detectAMB8465(string device, Detected *detected, SerialCommunicationManager *manager)
{
// Talk to the device and expect a very specific answer.
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
serial->doNotUseCallbacks();
AccessCheck rc = serial->open(false);
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
@ -565,6 +567,9 @@ AccessCheck detectAMB8465(string device, SerialCommunicationManager *manager)
data[7] != xorChecksum(data, 7)) {
return AccessCheck::NotThere;
}
detected->set(WMBusDeviceType::DEVICE_AMB8465, 9600, false);
return AccessCheck::AccessOK;
}

Wyświetl plik

@ -100,6 +100,7 @@ WMBusCUL::WMBusCUL(unique_ptr<SerialDevice> serial, SerialCommunicationManager *
{
sem_init(&command_wait_, 0, 0);
manager_->listenTo(this->serial(),call(this,processSerialData));
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
reset();
}
@ -355,10 +356,11 @@ FrameStatus WMBusCUL::checkCULFrame(vector<uchar> &data,
}
}
AccessCheck detectCUL(string device, SerialCommunicationManager *manager)
AccessCheck detectCUL(string device, Detected *detected, SerialCommunicationManager *manager)
{
// Talk to the device and expect a very specific answer.
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400);
serial->doNotUseCallbacks();
AccessCheck rc = serial->open(false);
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
@ -399,5 +401,8 @@ AccessCheck detectCUL(string device, SerialCommunicationManager *manager)
// TODO: check version string somehow
serial->close();
detected->set(WMBusDeviceType::DEVICE_CUL, 38400, false);
return AccessCheck::AccessOK;
}

Wyświetl plik

@ -76,7 +76,7 @@ private:
static FrameStatus checkIM871AFrame(vector<uchar> &data,
size_t *frame_length, int *endpoint_out, int *msgid_out,
int *payload_len_out, int *payload_offset);
friend AccessCheck detectIM871A(string device, SerialCommunicationManager *manager);
friend AccessCheck detectIM871A(string device, Detected *detected, SerialCommunicationManager *manager);
void handleDevMgmt(int msgid, vector<uchar> &payload);
void handleRadioLink(int msgid, vector<uchar> &payload);
void handleRadioLinkTest(int msgid, vector<uchar> &payload);
@ -101,6 +101,7 @@ WMBusIM871A::WMBusIM871A(unique_ptr<SerialDevice> serial, SerialCommunicationMan
{
sem_init(&command_wait_, 0, 0);
manager_->listenTo(this->serial(),call(this,processSerialData));
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
reset();
}
@ -108,7 +109,7 @@ bool WMBusIM871A::ping()
{
if (serial()->readonly()) return true; // Feeding from stdin or file.
pthread_mutex_lock(&command_lock_);
LOCK("(im871)", "ping", command_lock_);
vector<uchar> msg(4);
msg[0] = IM871A_SERIAL_SOF;
@ -122,7 +123,7 @@ bool WMBusIM871A::ping()
if (sent) waitForResponse();
pthread_mutex_unlock(&command_lock_);
UNLOCK("(im871)", "ping", command_lock_);
return true;
}
@ -130,7 +131,7 @@ uint32_t WMBusIM871A::getDeviceId()
{
if (serial()->readonly()) return 0; // Feeding from stdin or file.
pthread_mutex_lock(&command_lock_);
LOCK("(im871)", "getDeviceId", command_lock_);
vector<uchar> msg(4);
msg[0] = IM871A_SERIAL_SOF;
@ -165,7 +166,7 @@ uint32_t WMBusIM871A::getDeviceId()
id = 0;
}
pthread_mutex_unlock(&command_lock_);
UNLOCK("(im871)", "getDeviceId", command_lock_);
return id;
}
@ -173,7 +174,7 @@ LinkModeSet WMBusIM871A::getLinkModes()
{
if (serial()->readonly()) { return Any_bit; } // Feeding from stdin or file.
pthread_mutex_lock(&command_lock_);
LOCK("(im871)", "getLinkModes", command_lock_);
vector<uchar> msg(4);
msg[0] = IM871A_SERIAL_SOF;
@ -188,7 +189,7 @@ LinkModeSet WMBusIM871A::getLinkModes()
{
// If we are using a serial override that will not respond,
// then just return a value.
pthread_mutex_unlock(&command_lock_);
UNLOCK("(im871)", "getLinkModes", command_lock_);
// Use the remembered link modes set before.
return protectedGetLinkModes();
}
@ -320,7 +321,8 @@ LinkModeSet WMBusIM871A::getLinkModes()
}
}
pthread_mutex_unlock(&command_lock_);
UNLOCK("(im871)", "getLinkModes", command_lock_);
LinkModeSet lms;
lms.addLinkMode(lm);
return lms;
@ -344,7 +346,7 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
error("(im871a) setting link mode(s) %s is not supported for im871a\n", modes.c_str());
}
pthread_mutex_lock(&command_lock_);
LOCK("(im871)", "deviceSetLinkModes", command_lock_);
vector<uchar> msg(10);
msg[0] = IM871A_SERIAL_SOF;
@ -386,14 +388,16 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
if (sent) waitForResponse();
pthread_mutex_unlock(&command_lock_);
UNLOCK("(im871)", "deviceSetLinkModes", command_lock_);
}
void WMBusIM871A::waitForResponse()
{
while (manager_->isRunning())
{
trace("(im871) waitForResponse sem_wait command_wait_\n");
int rc = sem_wait(&command_wait_);
trace("(im871) waitForResponse waited command_wait_\n");
if (rc==0) break;
if (rc==-1) {
if (errno==EINTR) continue;
@ -649,10 +653,11 @@ void WMBusIM871A::handleHWTest(int msgid, vector<uchar> &payload)
}
}
AccessCheck detectIM871A(string device, SerialCommunicationManager *manager)
AccessCheck detectIM871A(string file, Detected *detected, SerialCommunicationManager *manager)
{
// Talk to the device and expect a very specific answer.
auto serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
auto serial = manager->createSerialDeviceTTY(file.c_str(), 57600);
serial->doNotUseCallbacks();
AccessCheck rc = serial->open(false);
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
@ -688,5 +693,7 @@ AccessCheck detectIM871A(string device, SerialCommunicationManager *manager)
{
return AccessCheck::NotThere;
}
detected->set(WMBusDeviceType::DEVICE_IM871A, 57600, false);
return AccessCheck::AccessOK;
}

Wyświetl plik

@ -152,7 +152,7 @@ void WMBusRawTTY::processSerialData()
}
}
AccessCheck detectRawTTY(string device, int baud, SerialCommunicationManager *manager)
AccessCheck detectRawTTY(string device, int baud, Detected *detected, SerialCommunicationManager *manager)
{
// 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.
@ -161,5 +161,8 @@ AccessCheck detectRawTTY(string device, int baud, SerialCommunicationManager *ma
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
serial->close();
detected->set(WMBusDeviceType::DEVICE_RAWTTY, baud, false);
return AccessCheck::AccessOK;
}

Wyświetl plik

@ -288,8 +288,15 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector<uchar> &data,
return FullFrame;
}
AccessCheck detectRTLSDR(string device, SerialCommunicationManager *manager)
AccessCheck detectRTLSDR(string device, Detected *detected, SerialCommunicationManager *manager)
{
// No more advanced test than that the /dev/rtlsdr link exists.
return checkIfExistsAndSameGroup(device);
AccessCheck rc = checkIfExistsAndSameGroup(device);
if (rc == AccessCheck::AccessOK)
{
detected->set(WMBusDeviceType::DEVICE_RTLWMBUS,0, false);
}
return rc;
}

Wyświetl plik

@ -29,14 +29,17 @@ string frameTypeKamstrupC1(int ft);
struct WMBusCommonImplementation : public virtual WMBus
{
WMBusCommonImplementation(WMBusDeviceType t, SerialCommunicationManager *manager, unique_ptr<SerialDevice> serial_override);
~WMBusCommonImplementation();
WMBusDeviceType type();
void setMeters(vector<unique_ptr<Meter>> *meters);
void onTelegram(function<bool(vector<uchar>)> cb);
bool handleTelegram(vector<uchar> frame);
void checkStatus();
bool isWorking();
void setTimeout(int seconds, std::string expected_activity);
void setLinkModes(LinkModeSet lms);
void disconnectedFromDevice();
bool reset();
SerialDevice *serial() { if (serial_) return serial_.get(); else return NULL; }
string device() { if (serial_) return serial_->device(); else return "?"; }
@ -55,6 +58,7 @@ struct WMBusCommonImplementation : public virtual WMBus
private:
bool is_working_ {};
vector<function<bool(vector<uchar>)>> telegram_listeners_;
vector<unique_ptr<Meter>> *meters_;
WMBusDeviceType type_ {};

Wyświetl plik

@ -203,7 +203,7 @@ void WMBusWMB13U::processSerialData()
// Receive and accumulated serial data until a full frame has been received.
serial()->receive(&data);
// Unlock the serial lock.
pthread_mutex_unlock(&serial_lock_);
UNLOCK("(wmb13u)", "processSerialData", serial_lock_);
read_buffer_.insert(read_buffer_.end(), data.begin(), data.end());
@ -245,7 +245,7 @@ void WMBusWMB13U::processSerialData()
bool WMBusWMB13U::enterConfigModee()
{
pthread_mutex_lock(&serial_lock_);
LOCK("(wmb13u)", "enterConfigMode", serial_lock_);
vector<uchar> data;
@ -272,7 +272,8 @@ bool WMBusWMB13U::enterConfigModee()
return true;
fail:
pthread_mutex_unlock(&serial_lock_);
UNLOCK("(wmb13u)", "enterConfigMode", serial_lock_);
return false;
}
@ -291,7 +292,7 @@ bool WMBusWMB13U::exitConfigModee()
serial()->receive(&data);
// Always unlock....
pthread_mutex_unlock(&serial_lock_);
UNLOCK("(wmb13u)", "exitConfigMode", serial_lock_);
if (!startsWith("OK", data)) return false;