From 69df7f022a5933525361c7680f3da73b8caa0c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Sun, 30 Aug 2020 21:33:48 +0200 Subject: [PATCH] Detect and start wmbus dongles from within wmbusmeters. --- Makefile | 4 +- install.sh | 123 ++----- src/admin.cc | 459 ++++++------------------- src/cmdline.cc | 31 +- src/config.cc | 12 +- src/config.h | 4 +- src/main.cc | 529 ++++++++++++++++++----------- src/meter_amiplus.cc | 10 +- src/meter_apator08.cc | 10 +- src/meter_apator162.cc | 10 +- src/meter_cma12w.cc | 10 +- src/meter_ebzwmbe.cc | 10 +- src/meter_ehzp.cc | 10 +- src/meter_esyswm.cc | 10 +- src/meter_eurisii.cc | 10 +- src/meter_fhkvdataiii.cc | 10 +- src/meter_hydrodigit.cc | 10 +- src/meter_hydrus.cc | 10 +- src/meter_iperl.cc | 10 +- src/meter_izar.cc | 10 +- src/meter_lansendw.cc | 10 +- src/meter_lansenpu.cc | 10 +- src/meter_lansensm.cc | 10 +- src/meter_lansenth.cc | 10 +- src/meter_mkradio3.cc | 10 +- src/meter_multical21.cc | 18 +- src/meter_multical302.cc | 10 +- src/meter_multical403.cc | 10 +- src/meter_omnipower.cc | 10 +- src/meter_q400.cc | 10 +- src/meter_qcaloric.cc | 10 +- src/meter_rfmamb.cc | 10 +- src/meter_rfmtx1.cc | 10 +- src/meter_supercom587.cc | 10 +- src/meter_vario451.cc | 10 +- src/meter_waterstarm.cc | 10 +- src/meters.cc | 18 +- src/meters.h | 63 ++-- src/meters_common_implementation.h | 4 +- src/serial.cc | 165 +++++---- src/serial.h | 13 +- src/testinternals.cc | 27 ++ src/timings.h | 6 +- src/util.cc | 7 + src/util.h | 8 +- src/wmbus.cc | 182 ++++++---- src/wmbus.h | 106 +++--- src/wmbus_amb8465.cc | 25 +- src/wmbus_cul.cc | 7 +- src/wmbus_im871a.cc | 31 +- src/wmbus_rawtty.cc | 5 +- src/wmbus_rtlwmbus.cc | 11 +- src/wmbus_utils.h | 4 + src/wmbus_wmb13u.cc | 9 +- 54 files changed, 1088 insertions(+), 1063 deletions(-) diff --git a/Makefile b/Makefile index 7ff33c3..a023d34 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/install.sh b/install.sh index 3c65c80..94c8cba 100755 --- a/install.sh +++ b/install.sh @@ -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 < "$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 diff --git a/src/admin.cc b/src/admin.cc index ad74aec..4a607e2 100644 --- a/src/admin.cc +++ b/src/admin.cc @@ -15,24 +15,16 @@ along with this program. If not, see . */ -#include -#include #include #include #include -#include +#include #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 - 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 *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 menu); -void displayInformationAndWait(string title, vector entries, int px=-1, int py=-1); -void displayInformationNoWait(WINDOW **win, string title, vector entries, int px=-1, int py=-1); - -void notImplementedYet(string msg); - -int screen_width, screen_height; unique_ptr 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 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 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 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 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 menu; - int n_choices = countEntries(entries); - - for (int i=0; i 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 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 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 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 devices = handler->listSerialDevices(); vector 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 args; + vector 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 args; @@ -674,3 +377,49 @@ void detectProcesses(string cmd, vector *pids) pch = strtok (NULL, " \n"); } } + +void stopDaemon() +{ + vector 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 args; + //vector 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; +} +*/ diff --git a/src/cmdline.cc b/src/cmdline.cc index 5fcfbaf..2b0da5f 100644 --- a/src/cmdline.cc +++ b/src/cmdline.cc @@ -16,7 +16,6 @@ */ #include"cmdline.h" -#include"config.h" #include"meters.h" #include"util.h" @@ -68,7 +67,8 @@ unique_ptr parseCommandLine(int argc, char **argv) { c->need_help = true; return unique_ptr(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(c); @@ -96,6 +96,12 @@ unique_ptr 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 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) { diff --git a/src/config.cc b/src/config.cc index c2f1744..a07a525 100644 --- a/src/config.cc +++ b/src/config.cc @@ -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); } } diff --git a/src/config.h b/src/config.h index 585e111..f56e545 100644 --- a/src/config.h +++ b/src/config.h @@ -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 wmbus_devices; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus, /dev/ttyUSB1:9600 + std::vector 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; diff --git a/src/main.cc b/src/main.cc index 4880271..2680a5f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -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 - +#include #include #include #include @@ -38,21 +37,49 @@ using namespace std; -void oneshotCheck(Configuration *cmdline, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector> &meters); -bool startUsingCommandline(Configuration *cmdline); +void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector> *meters); +void setupLogFile(Configuration *config); +void setupMeters(Configuration *config, vector> *meters); +void attachMetersToPrinter(Configuration *config, vector> *meters, Printer *printer); +void detectAndConfigureWMBusDevices(Configuration *config, SerialCommunicationManager *manager, vector> *devices); +unique_ptr 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 manager_; + +// Registered meters to decode and relay. +// This does not change during runtime. +vector> meters_; + +// Current active set of wmbus devices that can receive telegrams. +// This can change during runtime, plugging/unplugging wmbus dongles. +vector> 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_; + +// 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 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; unique_ptr 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; - - 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(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> 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 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 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> *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 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> *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> *devices) +{ + trace("(trace main) checking for dead wmbus devices...\n"); + + LOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_); + vector 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 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 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 createPrinter(Configuration *config) +{ + return unique_ptr(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> &meters) +void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector> *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 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"); diff --git a/src/meter_amiplus.cc b/src/meter_amiplus.cc index 5be3daf..823ead4 100644 --- a/src/meter_amiplus.cc +++ b/src/meter_amiplus.cc @@ -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 createAmiplus(WMBus *bus, MeterInfo &mi) +unique_ptr createAmiplus(MeterInfo &mi) { - return unique_ptr(new MeterAmiplus(bus, mi)); + return unique_ptr(new MeterAmiplus(mi)); } double MeterAmiplus::totalEnergyConsumption(Unit u) diff --git a/src/meter_apator08.cc b/src/meter_apator08.cc index 89add3b..a5237c3 100644 --- a/src/meter_apator08.cc +++ b/src/meter_apator08.cc @@ -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 createApator08(WMBus *bus, MeterInfo &mi) +unique_ptr createApator08(MeterInfo &mi) { - return unique_ptr(new MeterApator08(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_apator162.cc b/src/meter_apator162.cc index a65d439..a52537d 100644 --- a/src/meter_apator162.cc +++ b/src/meter_apator162.cc @@ -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 createApator162(WMBus *bus, MeterInfo &mi) +unique_ptr createApator162(MeterInfo &mi) { - return unique_ptr(new MeterApator162(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_cma12w.cc b/src/meter_cma12w.cc index 8963bd9..4b72a93 100644 --- a/src/meter_cma12w.cc +++ b/src/meter_cma12w.cc @@ -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 createCMa12w(WMBus *bus, MeterInfo &mi) +unique_ptr createCMa12w(MeterInfo &mi) { - return unique_ptr(new MeterCMa12w(bus, mi)); + return unique_ptr(new MeterCMa12w(mi)); } double MeterCMa12w::currentTemperature(Unit u) diff --git a/src/meter_ebzwmbe.cc b/src/meter_ebzwmbe.cc index 3ffada5..bd33c58 100644 --- a/src/meter_ebzwmbe.cc +++ b/src/meter_ebzwmbe.cc @@ -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 createEBZWMBE(WMBus *bus, MeterInfo &mi) +unique_ptr createEBZWMBE(MeterInfo &mi) { - return unique_ptr(new MeterEBZWMBE(bus, mi)); + return unique_ptr(new MeterEBZWMBE(mi)); } double MeterEBZWMBE::totalEnergyConsumption(Unit u) diff --git a/src/meter_ehzp.cc b/src/meter_ehzp.cc index f6564eb..b6deefa 100644 --- a/src/meter_ehzp.cc +++ b/src/meter_ehzp.cc @@ -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 createEHZP(WMBus *bus, MeterInfo &mi) +unique_ptr createEHZP(MeterInfo &mi) { - return unique_ptr(new MeterEHZP(bus, mi)); + return unique_ptr(new MeterEHZP(mi)); } double MeterEHZP::totalEnergyConsumption(Unit u) diff --git a/src/meter_esyswm.cc b/src/meter_esyswm.cc index 1e5b102..4c46bac 100644 --- a/src/meter_esyswm.cc +++ b/src/meter_esyswm.cc @@ -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 createESYSWM(WMBus *bus, MeterInfo &mi) +unique_ptr createESYSWM(MeterInfo &mi) { - return unique_ptr(new MeterESYSWM(bus, mi)); + return unique_ptr(new MeterESYSWM(mi)); } double MeterESYSWM::totalEnergyConsumption(Unit u) diff --git a/src/meter_eurisii.cc b/src/meter_eurisii.cc index 51ae030..baa134e 100644 --- a/src/meter_eurisii.cc +++ b/src/meter_eurisii.cc @@ -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 createEurisII(WMBus *bus, MeterInfo &mi) +unique_ptr createEurisII(MeterInfo &mi) { - return unique_ptr(new MeterEurisII(bus, mi)); + return unique_ptr(new MeterEurisII(mi)); } double MeterEurisII::currentConsumption(Unit u) diff --git a/src/meter_fhkvdataiii.cc b/src/meter_fhkvdataiii.cc index 1bf60a0..7901d06 100644 --- a/src/meter_fhkvdataiii.cc +++ b/src/meter_fhkvdataiii.cc @@ -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 createFHKVDataIII(WMBus *bus, MeterInfo &mi) +unique_ptr createFHKVDataIII(MeterInfo &mi) { - return unique_ptr(new MeterFHKVDataIII(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_hydrodigit.cc b/src/meter_hydrodigit.cc index 4ce07c0..9c020e0 100644 --- a/src/meter_hydrodigit.cc +++ b/src/meter_hydrodigit.cc @@ -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 createHydrodigit(WMBus *bus, MeterInfo &mi) +unique_ptr createHydrodigit(MeterInfo &mi) { - return unique_ptr(new MeterHydrodigit(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_hydrus.cc b/src/meter_hydrus.cc index d1c1d7f..0519db6 100644 --- a/src/meter_hydrus.cc +++ b/src/meter_hydrus.cc @@ -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 createHydrus(WMBus *bus, MeterInfo &mi) +unique_ptr createHydrus(MeterInfo &mi) { - return unique_ptr(new MeterHydrus(bus, mi)); + return unique_ptr(new MeterHydrus(mi)); } void MeterHydrus::processContent(Telegram *t) diff --git a/src/meter_iperl.cc b/src/meter_iperl.cc index 4e8fbef..f0bedf3 100644 --- a/src/meter_iperl.cc +++ b/src/meter_iperl.cc @@ -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 createIperl(WMBus *bus, MeterInfo &mi) +unique_ptr createIperl(MeterInfo &mi) { - return unique_ptr(new MeterIperl(bus, mi)); + return unique_ptr(new MeterIperl(mi)); } void MeterIperl::processContent(Telegram *t) diff --git a/src/meter_izar.cc b/src/meter_izar.cc index 06e6fe1..6c2fb68 100644 --- a/src/meter_izar.cc +++ b/src/meter_izar.cc @@ -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 keys; }; -unique_ptr createIzar(WMBus *bus, MeterInfo &mi) +unique_ptr createIzar(MeterInfo &mi) { - return unique_ptr(new MeterIzar(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_lansendw.cc b/src/meter_lansendw.cc index c4168a3..8786837 100644 --- a/src/meter_lansendw.cc +++ b/src/meter_lansendw.cc @@ -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 createLansenDW(WMBus *bus, MeterInfo &mi) +unique_ptr createLansenDW(MeterInfo &mi) { - return unique_ptr(new MeterLansenDW(bus, mi)); + return unique_ptr(new MeterLansenDW(mi)); } bool MeterLansenDW::open() diff --git a/src/meter_lansenpu.cc b/src/meter_lansenpu.cc index ac26123..191542b 100644 --- a/src/meter_lansenpu.cc +++ b/src/meter_lansenpu.cc @@ -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 createLansenPU(WMBus *bus, MeterInfo &mi) +unique_ptr createLansenPU(MeterInfo &mi) { - return unique_ptr(new MeterLansenPU(bus, mi)); + return unique_ptr(new MeterLansenPU(mi)); } double MeterLansenPU::counterA() diff --git a/src/meter_lansensm.cc b/src/meter_lansensm.cc index 6a53ca8..42315b7 100644 --- a/src/meter_lansensm.cc +++ b/src/meter_lansensm.cc @@ -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 createLansenSM(WMBus *bus, MeterInfo &mi) +unique_ptr createLansenSM(MeterInfo &mi) { - return unique_ptr(new MeterLansenSM(bus, mi)); + return unique_ptr(new MeterLansenSM(mi)); } bool MeterLansenSM::smokeDetected() diff --git a/src/meter_lansenth.cc b/src/meter_lansenth.cc index 1769452..1ddbc78 100644 --- a/src/meter_lansenth.cc +++ b/src/meter_lansenth.cc @@ -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 createLansenTH(WMBus *bus, MeterInfo &mi) +unique_ptr createLansenTH(MeterInfo &mi) { - return unique_ptr(new MeterLansenTH(bus, mi)); + return unique_ptr(new MeterLansenTH(mi)); } double MeterLansenTH::currentTemperature(Unit u) diff --git a/src/meter_mkradio3.cc b/src/meter_mkradio3.cc index b9e0d0e..7034cb9 100644 --- a/src/meter_mkradio3.cc +++ b/src/meter_mkradio3.cc @@ -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 createMKRadio3(WMBus *bus, MeterInfo &mi) +unique_ptr createMKRadio3(MeterInfo &mi) { - return unique_ptr(new MKRadio3(bus, mi)); + return unique_ptr(new MKRadio3(mi)); } void MKRadio3::processContent(Telegram *t) diff --git a/src/meter_multical21.cc b/src/meter_multical21.cc index 5e14967..1034ee7 100644 --- a/src/meter_multical21.cc +++ b/src/meter_multical21.cc @@ -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 createMulticalWaterMeter(WMBus *bus, MeterInfo &mi, MeterType mt) +unique_ptr 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(new MeterMultical21(bus,mi,mt)); + return unique_ptr(new MeterMultical21(mi,mt)); } -unique_ptr createMultical21(WMBus *bus, MeterInfo &mi) +unique_ptr createMultical21(MeterInfo &mi) { - return createMulticalWaterMeter(bus, mi, MeterType::MULTICAL21); + return createMulticalWaterMeter(mi, MeterType::MULTICAL21); } -unique_ptr createFlowIQ3100(WMBus *bus, MeterInfo &mi) +unique_ptr createFlowIQ3100(MeterInfo &mi) { - return createMulticalWaterMeter(bus, mi, MeterType::FLOWIQ3100); + return createMulticalWaterMeter(mi, MeterType::FLOWIQ3100); } void MeterMultical21::processContent(Telegram *t) diff --git a/src/meter_multical302.cc b/src/meter_multical302.cc index 1339ea4..eca76a6 100644 --- a/src/meter_multical302.cc +++ b/src/meter_multical302.cc @@ -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 createMultical302(WMBus *bus, MeterInfo &mi) { - return unique_ptr(new MeterMultical302(bus, mi)); +unique_ptr createMultical302(MeterInfo &mi) { + return unique_ptr(new MeterMultical302(mi)); } double MeterMultical302::totalEnergyConsumption(Unit u) diff --git a/src/meter_multical403.cc b/src/meter_multical403.cc index b281de2..d2a10df 100644 --- a/src/meter_multical403.cc +++ b/src/meter_multical403.cc @@ -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 createMultical403(WMBus *bus, MeterInfo &mi) { - return unique_ptr(new MeterMultical403(bus, mi)); +unique_ptr createMultical403(MeterInfo &mi) { + return unique_ptr(new MeterMultical403(mi)); } double MeterMultical403::totalEnergyConsumption(Unit u) diff --git a/src/meter_omnipower.cc b/src/meter_omnipower.cc index c564e6a..2e3f5ee 100644 --- a/src/meter_omnipower.cc +++ b/src/meter_omnipower.cc @@ -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 createOmnipower(WMBus *bus, MeterInfo &mi) +unique_ptr createOmnipower(MeterInfo &mi) { - return unique_ptr(new MeterOmnipower(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_q400.cc b/src/meter_q400.cc index d5e6ae1..2b85de9 100644 --- a/src/meter_q400.cc +++ b/src/meter_q400.cc @@ -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 createQ400(WMBus *bus, MeterInfo &mi) +unique_ptr createQ400(MeterInfo &mi) { - return unique_ptr(new MeterQ400(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_qcaloric.cc b/src/meter_qcaloric.cc index 05b2d2e..b421979 100644 --- a/src/meter_qcaloric.cc +++ b/src/meter_qcaloric.cc @@ -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 createQCaloric(WMBus *bus, MeterInfo &mi) +unique_ptr createQCaloric(MeterInfo &mi) { - return unique_ptr(new MeterQCaloric(bus, mi)); + return unique_ptr(new MeterQCaloric(mi)); } double MeterQCaloric::currentConsumption(Unit u) diff --git a/src/meter_rfmamb.cc b/src/meter_rfmamb.cc index 2fb0533..6ccf839 100644 --- a/src/meter_rfmamb.cc +++ b/src/meter_rfmamb.cc @@ -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 createRfmAmb(WMBus *bus, MeterInfo &mi) +unique_ptr createRfmAmb(MeterInfo &mi) { - return unique_ptr(new MeterRfmAmb(bus, mi)); + return unique_ptr(new MeterRfmAmb(mi)); } double MeterRfmAmb::currentTemperature(Unit u) diff --git a/src/meter_rfmtx1.cc b/src/meter_rfmtx1.cc index 4168f17..6326246 100644 --- a/src/meter_rfmtx1.cc +++ b/src/meter_rfmtx1.cc @@ -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 createRfmTX1(WMBus *bus, MeterInfo &mi) +unique_ptr createRfmTX1(MeterInfo &mi) { - return unique_ptr(new MeterRfmTX1(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_supercom587.cc b/src/meter_supercom587.cc index 87118ba..9ea68ef 100644 --- a/src/meter_supercom587.cc +++ b/src/meter_supercom587.cc @@ -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 createSupercom587(WMBus *bus, MeterInfo &mi) +unique_ptr createSupercom587(MeterInfo &mi) { - return unique_ptr(new MeterSupercom587(bus, mi)); + return unique_ptr(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); diff --git a/src/meter_vario451.cc b/src/meter_vario451.cc index c2ebfe1..591ebe3 100644 --- a/src/meter_vario451.cc +++ b/src/meter_vario451.cc @@ -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 createVario451(WMBus *bus, MeterInfo &mi) +unique_ptr createVario451(MeterInfo &mi) { - return unique_ptr(new MeterVario451(bus, mi)); + return unique_ptr(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 diff --git a/src/meter_waterstarm.cc b/src/meter_waterstarm.cc index f4340f4..f11e607 100644 --- a/src/meter_waterstarm.cc +++ b/src/meter_waterstarm.cc @@ -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 createWaterstarM(WMBus *bus, MeterInfo &mi) +unique_ptr createWaterstarM(MeterInfo &mi) { - return unique_ptr(new MeterWaterstarM(bus, mi)); + return unique_ptr(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); diff --git a/src/meters.cc b/src/meters.cc index 9835ba9..56b2096 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -25,19 +25,20 @@ #include #include -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](vectorinput_frame){return this->handleTelegram(input_frame);}); + //MeterCommonImplementation::bus()->onTelegram([this](vectorinput_frame){return this->handleTelegram(input_frame);}); } void MeterCommonImplementation::addConversions(std::vector cs) @@ -139,11 +140,6 @@ string MeterCommonImplementation::name() return name_; } -WMBus *MeterCommonImplementation::bus() -{ - return bus_; -} - void MeterCommonImplementation::onUpdate(function cb) { on_update_.push_back(cb); diff --git a/src/meters.h b/src/meters.h index 1542b99..2328e1c 100644 --- a/src/meters.h +++ b/src/meters.h @@ -101,7 +101,6 @@ struct Meter virtual string name() = 0; virtual MeterType type() = 0; virtual vector 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 createMultical21(WMBus *bus, MeterInfo &m); -unique_ptr createFlowIQ3100(WMBus *bus, MeterInfo &m); -unique_ptr createMultical302(WMBus *bus, MeterInfo &m); -unique_ptr createMultical403(WMBus *bus, MeterInfo &m); -unique_ptr createVario451(WMBus *bus, MeterInfo &m); -unique_ptr createWaterstarM(WMBus *bus, MeterInfo &m); -unique_ptr createOmnipower(WMBus *bus, MeterInfo &m); -unique_ptr createAmiplus(WMBus *bus, MeterInfo &m); -unique_ptr createSupercom587(WMBus *bus, MeterInfo &m); -unique_ptr createMKRadio3(WMBus *bus, MeterInfo &m); -unique_ptr createApator08(WMBus *bus, MeterInfo &m); -unique_ptr createApator162(WMBus *bus, MeterInfo &m); -unique_ptr createIperl(WMBus *bus, MeterInfo &m); -unique_ptr createHydrus(WMBus *bus, MeterInfo &m); -unique_ptr createHydrodigit(WMBus *bus, MeterInfo &m); -unique_ptr createIzar(WMBus *bus, MeterInfo &m); -unique_ptr createQ400(WMBus *bus, MeterInfo &m); -unique_ptr createQCaloric(WMBus *bus, MeterInfo &m); -unique_ptr createEurisII(WMBus *bus, MeterInfo &m); -unique_ptr createFHKVDataIII(WMBus *bus, MeterInfo &m); -unique_ptr createLansenTH(WMBus *bus, MeterInfo &m); -unique_ptr createLansenSM(WMBus *bus, MeterInfo &m); -unique_ptr createLansenPU(WMBus *bus, MeterInfo &m); -unique_ptr createLansenDW(WMBus *bus, MeterInfo &m); -unique_ptr createCMa12w(WMBus *bus, MeterInfo &m); -unique_ptr createRfmAmb(WMBus *bus, MeterInfo &m); -unique_ptr createRfmTX1(WMBus *bus, MeterInfo &m); -unique_ptr createEHZP(WMBus *bus, MeterInfo &m); -unique_ptr createESYSWM(WMBus *bus, MeterInfo &m); -unique_ptr createEBZWMBE(WMBus *bus, MeterInfo &m); -GenericMeter *createGeneric(WMBus *bus, MeterInfo &m); +unique_ptr createMultical21(MeterInfo &m); +unique_ptr createFlowIQ3100(MeterInfo &m); +unique_ptr createMultical302(MeterInfo &m); +unique_ptr createMultical403(MeterInfo &m); +unique_ptr createVario451(MeterInfo &m); +unique_ptr createWaterstarM(MeterInfo &m); +unique_ptr createOmnipower(MeterInfo &m); +unique_ptr createAmiplus(MeterInfo &m); +unique_ptr createSupercom587(MeterInfo &m); +unique_ptr createMKRadio3(MeterInfo &m); +unique_ptr createApator08(MeterInfo &m); +unique_ptr createApator162(MeterInfo &m); +unique_ptr createIperl(MeterInfo &m); +unique_ptr createHydrus(MeterInfo &m); +unique_ptr createHydrodigit(MeterInfo &m); +unique_ptr createIzar(MeterInfo &m); +unique_ptr createQ400(MeterInfo &m); +unique_ptr createQCaloric(MeterInfo &m); +unique_ptr createEurisII(MeterInfo &m); +unique_ptr createFHKVDataIII(MeterInfo &m); +unique_ptr createLansenTH(MeterInfo &m); +unique_ptr createLansenSM(MeterInfo &m); +unique_ptr createLansenPU(MeterInfo &m); +unique_ptr createLansenDW(MeterInfo &m); +unique_ptr createCMa12w(MeterInfo &m); +unique_ptr createRfmAmb(MeterInfo &m); +unique_ptr createRfmTX1(MeterInfo &m); +unique_ptr createEHZP(MeterInfo &m); +unique_ptr createESYSWM(MeterInfo &m); +unique_ptr createEBZWMBE(MeterInfo &m); +GenericMeter *createGeneric(MeterInfo &m); #endif diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 1bbd530..b0b493f 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -43,7 +43,6 @@ struct MeterCommonImplementation : public virtual Meter string name(); MeterType type(); vector 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; diff --git a/src/serial.cc b/src/serial.cc index 3cffc70..6e80d3b 100644 --- a/src/serial.cc +++ b/src/serial.cc @@ -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 createSerialDeviceSimulator(); void listenTo(SerialDevice *sd, function cb); + void onDisappear(SerialDevice *sd, function 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 callback, string name); + int startRegularCallback(string name, int seconds, function callback); void stopRegularCallback(int id); void resetInitiated() { debug("(serial) initiate reset\n"); resetting_ = true; } void resetCompleted() { debug("(serial) reset completed\n"); resetting_ = false; } vector listSerialDevices(); - + SerialDevice *lookup(std::string device); private: @@ -118,8 +119,9 @@ private: pthread_mutex_t devices_lock_ = PTHREAD_MUTEX_INITIALIZER; vector devices_; vector 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 &data) {}; int receive(vector *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 on_data_; + function 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 *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 *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 &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 &data) } end: - pthread_mutex_unlock(&write_lock_); + UNLOCK("(serial)", "send", write_lock_); return rc; } @@ -476,7 +487,7 @@ bool SerialDeviceCommand::send(vector &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 &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 si->on_data_ = cb; } +void SerialCommunicationManagerImp::onDisappear(SerialDevice *sd, function cb) +{ + if (sd == NULL) return; + SerialDeviceImp *si = dynamic_cast(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 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 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 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 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 callback, string name) +int SerialCommunicationManagerImp::startRegularCallback(string name, int seconds, function 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 SerialCommunicationManagerImp::listSerialDevices() { @@ -1201,7 +1238,11 @@ vector 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); diff --git a/src/serial.h b/src/serial.h index fd4e8d5..dad9636 100644 --- a/src/serial.h +++ b/src/serial.h @@ -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 createSerialDeviceSimulator() = 0; + // Invoke cb callback when data arrives on the serial device. virtual void listenTo(SerialDevice *sd, function cb) = 0; + // Invoke cb callback when the serial device has disappeared! + virtual void onDisappear(SerialDevice *sd, function 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 callback, std::string name) = 0; + virtual int startRegularCallback(std::string name, int seconds, function 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 listSerialDevices() = 0; + // Return a serial device for the given device, if it exists! Otherwise NULL. + virtual SerialDevice *lookup(std::string device) = 0; virtual ~SerialCommunicationManager(); }; diff --git a/src/testinternals.cc b/src/testinternals.cc index 3ac5574..8ca01d0 100644 --- a/src/testinternals.cc +++ b/src/testinternals.cc @@ -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); +} diff --git a/src/timings.h b/src/timings.h index 306f31b..86a4f51 100644 --- a/src/timings.h +++ b/src/timings.h @@ -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 diff --git a/src/util.cc b/src/util.cc index 44a24ac..0f00b67 100644 --- a/src/util.cc +++ b/src/util.cc @@ -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; diff --git a/src/util.h b/src/util.h index b8e37f9..843a9a6 100644 --- a/src/util.h +++ b/src/util.h @@ -49,8 +49,11 @@ std::string safeString(std::vector &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 &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 diff --git a/src/wmbus.cc b/src/wmbus.cc index ff7b6cd..44773ad 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -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 *format_byt return ok; } +WMBusCommonImplementation::~WMBusCommonImplementation() +{ + info("(wmbus) deleted %s\n", toString(type())); +} + WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t, SerialCommunicationManager *manager, unique_ptr 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; +} diff --git a/src/wmbus.h b/src/wmbus.h index f647e0f..e5400b8 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -30,6 +30,56 @@ bool trimCRCsFrameFormatA(std::vector &payload); bool trimCRCsFrameFormatB(std::vector &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)> 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 openIM871A(string device, SerialCommunicationManager *manager, unique_ptr serial_override); unique_ptr openAMB8465(string device, SerialCommunicationManager *manager, @@ -518,15 +540,19 @@ FrameStatus checkWMBusFrame(vector &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 diff --git a/src/wmbus_amb8465.cc b/src/wmbus_amb8465.cc index 0a77d68..d659d59 100644 --- a/src/wmbus_amb8465.cc +++ b/src/wmbus_amb8465.cc @@ -109,6 +109,7 @@ WMBusAmber::WMBusAmber(unique_ptr 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 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 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 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 &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; } diff --git a/src/wmbus_cul.cc b/src/wmbus_cul.cc index acb5c18..e68742a 100644 --- a/src/wmbus_cul.cc +++ b/src/wmbus_cul.cc @@ -100,6 +100,7 @@ WMBusCUL::WMBusCUL(unique_ptr 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 &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; } diff --git a/src/wmbus_im871a.cc b/src/wmbus_im871a.cc index bf8e3d2..f465894 100644 --- a/src/wmbus_im871a.cc +++ b/src/wmbus_im871a.cc @@ -76,7 +76,7 @@ private: static FrameStatus checkIM871AFrame(vector &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 &payload); void handleRadioLink(int msgid, vector &payload); void handleRadioLinkTest(int msgid, vector &payload); @@ -101,6 +101,7 @@ WMBusIM871A::WMBusIM871A(unique_ptr 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 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 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 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 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 &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; } diff --git a/src/wmbus_rawtty.cc b/src/wmbus_rawtty.cc index 2dc2d2e..c61adb9 100644 --- a/src/wmbus_rawtty.cc +++ b/src/wmbus_rawtty.cc @@ -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; } diff --git a/src/wmbus_rtlwmbus.cc b/src/wmbus_rtlwmbus.cc index a089359..1196435 100644 --- a/src/wmbus_rtlwmbus.cc +++ b/src/wmbus_rtlwmbus.cc @@ -288,8 +288,15 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector &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; } diff --git a/src/wmbus_utils.h b/src/wmbus_utils.h index c427e73..4dd9dc1 100644 --- a/src/wmbus_utils.h +++ b/src/wmbus_utils.h @@ -29,14 +29,17 @@ string frameTypeKamstrupC1(int ft); struct WMBusCommonImplementation : public virtual WMBus { WMBusCommonImplementation(WMBusDeviceType t, SerialCommunicationManager *manager, unique_ptr serial_override); + ~WMBusCommonImplementation(); WMBusDeviceType type(); void setMeters(vector> *meters); void onTelegram(function)> cb); bool handleTelegram(vector 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)>> telegram_listeners_; vector> *meters_; WMBusDeviceType type_ {}; diff --git a/src/wmbus_wmb13u.cc b/src/wmbus_wmb13u.cc index f6fe66b..0bd6fa8 100644 --- a/src/wmbus_wmb13u.cc +++ b/src/wmbus_wmb13u.cc @@ -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 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;