kopia lustrzana https://github.com/weetmuts/wmbusmeters
Detect and start wmbus dongles from within wmbusmeters.
rodzic
78a353de59
commit
69df7f022a
4
Makefile
4
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
|
||||
|
|
123
install.sh
123
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 <<EOF > "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",SYMLINK+="im871a_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/im871a_%n.service"
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",SYMLINK+="amb8465_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/amb8465_%n.service"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838",SYMLINK+="rtlsdr_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/rtlsdr_%n.service"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="2047", ATTRS{idProduct}=="0863",SYMLINK+="rfmrx2_%n",MODE="0660", GROUP="wmbusmeters",TAG+="systemd",ENV{SYSTEMD_WANTS}="wmbusmeters@/dev/rfmrx2_%n.service"
|
||||
EOF
|
||||
echo udev: installed "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
|
||||
else
|
||||
echo udev: "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules unchanged
|
||||
fi
|
||||
echo udev: removing "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
|
||||
echo udev: backup stored here: ~/old.wmbusmeters-wmbus-usb-serial.rules.backup
|
||||
cp "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ~/old.wmbusmeters-wmbus-usb-serial.rules.backup
|
||||
rm "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules
|
||||
UDEV_NEEDS_RELOAD=true
|
||||
fi
|
||||
|
||||
if [ "$SYSTEMD_NEEDS_RELOAD" = "true" ]
|
||||
|
@ -362,13 +311,9 @@ fi
|
|||
|
||||
if [ "$UDEV_NEEDS_RELOAD" = "true" ]
|
||||
then
|
||||
D=$(diff "$ROOT"/etc/udev/rules.d/99-wmbus-usb-serial.rules ~/old.wmbusmeters-wmbus-usb-serial.rules.backup)
|
||||
if [ "$D" != "" ]
|
||||
then
|
||||
echo
|
||||
echo
|
||||
echo You need to reload udev configuration! Please do:
|
||||
echo "sudo udevadm control --reload-rules"
|
||||
echo "sudo udevadm trigger"
|
||||
fi
|
||||
echo
|
||||
echo
|
||||
echo You need to reload udev configuration! Please do:
|
||||
echo "sudo udevadm control --reload-rules"
|
||||
echo "sudo udevadm trigger"
|
||||
fi
|
||||
|
|
459
src/admin.cc
459
src/admin.cc
|
@ -15,24 +15,16 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include<curses.h>
|
||||
#include<menu.h>
|
||||
#include<string.h>
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include<syslog.h>
|
||||
|
||||
#include"serial.h"
|
||||
#include"shell.h"
|
||||
#include"ui.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
#define BG_PAIR 1
|
||||
#define WIN_PAIR 2
|
||||
#define TITLE_PAIR 3
|
||||
#define HILIGHT_PAIR 4
|
||||
|
||||
#include <menu.h>
|
||||
|
||||
bool running_as_root_ = false;
|
||||
bool member_of_dialout_ = false;
|
||||
|
||||
|
@ -78,30 +70,24 @@ LIST_OF_WMBUS_RECEIVERS
|
|||
};
|
||||
|
||||
bool detectIfRoot();
|
||||
string userName();
|
||||
bool detectIfMemberOfGroup(string group);
|
||||
void detectProcesses(string cmd, vector<int> *pids);
|
||||
void detectWMBUSReceiver();
|
||||
void resetWMBUSReceiver();
|
||||
void probeFor(string type, AccessCheck(*func)(string,SerialCommunicationManager*));
|
||||
void probeFor(string type, AccessCheck(*func)(string,Detected*,SerialCommunicationManager*));
|
||||
|
||||
void printAt(WINDOW *win, int y, int x, const char *str, chtype color);
|
||||
void printMiddle(WINDOW *win, int y, int width, const char *str, chtype color);
|
||||
void stopDaemon();
|
||||
void startDaemon();
|
||||
|
||||
void alwaysOnScreen();
|
||||
int selectFromMenu(const char *title, const char *menu[]);
|
||||
int selectFromMenu(const char *title, vector<string> menu);
|
||||
void displayInformationAndWait(string title, vector<string> entries, int px=-1, int py=-1);
|
||||
void displayInformationNoWait(WINDOW **win, string title, vector<string> entries, int px=-1, int py=-1);
|
||||
|
||||
void notImplementedYet(string msg);
|
||||
|
||||
int screen_width, screen_height;
|
||||
unique_ptr<SerialCommunicationManager> handler;
|
||||
|
||||
WINDOW *status_window;
|
||||
WINDOW *serial_ports_window;
|
||||
WINDOW *processes_window;
|
||||
|
||||
void alwaysOnScreen();
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 2 && (!strcmp(argv[1], "--debug") || !strcmp(argv[1], "--trace")))
|
||||
|
@ -112,27 +98,33 @@ int main(int argc, char **argv)
|
|||
enableSyslog();
|
||||
}
|
||||
|
||||
initUI();
|
||||
clear();
|
||||
|
||||
refresh();
|
||||
int x=0;
|
||||
int y=0;
|
||||
for (int i=0;i<10; ++i) {
|
||||
printAt(stdscr, y, x, "HEJSAN", COLOR_PAIR(BG_PAIR));
|
||||
y++;
|
||||
x++;
|
||||
};
|
||||
refresh();
|
||||
for(;;) {}
|
||||
endwin();
|
||||
return 0;
|
||||
|
||||
/*
|
||||
running_as_root_ = detectIfRoot();
|
||||
member_of_dialout_ = detectIfMemberOfGroup("dialout");
|
||||
|
||||
handler = createSerialCommunicationManager(0, 0, false);
|
||||
|
||||
initscr();
|
||||
getmaxyx(stdscr, screen_height, screen_width);
|
||||
start_color();
|
||||
cbreak();
|
||||
curs_set(0);
|
||||
noecho();
|
||||
keypad(stdscr, TRUE);
|
||||
|
||||
init_pair(BG_PAIR, COLOR_WHITE, COLOR_BLUE);
|
||||
init_pair(WIN_PAIR, COLOR_BLACK, COLOR_WHITE);
|
||||
init_pair(TITLE_PAIR, COLOR_WHITE, COLOR_CYAN);
|
||||
init_pair(HILIGHT_PAIR, COLOR_WHITE, COLOR_RED);
|
||||
wbkgd(stdscr, COLOR_PAIR(BG_PAIR));
|
||||
initUI();
|
||||
|
||||
bool running = true;
|
||||
|
||||
registerUpdateCB(alwaysOnScreen);
|
||||
alwaysOnScreen();
|
||||
|
||||
do
|
||||
|
@ -157,84 +149,23 @@ int main(int argc, char **argv)
|
|||
notImplementedYet("Edit meters");
|
||||
break;
|
||||
case MainMenuType::STOP_DAEMON:
|
||||
notImplementedYet("Stop daemon");
|
||||
stopDaemon();
|
||||
break;
|
||||
case MainMenuType::START_DAEMON:
|
||||
notImplementedYet("Start daemon");
|
||||
startDaemon();
|
||||
break;
|
||||
case MainMenuType::EXIT_ADMIN:
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
} while (running);
|
||||
|
||||
|
||||
endwin();
|
||||
}
|
||||
|
||||
void printAt(WINDOW *win, int y, int x, const char *str, chtype color)
|
||||
{
|
||||
wattron(win, color);
|
||||
mvwprintw(win, y, x, "%s", str);
|
||||
wattroff(win, color);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void printMiddle(WINDOW *win, int y, int width, const char *str, chtype color)
|
||||
{
|
||||
int len = strlen(str);
|
||||
int wh, ww;
|
||||
|
||||
getyx(win, wh, ww);
|
||||
((void)wh);
|
||||
|
||||
int x = (width-len)/2;
|
||||
wattron(win, color);
|
||||
mvwprintw(win, y, x, "%s", str);
|
||||
wattroff(win, color);
|
||||
refresh();
|
||||
}
|
||||
|
||||
int countEntries(const char *entries[])
|
||||
{
|
||||
int i = 0;
|
||||
for (; entries[i] != 0; ++i);
|
||||
return i+1;
|
||||
}
|
||||
|
||||
int maxWidth(const char *entries[])
|
||||
{
|
||||
int max = 0;
|
||||
for (int i=0; entries[i] != 0; ++i)
|
||||
{
|
||||
int n = strlen(entries[i]);
|
||||
if (max < n) max = n;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
int maxWidth(vector<string> entries)
|
||||
{
|
||||
int max = 0;
|
||||
for (string& s : entries)
|
||||
{
|
||||
int n = s.length();
|
||||
if (max < n) max = n;
|
||||
}
|
||||
return max;
|
||||
*/
|
||||
}
|
||||
|
||||
void alwaysOnScreen()
|
||||
{
|
||||
static uchar ticktock = 0;
|
||||
|
||||
vector<string> info;
|
||||
ticktock++;
|
||||
|
||||
if (running_as_root_ == false)
|
||||
{
|
||||
info.push_back("Not running as root!");
|
||||
}
|
||||
if (member_of_dialout_ == false)
|
||||
{
|
||||
info.push_back("Not member of dialout!");
|
||||
|
@ -268,7 +199,17 @@ void alwaysOnScreen()
|
|||
}
|
||||
}
|
||||
|
||||
displayInformationNoWait(&status_window, (ticktock%2==0)?"Status ":"Status.", info, 1, 1);
|
||||
vector<string> status;
|
||||
time_t now = time(NULL);
|
||||
struct tm nowt {};
|
||||
localtime_r(&now, &nowt);
|
||||
status.push_back("wmbusmeters-admin");
|
||||
status.push_back(strdatetimesec(&nowt));
|
||||
string name = "["+userName()+"]";
|
||||
status.push_back(name);
|
||||
displayStatusLineNoWait(&status_window, status, 0, 0);
|
||||
|
||||
displayInformationNoWait(&status_window, "Problems", info, 2, 2);
|
||||
|
||||
vector<string> devices = handler->listSerialDevices();
|
||||
if (devices.size() == 0)
|
||||
|
@ -280,252 +221,8 @@ void alwaysOnScreen()
|
|||
displayInformationNoWait(&serial_ports_window, "Serial ports", devices, 1, 15);
|
||||
|
||||
erase();
|
||||
redrawwin(status_window);
|
||||
redrawwin(serial_ports_window);
|
||||
}
|
||||
|
||||
int selectFromMenu(const char *title, const char *entries[])
|
||||
{
|
||||
vector<string> menu;
|
||||
int n_choices = countEntries(entries);
|
||||
|
||||
for (int i=0; i<n_choices; ++i)
|
||||
{
|
||||
if (entries[i] == NULL) break;
|
||||
menu.push_back(entries[i]);
|
||||
}
|
||||
return selectFromMenu(title, menu);
|
||||
}
|
||||
|
||||
int selectFromMenu(const char *title, vector<string> entries)
|
||||
{
|
||||
int selected = -1;
|
||||
ITEM **menu_items;
|
||||
int c;
|
||||
MENU *menu;
|
||||
WINDOW *frame_window, *menu_window;
|
||||
int n_choices, i;
|
||||
|
||||
n_choices = entries.size()+1;
|
||||
menu_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
|
||||
for(i = 0; i < n_choices-1; ++i)
|
||||
{
|
||||
menu_items[i] = new_item(entries[i].c_str(), NULL);
|
||||
}
|
||||
menu_items[n_choices-1] = NULL;
|
||||
|
||||
menu = new_menu(menu_items);
|
||||
int mw = 0;
|
||||
int mh = 0;
|
||||
scale_menu(menu, &mh, &mw);
|
||||
int w = mw+2;
|
||||
int h = mh+4;
|
||||
if (w-2 < (int)strlen(title))
|
||||
{
|
||||
w = (int)strlen(title)+2;
|
||||
}
|
||||
int x = screen_width/2-w/2;
|
||||
int y = screen_height/2-h/2;
|
||||
frame_window = newwin(h, w, y, x);
|
||||
|
||||
int mx = (w-mw)/2;
|
||||
int my = 3;
|
||||
menu_window = derwin(frame_window, mh, mw, my, mx);
|
||||
|
||||
set_menu_fore(menu, COLOR_PAIR(HILIGHT_PAIR));
|
||||
set_menu_back(menu, COLOR_PAIR(WIN_PAIR));
|
||||
set_menu_grey(menu, COLOR_PAIR(3));
|
||||
|
||||
keypad(frame_window, TRUE);
|
||||
|
||||
set_menu_win(menu, frame_window);
|
||||
set_menu_sub(menu, menu_window);
|
||||
|
||||
set_menu_mark(menu, ">");
|
||||
|
||||
box(frame_window, 0, 0);
|
||||
wbkgd(frame_window, COLOR_PAIR(WIN_PAIR));
|
||||
|
||||
printMiddle(frame_window, 1, w, title, COLOR_PAIR(WIN_PAIR));
|
||||
mvwaddch(frame_window, 2, 0, ACS_LTEE);
|
||||
mvwhline(frame_window, 2, 1, ACS_HLINE, 38);
|
||||
mvwaddch(frame_window, 2, w-1, ACS_RTEE);
|
||||
refresh();
|
||||
|
||||
post_menu(menu);
|
||||
wrefresh(frame_window);
|
||||
|
||||
alwaysOnScreen();
|
||||
|
||||
wtimeout(frame_window, 1000);
|
||||
|
||||
bool running = true;
|
||||
do
|
||||
{
|
||||
c = wgetch(frame_window);
|
||||
ITEM *cur = current_item(menu);
|
||||
selected = item_index(cur);
|
||||
switch(c)
|
||||
{
|
||||
case ERR:
|
||||
alwaysOnScreen();
|
||||
redrawwin(frame_window);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if (selected < n_choices-2)
|
||||
{
|
||||
menu_driver(menu, REQ_DOWN_ITEM);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_driver(menu, REQ_FIRST_ITEM);
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (selected > 0)
|
||||
{
|
||||
menu_driver(menu, REQ_UP_ITEM);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_driver(menu, REQ_LAST_ITEM);
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
wrefresh(frame_window);
|
||||
} while (running);
|
||||
|
||||
unpost_menu(menu);
|
||||
free_menu(menu);
|
||||
delwin(frame_window);
|
||||
erase();
|
||||
refresh();
|
||||
for(i = 0; i < n_choices; ++i)
|
||||
{
|
||||
free_item(menu_items[i]);
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
void displayInformationAndWait(string title, vector<string> entries, int px, int py)
|
||||
{
|
||||
WINDOW *frame_window;
|
||||
|
||||
alwaysOnScreen();
|
||||
|
||||
int mw = maxWidth(entries)+1;
|
||||
int mh = entries.size();
|
||||
int w = mw+2;
|
||||
int h = mh+4;
|
||||
if (w-2 < (int)title.length())
|
||||
{
|
||||
w = (int)title.length()+2;
|
||||
}
|
||||
int x = screen_width/2-w/2;
|
||||
int y = screen_height/2-h/2;
|
||||
if (px != -1)
|
||||
{
|
||||
x = px;
|
||||
}
|
||||
if (py != -1)
|
||||
{
|
||||
y = py;
|
||||
}
|
||||
frame_window = newwin(h, w, y, x);
|
||||
|
||||
keypad(frame_window, TRUE);
|
||||
|
||||
box(frame_window, 0, 0);
|
||||
wbkgd(frame_window, COLOR_PAIR(WIN_PAIR));
|
||||
|
||||
printMiddle(frame_window, 1, w, title.c_str(), COLOR_PAIR(WIN_PAIR));
|
||||
mvwaddch(frame_window, 2, 0, ACS_LTEE);
|
||||
mvwhline(frame_window, 2, 1, ACS_HLINE, 38);
|
||||
mvwaddch(frame_window, 2, w-1, ACS_RTEE);
|
||||
//refresh();
|
||||
|
||||
int r = 3;
|
||||
for (string e : entries)
|
||||
{
|
||||
printAt(frame_window, r, 1, e.c_str(), COLOR_PAIR(WIN_PAIR));
|
||||
r++;
|
||||
}
|
||||
wrefresh(frame_window);
|
||||
wtimeout(frame_window, 1000);
|
||||
|
||||
bool running = true;
|
||||
do
|
||||
{
|
||||
int c = wgetch(frame_window);
|
||||
switch(c)
|
||||
{
|
||||
case ERR:
|
||||
alwaysOnScreen();
|
||||
redrawwin(frame_window);
|
||||
break;
|
||||
case 27:
|
||||
case '\n':
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
wrefresh(frame_window);
|
||||
} while (running);
|
||||
|
||||
delwin(frame_window);
|
||||
erase();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void displayInformationNoWait(WINDOW **winp, string title, vector<string> entries, int px, int py)
|
||||
{
|
||||
WINDOW *win = *winp;
|
||||
|
||||
if (win != NULL)
|
||||
{
|
||||
delwin(win);
|
||||
*winp = NULL;
|
||||
}
|
||||
int mw = maxWidth(entries)+1;
|
||||
int mh = entries.size();
|
||||
int w = mw+2;
|
||||
int h = mh+4;
|
||||
if (w-2 < (int)title.length())
|
||||
{
|
||||
w = (int)title.length()+2;
|
||||
}
|
||||
int x = screen_width/2-w/2;
|
||||
int y = screen_height/2-h/2;
|
||||
if (px != -1)
|
||||
{
|
||||
x = px;
|
||||
}
|
||||
if (py != -1)
|
||||
{
|
||||
y = py;
|
||||
}
|
||||
win = newwin(h, w, y, x);
|
||||
*winp = win;
|
||||
|
||||
box(win, 0, 0);
|
||||
wbkgd(win, COLOR_PAIR(WIN_PAIR));
|
||||
|
||||
printMiddle(win, 1, w, title.c_str(), COLOR_PAIR(WIN_PAIR));
|
||||
mvwaddch(win, 2, 0, ACS_LTEE);
|
||||
mvwhline(win, 2, 1, ACS_HLINE, 38);
|
||||
mvwaddch(win, 2, w-1, ACS_RTEE);
|
||||
// refresh();
|
||||
|
||||
int r = 3;
|
||||
for (string e : entries)
|
||||
{
|
||||
printAt(win, r, 1, e.c_str(), COLOR_PAIR(WIN_PAIR));
|
||||
r++;
|
||||
}
|
||||
wrefresh(win);
|
||||
wrefresh(status_window);
|
||||
wrefresh(serial_ports_window);
|
||||
}
|
||||
|
||||
void detectWMBUSReceiver()
|
||||
|
@ -586,15 +283,9 @@ void resetWMBUSReceiver()
|
|||
}
|
||||
}
|
||||
|
||||
void notImplementedYet(string msg)
|
||||
{
|
||||
vector<string> entries;
|
||||
entries.push_back(msg);
|
||||
displayInformationAndWait("Not implemented yet", entries);
|
||||
}
|
||||
|
||||
void probeFor(string type, AccessCheck (*check)(string,SerialCommunicationManager*))
|
||||
void probeFor(string type, AccessCheck (*check)(string,Detected*,SerialCommunicationManager*))
|
||||
{
|
||||
Detected detected {};
|
||||
vector<string> devices = handler->listSerialDevices();
|
||||
vector<string> entries;
|
||||
for (string& device : devices)
|
||||
|
@ -602,7 +293,7 @@ void probeFor(string type, AccessCheck (*check)(string,SerialCommunicationManage
|
|||
string tty = "?";
|
||||
AccessCheck ac = checkAccessAndDetect(
|
||||
handler.get(),
|
||||
[=](string d, SerialCommunicationManager* m){ return check(d, m);},
|
||||
[&](string d, SerialCommunicationManager* m){ return check(d, &detected, m);},
|
||||
type,
|
||||
device);
|
||||
|
||||
|
@ -638,6 +329,18 @@ bool detectIfRoot()
|
|||
return out == "0\n";
|
||||
}
|
||||
|
||||
string userName()
|
||||
{
|
||||
vector<string> args;
|
||||
vector<string> envs;
|
||||
args.push_back("-u");
|
||||
args.push_back("-n");
|
||||
string out;
|
||||
invokeShellCaptureOutput("/usr/bin/id", args, envs, &out, true);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool detectIfMemberOfGroup(string group)
|
||||
{
|
||||
vector<string> args;
|
||||
|
@ -674,3 +377,49 @@ void detectProcesses(string cmd, vector<int> *pids)
|
|||
pch = strtok (NULL, " \n");
|
||||
}
|
||||
}
|
||||
|
||||
void stopDaemon()
|
||||
{
|
||||
vector<string> info;
|
||||
info.push_back("Enter sudo password to execute:");
|
||||
info.push_back("systemctl stop wmbusmeters");
|
||||
|
||||
debug("(passowrd) calling inputfield\n");
|
||||
string pwd = inputField("Stop daemon", info, "Password");
|
||||
debug("(passowrd) GOT %s\n", pwd.c_str());
|
||||
//string pwd = displayInformationAndInput("Stop daemon", info, 1, 1);
|
||||
//vector<string> args;
|
||||
//vector<string> envs;
|
||||
//args.push_back("gurka");
|
||||
// string out;
|
||||
// invokeShellCaptureOutput("systemctl stop wmbusmeters", args, envs, &out, true);
|
||||
}
|
||||
|
||||
void startDaemon()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
static char* trim_whitespaces(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
// trim leading space
|
||||
while(isspace(*str))
|
||||
str++;
|
||||
|
||||
if(*str == 0) // all spaces?
|
||||
return str;
|
||||
|
||||
// trim trailing space
|
||||
end = str + strnlen(str, 128) - 1;
|
||||
|
||||
while(end > str && isspace(*end))
|
||||
end--;
|
||||
|
||||
// write new null terminator
|
||||
*(end+1) = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
|
||||
#include"cmdline.h"
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
#include"util.h"
|
||||
|
||||
|
@ -68,7 +67,8 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
|||
c->need_help = true;
|
||||
return unique_ptr<Configuration>(c);
|
||||
}
|
||||
while (argv[i] && argv[i][0] == '-') {
|
||||
while (argv[i] && argv[i][0] == '-')
|
||||
{
|
||||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
|
||||
c->need_help = true;
|
||||
return unique_ptr<Configuration>(c);
|
||||
|
@ -96,6 +96,12 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--trace")) {
|
||||
c->debug = true;
|
||||
c->trace = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--internaltesting")) {
|
||||
c->internaltesting = true;
|
||||
i++;
|
||||
|
@ -438,18 +444,17 @@ unique_ptr<Configuration> parseCommandLine(int argc, char **argv) {
|
|||
error("Unknown option \"%s\"\n", argv[i]);
|
||||
}
|
||||
|
||||
char *extra = argv[i] ? strchr(argv[i], ':') : NULL ;
|
||||
if (extra) {
|
||||
*extra = 0;
|
||||
extra++;
|
||||
c->device_extra = extra;
|
||||
while (argv[i])
|
||||
{
|
||||
Device device;
|
||||
bool ok = isPossibleDevice(argv[i], &device);
|
||||
if (!ok) break;
|
||||
c->wmbus_devices.push_back(device);
|
||||
i++;
|
||||
}
|
||||
if (argv[i]) {
|
||||
c->device = argv[i];
|
||||
}
|
||||
i++;
|
||||
if (c->device.length() == 0) {
|
||||
error("You must supply the usb device to which the wmbus dongle is connected.\n");
|
||||
|
||||
if (c->wmbus_devices.size() == 0) {
|
||||
error("You must supply at least one device to receive wmbus telegrams.\n");
|
||||
}
|
||||
|
||||
if ((argc-i) % 4 != 0) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,8 +79,8 @@ struct Configuration
|
|||
bool oneshot {};
|
||||
int exitafter {}; // Seconds to exit.
|
||||
int reopenafter {}; // Re-open the serial device repeatedly. Silly dongle.
|
||||
string device; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus
|
||||
string device_extra; // The frequency or the command line that will start rtlwmbus
|
||||
std::vector<Device> wmbus_devices; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus, /dev/ttyUSB1:9600
|
||||
std::vector<Device> mbus_devices; // auto, /dev/ttyUSB0, simulation.txt, rtlwmbus, /dev/ttyUSB1:9600
|
||||
string telegram_reader;
|
||||
// A set of all link modes (union) that the user requests the wmbus dongle to listen to.
|
||||
LinkModeSet listen_to_link_modes;
|
||||
|
|
529
src/main.cc
529
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<string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
|
@ -38,21 +37,49 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
void oneshotCheck(Configuration *cmdline, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> &meters);
|
||||
bool startUsingCommandline(Configuration *cmdline);
|
||||
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> *meters);
|
||||
void setupLogFile(Configuration *config);
|
||||
void setupMeters(Configuration *config, vector<unique_ptr<Meter>> *meters);
|
||||
void attachMetersToPrinter(Configuration *config, vector<unique_ptr<Meter>> *meters, Printer *printer);
|
||||
void detectAndConfigureWMBusDevices(Configuration *config, SerialCommunicationManager *manager, vector<unique_ptr<WMBus>> *devices);
|
||||
unique_ptr<Printer> createPrinter(Configuration *config);
|
||||
void logStartInformation(Configuration *config);
|
||||
bool start(Configuration *config);
|
||||
void startUsingConfigFiles(string root, bool is_daemon, string device_override, string listento_override);
|
||||
void startDaemon(string pid_file, string device_override, string listento_override); // Will use config files.
|
||||
|
||||
// The serial communication manager takes care of
|
||||
// monitoring the file descrtiptors for the ttys,
|
||||
// background shells. It also invokes regular callbacks
|
||||
// used for monitoring alarms and detecting new devices.
|
||||
unique_ptr<SerialCommunicationManager> manager_;
|
||||
|
||||
// Registered meters to decode and relay.
|
||||
// This does not change during runtime.
|
||||
vector<unique_ptr<Meter>> meters_;
|
||||
|
||||
// Current active set of wmbus devices that can receive telegrams.
|
||||
// This can change during runtime, plugging/unplugging wmbus dongles.
|
||||
vector<unique_ptr<WMBus>> devices_;
|
||||
pthread_mutex_t devices_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Rendering the telegrams to json,fields or shell calls is
|
||||
// done by the printer.
|
||||
unique_ptr<Printer> printer_;
|
||||
|
||||
// Set as true when the warning for no detected wmbus devices has been printed.
|
||||
bool printed_warning_ = false;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
auto cmdline = parseCommandLine(argc, argv);
|
||||
auto config = parseCommandLine(argc, argv);
|
||||
|
||||
if (cmdline->version) {
|
||||
if (config->version) {
|
||||
printf("wmbusmeters: " VERSION "\n");
|
||||
printf(COMMIT "\n");
|
||||
exit(0);
|
||||
}
|
||||
if (cmdline->license) {
|
||||
if (config->license) {
|
||||
const char * license = R"LICENSE(
|
||||
Copyright (C) 2017-2020 Fredrik Öhrström
|
||||
|
||||
|
@ -77,129 +104,79 @@ provided you with this binary. Read the full license for all details.
|
|||
puts(license);
|
||||
exit(0);
|
||||
}
|
||||
if (cmdline->need_help) {
|
||||
if (config->need_help) {
|
||||
printf("wmbusmeters version: " VERSION "\n");
|
||||
const char *short_manual =
|
||||
#include"short_manual.h"
|
||||
puts(short_manual);
|
||||
}
|
||||
else
|
||||
if (cmdline->daemon) {
|
||||
startDaemon(cmdline->pid_file, cmdline->device_override, cmdline->listento_override);
|
||||
if (config->daemon) {
|
||||
startDaemon(config->pid_file, config->device_override, config->listento_override);
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
if (cmdline->useconfig) {
|
||||
startUsingConfigFiles(cmdline->config_root, false, cmdline->device_override, cmdline->listento_override);
|
||||
if (config->useconfig) {
|
||||
startUsingConfigFiles(config->config_root, false, config->device_override, config->listento_override);
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
// We want the data visible in the log file asap!
|
||||
setbuf(stdout, NULL);
|
||||
startUsingCommandline(cmdline.get());
|
||||
start(config.get());
|
||||
exit(0);
|
||||
}
|
||||
error("(main) internal error\n");
|
||||
}
|
||||
|
||||
bool startUsingCommandline(Configuration *config)
|
||||
unique_ptr<WMBus> createWMBusDeviceFrom(Detected *detected, Configuration *config, SerialCommunicationManager *manager)
|
||||
{
|
||||
if (config->use_logfile)
|
||||
{
|
||||
verbose("(wmbusmeters) using log file %s\n", config->logfile.c_str());
|
||||
bool ok = enableLogfile(config->logfile, config->daemon);
|
||||
if (!ok) {
|
||||
if (config->daemon) {
|
||||
warning("Could not open log file, will use syslog instead.\n");
|
||||
} else {
|
||||
error("Could not open log file.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
disableLogfile();
|
||||
}
|
||||
|
||||
warningSilenced(config->silence);
|
||||
verboseEnabled(config->verbose);
|
||||
logTelegramsEnabled(config->logtelegrams);
|
||||
debugEnabled(config->debug);
|
||||
internalTestingEnabled(config->internaltesting);
|
||||
traceEnabled(config->trace);
|
||||
stderrEnabled(config->use_stderr);
|
||||
setAlarmShells(config->alarm_shells);
|
||||
|
||||
debug("(wmbusmeters) version: " VERSION "\n");
|
||||
|
||||
if (config->exitafter != 0) {
|
||||
verbose("(config) wmbusmeters will exit after %d seconds\n", config->exitafter);
|
||||
}
|
||||
|
||||
if (config->reopenafter != 0) {
|
||||
verbose("(config) wmbusmeters close/open the wmbus dongle fd after every %d seconds\n", config->reopenafter);
|
||||
}
|
||||
|
||||
if (config->meterfiles) {
|
||||
verbose("(config) store meter files in: \"%s\"\n", config->meterfiles_dir.c_str());
|
||||
}
|
||||
verbose("(config) using device: %s\n", config->device.c_str());
|
||||
if (config->device_extra.length() > 0) {
|
||||
verbose("(config) with: %s\n", config->device_extra.c_str());
|
||||
}
|
||||
verbose("(config) number of meters: %d\n", config->meters.size());
|
||||
|
||||
auto manager = createSerialCommunicationManager(config->exitafter, config->reopenafter);
|
||||
onExit(call(manager.get(),stop));
|
||||
|
||||
Detected settings = detectWMBusDeviceSetting(config->device, config->device_extra, manager.get());
|
||||
unique_ptr<WMBus> wmbus;
|
||||
|
||||
unique_ptr<SerialDevice> serial_override;
|
||||
bool link_modes_matter = true;
|
||||
|
||||
if (settings.override_tty)
|
||||
if (detected->override_tty)
|
||||
{
|
||||
serial_override = manager->createSerialDeviceFile(settings.devicefile);
|
||||
verbose("(serial) override with devicefile: %s\n", settings.devicefile.c_str());
|
||||
serial_override = manager->createSerialDeviceFile(detected->device.file);
|
||||
verbose("(serial) override with devicefile: %s\n", detected->device.file.c_str());
|
||||
link_modes_matter = false;
|
||||
}
|
||||
|
||||
unique_ptr<WMBus> wmbus;
|
||||
|
||||
switch (settings.type)
|
||||
switch (detected->type)
|
||||
{
|
||||
case DEVICE_IM871A:
|
||||
verbose("(im871a) on %s\n", settings.devicefile.c_str());
|
||||
wmbus = openIM871A(settings.devicefile, manager.get(), std::move(serial_override));
|
||||
verbose("(im871a) on %s\n", detected->device.file.c_str());
|
||||
wmbus = openIM871A(detected->device.file, manager, std::move(serial_override));
|
||||
break;
|
||||
case DEVICE_AMB8465:
|
||||
verbose("(amb8465) on %s\n", settings.devicefile.c_str());
|
||||
wmbus = openAMB8465(settings.devicefile, manager.get(), std::move(serial_override));
|
||||
verbose("(amb8465) on %s\n", detected->device.file.c_str());
|
||||
wmbus = openAMB8465(detected->device.file, manager, std::move(serial_override));
|
||||
break;
|
||||
case DEVICE_SIMULATOR:
|
||||
verbose("(simulator) in %s\n", settings.devicefile.c_str());
|
||||
wmbus = openSimulator(settings.devicefile, manager.get(), std::move(serial_override));
|
||||
verbose("(simulator) in %s\n", detected->device.file.c_str());
|
||||
wmbus = openSimulator(detected->device.file, manager, std::move(serial_override));
|
||||
link_modes_matter = false;
|
||||
break;
|
||||
case DEVICE_RAWTTY:
|
||||
verbose("(rawtty) on %s\n", settings.devicefile.c_str());
|
||||
wmbus = openRawTTY(settings.devicefile, settings.baudrate, manager.get(), std::move(serial_override));
|
||||
verbose("(rawtty) on %s\n", detected->device.file.c_str());
|
||||
wmbus = openRawTTY(detected->device.file, detected->baudrate, manager, std::move(serial_override));
|
||||
link_modes_matter = false;
|
||||
break;
|
||||
case DEVICE_RFMRX2:
|
||||
verbose("(rfmrx2) on %s\n", settings.devicefile.c_str());
|
||||
verbose("(rfmrx2) on %s\n", detected->device.file.c_str());
|
||||
if (config->reopenafter == 0)
|
||||
{
|
||||
manager->setReopenAfter(600); // Close and reopen the fd, because of some bug in the device.
|
||||
}
|
||||
wmbus = openRawTTY(settings.devicefile, 38400, manager.get(), std::move(serial_override));
|
||||
wmbus = openRawTTY(detected->device.file, 38400, manager, std::move(serial_override));
|
||||
break;
|
||||
case DEVICE_RTLWMBUS:
|
||||
{
|
||||
string command;
|
||||
if (!settings.override_tty)
|
||||
if (!detected->override_tty)
|
||||
{
|
||||
command = config->device_extra;
|
||||
command = detected->device.suffix;
|
||||
string freq = "868.95M";
|
||||
string prefix = "";
|
||||
if (isFrequency(command)) {
|
||||
|
@ -226,7 +203,7 @@ bool startUsingCommandline(Configuration *config)
|
|||
}
|
||||
verbose("(rtlwmbus) using command: %s\n", command.c_str());
|
||||
}
|
||||
wmbus = openRTLWMBUS(command, manager.get(),
|
||||
wmbus = openRTLWMBUS(command, manager,
|
||||
[command](){
|
||||
warning("(rtlwmbus) child process exited! "
|
||||
"Command was: \"%s\"\n", command.c_str());
|
||||
|
@ -237,9 +214,9 @@ bool startUsingCommandline(Configuration *config)
|
|||
case DEVICE_RTL433:
|
||||
{
|
||||
string command;
|
||||
if (!settings.override_tty)
|
||||
if (!detected->override_tty)
|
||||
{
|
||||
command = config->device_extra;
|
||||
command = detected->device.suffix;
|
||||
string freq = "868.95M";
|
||||
string prefix = "";
|
||||
if (isFrequency(command)) {
|
||||
|
@ -262,7 +239,7 @@ bool startUsingCommandline(Configuration *config)
|
|||
}
|
||||
verbose("(rtl433) using command: %s\n", command.c_str());
|
||||
}
|
||||
wmbus = openRTL433(command, manager.get(),
|
||||
wmbus = openRTL433(command, manager,
|
||||
[command](){
|
||||
warning("(rtl433) child process exited! "
|
||||
"Command was: \"%s\"\n", command.c_str());
|
||||
|
@ -272,20 +249,20 @@ bool startUsingCommandline(Configuration *config)
|
|||
}
|
||||
case DEVICE_CUL:
|
||||
{
|
||||
verbose("(cul) on %s\n", settings.devicefile.c_str());
|
||||
wmbus = openCUL(settings.devicefile, manager.get(), std::move(serial_override));
|
||||
verbose("(cul) on %s\n", detected->device.file.c_str());
|
||||
wmbus = openCUL(detected->device.file, manager, std::move(serial_override));
|
||||
break;
|
||||
}
|
||||
case DEVICE_D1TC:
|
||||
{
|
||||
verbose("(d1tc) on %s\n", settings.devicefile.c_str());
|
||||
wmbus = openD1TC(settings.devicefile, manager.get(), std::move(serial_override));
|
||||
verbose("(d1tc) on %s\n", detected->device.file.c_str());
|
||||
wmbus = openD1TC(detected->device.file, manager, std::move(serial_override));
|
||||
break;
|
||||
}
|
||||
case DEVICE_WMB13U:
|
||||
{
|
||||
verbose("(wmb13u) on %s\n", settings.devicefile.c_str());
|
||||
wmbus = openWMB13U(settings.devicefile, manager.get(), std::move(serial_override));
|
||||
verbose("(wmb13u) on %s\n", detected->device.file.c_str());
|
||||
wmbus = openWMB13U(detected->device.file, manager, std::move(serial_override));
|
||||
break;
|
||||
}
|
||||
case DEVICE_UNKNOWN:
|
||||
|
@ -302,127 +279,301 @@ bool startUsingCommandline(Configuration *config)
|
|||
if (lmcr.type != LinkModeCalculationResultType::Success) {
|
||||
error("%s\n", lmcr.msg.c_str());
|
||||
}
|
||||
return wmbus;
|
||||
}
|
||||
|
||||
auto output = unique_ptr<Printer>(new Printer(config->json, config->fields,
|
||||
config->separator, config->meterfiles, config->meterfiles_dir,
|
||||
config->use_logfile, config->logfile,
|
||||
config->telegram_shells,
|
||||
config->meterfiles_action == MeterFileType::Overwrite,
|
||||
config->meterfiles_naming,
|
||||
config->meterfiles_timestamp));
|
||||
vector<unique_ptr<Meter>> meters;
|
||||
|
||||
if (config->meters.size() > 0)
|
||||
void setupLogFile(Configuration *config)
|
||||
{
|
||||
if (config->use_logfile)
|
||||
{
|
||||
for (auto &m : config->meters)
|
||||
{
|
||||
const char *keymsg = (m.key[0] == 0) ? "not-encrypted" : "encrypted";
|
||||
switch (toMeterType(m.type))
|
||||
{
|
||||
#define X(mname,link,info,type,cname) \
|
||||
case MeterType::type: \
|
||||
meters.push_back(create##cname(wmbus.get(), m)); \
|
||||
verbose("(wmbusmeters) configured \"%s\" \"" #mname "\" \"%s\" %s\n", \
|
||||
m.name.c_str(), m.id.c_str(), keymsg); \
|
||||
meters.back()->addConversions(config->conversions); \
|
||||
break;
|
||||
LIST_OF_METERS
|
||||
#undef X
|
||||
case MeterType::UNKNOWN:
|
||||
error("No such meter type \"%s\"\n", m.type.c_str());
|
||||
break;
|
||||
verbose("(wmbusmeters) using log file %s\n", config->logfile.c_str());
|
||||
bool ok = enableLogfile(config->logfile, config->daemon);
|
||||
if (!ok) {
|
||||
if (config->daemon) {
|
||||
warning("Could not open log file, will use syslog instead.\n");
|
||||
} else {
|
||||
error("Could not open log file.\n");
|
||||
}
|
||||
|
||||
if (config->list_shell_envs)
|
||||
{
|
||||
string ignore1, ignore2, ignore3;
|
||||
vector<string> envs;
|
||||
Telegram t;
|
||||
meters.back()->printMeter(&t,
|
||||
&ignore1,
|
||||
&ignore2, config->separator,
|
||||
&ignore3,
|
||||
&envs,
|
||||
&config->jsons,
|
||||
&config->selected_fields);
|
||||
printf("Environment variables provided to shell for meter %s:\n", m.type.c_str());
|
||||
for (auto &e : envs) {
|
||||
int p = e.find('=');
|
||||
string key = e.substr(0,p);
|
||||
printf("%s\n", key.c_str());
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (config->list_fields)
|
||||
{
|
||||
printf("Fields produced by meter %s:\n", m.type.c_str());
|
||||
printf("id\n");
|
||||
printf("name\n");
|
||||
printf("timestamp\n");
|
||||
for (auto &f : meters.back()->fields())
|
||||
{
|
||||
printf("%s\n", f.c_str());
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
meters.back()->onUpdate([&](Telegram*t,Meter* meter)
|
||||
{
|
||||
output->print(t,meter,&config->jsons,&config->selected_fields);
|
||||
});
|
||||
meters.back()->onUpdate([&](Telegram*t, Meter* meter)
|
||||
{
|
||||
oneshotCheck(config, manager.get(), t, meter, meters);
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
notice("No meters configured. Printing id:s of all telegrams heard!\n\n");
|
||||
disableLogfile();
|
||||
}
|
||||
}
|
||||
|
||||
wmbus->onTelegram([](vector<uchar> frame){
|
||||
Telegram t;
|
||||
MeterKeys mk;
|
||||
t.parserNoWarnings(); // Try a best effort parse, do not print any warnings.
|
||||
t.parse(frame, &mk);
|
||||
t.print();
|
||||
t.explainParse("(wmbus)",0);
|
||||
logTelegram("(wmbus)", t.frame, 0, 0);
|
||||
return true;
|
||||
});
|
||||
void setupMeters(Configuration *config, vector<unique_ptr<Meter>> *meters)
|
||||
{
|
||||
for (auto &m : config->meters)
|
||||
{
|
||||
const char *keymsg = (m.key[0] == 0) ? "not-encrypted" : "encrypted";
|
||||
switch (toMeterType(m.type))
|
||||
{
|
||||
#define X(mname,link,info,type,cname) \
|
||||
case MeterType::type: \
|
||||
meters->push_back(create##cname(m)); \
|
||||
verbose("(wmbusmeters) configured \"%s\" \"" #mname "\" \"%s\" %s\n", \
|
||||
m.name.c_str(), m.id.c_str(), keymsg); \
|
||||
meters->back()->addConversions(config->conversions); \
|
||||
break;
|
||||
LIST_OF_METERS
|
||||
#undef X
|
||||
case MeterType::UNKNOWN:
|
||||
error("No such meter type \"%s\"\n", m.type.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
if (config->list_shell_envs)
|
||||
{
|
||||
string ignore1, ignore2, ignore3;
|
||||
vector<string> envs;
|
||||
Telegram t;
|
||||
meters->back()->printMeter(&t,
|
||||
&ignore1,
|
||||
&ignore2, config->separator,
|
||||
&ignore3,
|
||||
&envs,
|
||||
&config->jsons,
|
||||
&config->selected_fields);
|
||||
printf("Environment variables provided to shell for meter %s:\n", m.type.c_str());
|
||||
for (auto &e : envs) {
|
||||
int p = e.find('=');
|
||||
string key = e.substr(0,p);
|
||||
printf("%s\n", key.c_str());
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (config->list_fields)
|
||||
{
|
||||
printf("Fields produced by meter %s:\n", m.type.c_str());
|
||||
printf("id\n");
|
||||
printf("name\n");
|
||||
printf("timestamp\n");
|
||||
for (auto &f : meters->back()->fields())
|
||||
{
|
||||
printf("%s\n", f.c_str());
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void attachMetersToPrinter(Configuration *config, vector<unique_ptr<Meter>> *meters, Printer *printer)
|
||||
{
|
||||
for (auto &meter : *meters)
|
||||
{
|
||||
meter->onUpdate([&](Telegram*t,Meter* meter)
|
||||
{
|
||||
printer->print(t,meter,&config->jsons,&config->selected_fields);
|
||||
});
|
||||
meter->onUpdate([&](Telegram*t, Meter* meter)
|
||||
{
|
||||
oneshotCheck(config, manager_.get(), t, meter, meters);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void detectAndConfigureWMBusDevices(Configuration *config, SerialCommunicationManager *manager, vector<unique_ptr<WMBus>> *devices)
|
||||
{
|
||||
trace("(trace main) checking for dead wmbus devices...\n");
|
||||
|
||||
LOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
|
||||
vector<WMBus*> not_working;
|
||||
for (auto &w : devices_)
|
||||
{
|
||||
if (!w->isWorking())
|
||||
{
|
||||
not_working.push_back(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
wmbus->setMeters(&meters);
|
||||
wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
|
||||
manager->startEventLoop();
|
||||
wmbus->setLinkModes(config->listen_to_link_modes);
|
||||
string using_link_modes = wmbus->getLinkModes().hr();
|
||||
|
||||
verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
|
||||
|
||||
if (settings.type == DEVICE_SIMULATOR) {
|
||||
wmbus->simulate();
|
||||
for (auto w : not_working)
|
||||
{
|
||||
auto i = devices_.begin();
|
||||
while (i != devices_.end())
|
||||
{
|
||||
if (w == (*i).get())
|
||||
{
|
||||
// The erased unique_ptr will delete the WMBus object.
|
||||
devices_.erase(i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->daemon) {
|
||||
if (devices_.size() == 0)
|
||||
{
|
||||
if (!printed_warning_)
|
||||
{
|
||||
info("(main) no wmbus devices detected.\n");
|
||||
printed_warning_ = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_warning_ = false;
|
||||
}
|
||||
|
||||
UNLOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
|
||||
|
||||
trace("(trace main) checking for new wmbus devices...\n");
|
||||
|
||||
vector<string> ds = manager->listSerialDevices();
|
||||
for (string& device : ds)
|
||||
{
|
||||
trace("(trace main) serial device %s\n", device.c_str());
|
||||
SerialDevice *sd = manager->lookup(device);
|
||||
if (sd == NULL)
|
||||
{
|
||||
debug("(main) device %s not currently used, detect contents...\n", device.c_str());
|
||||
// This serial device is not in use.
|
||||
Detected detected = detectImstAmberCul(device, "", manager);
|
||||
if (detected.type != DEVICE_UNKNOWN)
|
||||
{
|
||||
info("(main) detected %s on %s\n", toString(detected.type), device.c_str());
|
||||
LOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
|
||||
unique_ptr<WMBus> w = createWMBusDeviceFrom(&detected, config, manager);
|
||||
devices->push_back(std::move(w));
|
||||
WMBus *wmbus = devices->back().get();
|
||||
UNLOCK("(main)", "detectAndConfigureWMBusDevices", devices_lock_);
|
||||
wmbus->setLinkModes(config->listen_to_link_modes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Printer> createPrinter(Configuration *config)
|
||||
{
|
||||
return unique_ptr<Printer>(new Printer(config->json, config->fields,
|
||||
config->separator, config->meterfiles, config->meterfiles_dir,
|
||||
config->use_logfile, config->logfile,
|
||||
config->telegram_shells,
|
||||
config->meterfiles_action == MeterFileType::Overwrite,
|
||||
config->meterfiles_naming,
|
||||
config->meterfiles_timestamp));
|
||||
}
|
||||
|
||||
void logStartInformation(Configuration *config)
|
||||
{
|
||||
verbose("(wmbusmeters) version: " VERSION "\n");
|
||||
|
||||
if (config->exitafter != 0) {
|
||||
verbose("(config) wmbusmeters will exit after %d seconds\n", config->exitafter);
|
||||
}
|
||||
|
||||
if (config->reopenafter != 0) {
|
||||
verbose("(config) wmbusmeters close/open the wmbus dongle fd after every %d seconds\n", config->reopenafter);
|
||||
}
|
||||
|
||||
if (config->meterfiles) {
|
||||
verbose("(config) store meter files in: \"%s\"\n", config->meterfiles_dir.c_str());
|
||||
}
|
||||
|
||||
for (auto &device : config->wmbus_devices)
|
||||
{
|
||||
verbose("(config) using device: %s %s\n", device.file.c_str(), device.suffix.c_str());
|
||||
}
|
||||
verbose("(config) number of meters: %d\n", config->meters.size());
|
||||
}
|
||||
|
||||
bool start(Configuration *config)
|
||||
{
|
||||
// Configure where the logging information should end up.
|
||||
setupLogFile(config);
|
||||
|
||||
// Configure settings.
|
||||
warningSilenced(config->silence);
|
||||
verboseEnabled(config->verbose);
|
||||
logTelegramsEnabled(config->logtelegrams);
|
||||
debugEnabled(config->debug);
|
||||
internalTestingEnabled(config->internaltesting);
|
||||
traceEnabled(config->trace);
|
||||
stderrEnabled(config->use_stderr);
|
||||
setAlarmShells(config->alarm_shells);
|
||||
|
||||
logStartInformation(config);
|
||||
|
||||
// Create the manager monitoring all filedescriptors and invoking callbacks.
|
||||
manager_ = createSerialCommunicationManager(config->exitafter, config->reopenafter);
|
||||
// If our software unexpectedly exits, then stop the manager, to try
|
||||
// to achive a nice shutdown.
|
||||
onExit(call(manager_.get(),stop));
|
||||
|
||||
// Create the printer object that knows how to translate
|
||||
// telegrams into json, fields that are written into log files
|
||||
// or sent to shell invocations.
|
||||
printer_ = createPrinter(config);
|
||||
|
||||
// Create the Meter objects from the configuration.
|
||||
setupMeters(config, &meters_);
|
||||
// Attach a received-telegram-callback from the meter and
|
||||
// attach it to the printer.
|
||||
attachMetersToPrinter(config, &meters_, printer_.get());
|
||||
|
||||
manager_->startEventLoop();
|
||||
|
||||
// Detect and initialize any devices.
|
||||
// Future changes are triggered through this callback.
|
||||
printed_warning_ = true;
|
||||
detectAndConfigureWMBusDevices(config, manager_.get(), &devices_);
|
||||
|
||||
if (devices_.size() == 0)
|
||||
{
|
||||
info("(main) no wmbus devices detected.\n");
|
||||
}
|
||||
|
||||
// Every 2 seconds, perform the exact same call again and again.
|
||||
manager_->startRegularCallback("device_detector",
|
||||
2,
|
||||
[&](){
|
||||
detectAndConfigureWMBusDevices(config, manager_.get(), &devices_);
|
||||
});
|
||||
|
||||
//wmbus->setMeters(&meters);
|
||||
//wmbus->setTimeout(config->alarm_timeout, config->alarm_expected_activity);
|
||||
//wmbus->setLinkModes(config->listen_to_link_modes);
|
||||
//string using_link_modes = wmbus->getLinkModes().hr();
|
||||
|
||||
//verbose("(config) listen to link modes: %s\n", using_link_modes.c_str());
|
||||
|
||||
//if (detected.type == DEVICE_SIMULATOR) {
|
||||
//wmbus->simulate();
|
||||
//}
|
||||
if (config->daemon)
|
||||
{
|
||||
notice("(wmbusmeters) waiting for telegrams\n");
|
||||
}
|
||||
|
||||
manager->waitForStop();
|
||||
if (config->daemon) {
|
||||
// This thread now sleeps waiting for the serial communication manager to stop.
|
||||
// The manager has already started one thread that performs select and then callbacks
|
||||
// to decoding the telegrams, finally invoking the printer.
|
||||
// The regular callback invoked to detect changes in the wmbus devices and
|
||||
// the alarm checks, is started in a separate thread.
|
||||
manager_->waitForStop();
|
||||
|
||||
if (config->daemon)
|
||||
{
|
||||
notice("(wmbusmeters) shutting down\n");
|
||||
}
|
||||
|
||||
// Destroy any remaining allocated objects.
|
||||
devices_.clear();
|
||||
meters_.clear();
|
||||
printer_.reset();
|
||||
manager_.reset();
|
||||
|
||||
restoreSignalHandlers();
|
||||
return gotHupped();
|
||||
}
|
||||
|
||||
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> &meters)
|
||||
void oneshotCheck(Configuration *config, SerialCommunicationManager *manager, Telegram *t, Meter *meter, vector<unique_ptr<Meter>> *meters)
|
||||
{
|
||||
if (!config->oneshot) return;
|
||||
|
||||
for (auto &m : meters) {
|
||||
for (auto &m : *meters)
|
||||
{
|
||||
if (m->numUpdates() == 0) return;
|
||||
}
|
||||
// All meters have received at least one update! Stop!
|
||||
|
@ -507,7 +658,7 @@ void startUsingConfigFiles(string root, bool is_daemon, string device_override,
|
|||
{
|
||||
unique_ptr<Configuration> config = loadConfiguration(root, device_override, listento_override);
|
||||
config->daemon = is_daemon;
|
||||
restart = startUsingCommandline(config.get());
|
||||
restart = start(config.get());
|
||||
if (restart)
|
||||
{
|
||||
notice("(wmbusmeters) HUP received, restarting and reloading config files.\n");
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include"util.h"
|
||||
|
||||
struct MeterAmiplus : public virtual ElectricityMeter, public virtual MeterCommonImplementation {
|
||||
MeterAmiplus(WMBus *bus, MeterInfo &mi);
|
||||
MeterAmiplus(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
double currentPowerConsumption(Unit u);
|
||||
|
@ -41,8 +41,8 @@ private:
|
|||
string device_date_time_;
|
||||
};
|
||||
|
||||
MeterAmiplus::MeterAmiplus(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::AMIPLUS, 0)
|
||||
MeterAmiplus::MeterAmiplus(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::AMIPLUS, 0)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -86,9 +86,9 @@ MeterAmiplus::MeterAmiplus(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<ElectricityMeter> createAmiplus(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<ElectricityMeter> createAmiplus(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<ElectricityMeter>(new MeterAmiplus(bus, mi));
|
||||
return unique_ptr<ElectricityMeter>(new MeterAmiplus(mi));
|
||||
}
|
||||
|
||||
double MeterAmiplus::totalEnergyConsumption(Unit u)
|
||||
|
|
|
@ -25,7 +25,7 @@ using namespace std;
|
|||
|
||||
struct MeterApator08 : public virtual WaterMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MeterApator08(WMBus *bus, MeterInfo &mi);
|
||||
MeterApator08(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -38,13 +38,13 @@ private:
|
|||
double total_water_consumption_m3_ {};
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createApator08(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createApator08(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterApator08(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterApator08(mi));
|
||||
}
|
||||
|
||||
MeterApator08::MeterApator08(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::APATOR08, 0x8614) // Not compliant! Will decode to APT.
|
||||
MeterApator08::MeterApator08(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::APATOR08, 0x8614) // Not compliant! Will decode to APT.
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterApator162 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterApator162(WMBus *bus, MeterInfo &mi);
|
||||
MeterApator162(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -37,13 +37,13 @@ private:
|
|||
double total_water_consumption_m3_ {};
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createApator162(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createApator162(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterApator162(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterApator162(mi));
|
||||
}
|
||||
|
||||
MeterApator162::MeterApator162(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::APATOR162, MANUFACTURER_APA)
|
||||
MeterApator162::MeterApator162(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::APATOR162, MANUFACTURER_APA)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include"wmbus_utils.h"
|
||||
|
||||
struct MeterCMa12w : public virtual TempHygroMeter, public virtual MeterCommonImplementation {
|
||||
MeterCMa12w(WMBus *bus, MeterInfo &mi);
|
||||
MeterCMa12w(MeterInfo &mi);
|
||||
|
||||
double currentTemperature(Unit u);
|
||||
double currentRelativeHumidity();
|
||||
|
@ -35,8 +35,8 @@ private:
|
|||
double average_temperature_1h_c_;
|
||||
};
|
||||
|
||||
MeterCMa12w::MeterCMa12w(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::CMA12W, MANUFACTURER_ELV)
|
||||
MeterCMa12w::MeterCMa12w(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::CMA12W, MANUFACTURER_ELV)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -57,9 +57,9 @@ MeterCMa12w::MeterCMa12w(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<TempHygroMeter> createCMa12w(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<TempHygroMeter> createCMa12w(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<TempHygroMeter>(new MeterCMa12w(bus, mi));
|
||||
return unique_ptr<TempHygroMeter>(new MeterCMa12w(mi));
|
||||
}
|
||||
|
||||
double MeterCMa12w::currentTemperature(Unit u)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
struct MeterEBZWMBE : public virtual ElectricityMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MeterEBZWMBE(WMBus *bus, MeterInfo &mi);
|
||||
MeterEBZWMBE(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
double currentPowerConsumption(Unit u);
|
||||
|
@ -44,8 +44,8 @@ private:
|
|||
string customer_;
|
||||
};
|
||||
|
||||
MeterEBZWMBE::MeterEBZWMBE(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::EBZWMBE, MANUFACTURER_EBZ)
|
||||
MeterEBZWMBE::MeterEBZWMBE(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::EBZWMBE, MANUFACTURER_EBZ)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV);
|
||||
|
||||
|
@ -87,9 +87,9 @@ MeterEBZWMBE::MeterEBZWMBE(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<ElectricityMeter> createEBZWMBE(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<ElectricityMeter> createEBZWMBE(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<ElectricityMeter>(new MeterEBZWMBE(bus, mi));
|
||||
return unique_ptr<ElectricityMeter>(new MeterEBZWMBE(mi));
|
||||
}
|
||||
|
||||
double MeterEBZWMBE::totalEnergyConsumption(Unit u)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
struct MeterEHZP : public virtual ElectricityMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MeterEHZP(WMBus *bus, MeterInfo &mi);
|
||||
MeterEHZP(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
double currentPowerConsumption(Unit u);
|
||||
|
@ -42,8 +42,8 @@ private:
|
|||
double on_time_h_ {};
|
||||
};
|
||||
|
||||
MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::EHZP, MANUFACTURER_EMH)
|
||||
MeterEHZP::MeterEHZP(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::EHZP, MANUFACTURER_EMH)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV);
|
||||
|
||||
|
@ -75,9 +75,9 @@ MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<ElectricityMeter> createEHZP(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<ElectricityMeter> createEHZP(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<ElectricityMeter>(new MeterEHZP(bus, mi));
|
||||
return unique_ptr<ElectricityMeter>(new MeterEHZP(mi));
|
||||
}
|
||||
|
||||
double MeterEHZP::totalEnergyConsumption(Unit u)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
struct MeterESYSWM : public virtual ElectricityMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MeterESYSWM(WMBus *bus, MeterInfo &mi);
|
||||
MeterESYSWM(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
double totalEnergyConsumptionTariff1(Unit u);
|
||||
|
@ -61,8 +61,8 @@ private:
|
|||
string fabrication_no_;
|
||||
};
|
||||
|
||||
MeterESYSWM::MeterESYSWM(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::ESYSWM, MANUFACTURER_ESY)
|
||||
MeterESYSWM::MeterESYSWM(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::ESYSWM, MANUFACTURER_ESY)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_NO_IV);
|
||||
|
||||
|
@ -134,9 +134,9 @@ MeterESYSWM::MeterESYSWM(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<ElectricityMeter> createESYSWM(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<ElectricityMeter> createESYSWM(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<ElectricityMeter>(new MeterESYSWM(bus, mi));
|
||||
return unique_ptr<ElectricityMeter>(new MeterESYSWM(mi));
|
||||
}
|
||||
|
||||
double MeterESYSWM::totalEnergyConsumption(Unit u)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include"wmbus_utils.h"
|
||||
|
||||
struct MeterEurisII : public virtual HeatCostMeter, public virtual MeterCommonImplementation {
|
||||
MeterEurisII(WMBus *bus, MeterInfo &mi);
|
||||
MeterEurisII(MeterInfo &mi);
|
||||
|
||||
double currentConsumption(Unit u);
|
||||
string setDate();
|
||||
|
@ -41,8 +41,8 @@ private:
|
|||
uint16_t error_flags_;
|
||||
};
|
||||
|
||||
MeterEurisII::MeterEurisII(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::EURISII, MANUFACTURER_INE)
|
||||
MeterEurisII::MeterEurisII(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::EURISII, MANUFACTURER_INE)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -84,9 +84,9 @@ MeterEurisII::MeterEurisII(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<HeatCostMeter> createEurisII(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<HeatCostMeter> createEurisII(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<HeatCostMeter>(new MeterEurisII(bus, mi));
|
||||
return unique_ptr<HeatCostMeter>(new MeterEurisII(mi));
|
||||
}
|
||||
|
||||
double MeterEurisII::currentConsumption(Unit u)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
struct MeterFHKVDataIII : public virtual HeatCostMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MeterFHKVDataIII(WMBus *bus, MeterInfo &mi);
|
||||
MeterFHKVDataIII(MeterInfo &mi);
|
||||
|
||||
double currentPeriodEnergyConsumption(Unit u);
|
||||
string currentPeriodDate();
|
||||
|
@ -49,14 +49,14 @@ struct MeterFHKVDataIII : public virtual HeatCostMeter, public virtual MeterComm
|
|||
double temp_radiator_ {};
|
||||
};
|
||||
|
||||
unique_ptr<HeatCostMeter> createFHKVDataIII(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<HeatCostMeter> createFHKVDataIII(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<HeatCostMeter>(new MeterFHKVDataIII(bus, mi));
|
||||
return unique_ptr<HeatCostMeter>(new MeterFHKVDataIII(mi));
|
||||
}
|
||||
|
||||
|
||||
MeterFHKVDataIII::MeterFHKVDataIII(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::FHKVDATAIII, MANUFACTURER_TCH)
|
||||
MeterFHKVDataIII::MeterFHKVDataIII(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::FHKVDATAIII, MANUFACTURER_TCH)
|
||||
{
|
||||
addMedia(0x80); // T telegrams
|
||||
addExpectedVersion(0x69);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterHydrodigit : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterHydrodigit(WMBus *bus, MeterInfo &mi);
|
||||
MeterHydrodigit(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -38,13 +38,13 @@ private:
|
|||
string meter_datetime_;
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createHydrodigit(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createHydrodigit(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterHydrodigit(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterHydrodigit(mi));
|
||||
}
|
||||
|
||||
MeterHydrodigit::MeterHydrodigit(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::HYDRODIGIT, MANUFACTURER_BMT)
|
||||
MeterHydrodigit::MeterHydrodigit(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::HYDRODIGIT, MANUFACTURER_BMT)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterHydrus : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterHydrus(WMBus *bus, MeterInfo &mi);
|
||||
MeterHydrus(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -44,8 +44,8 @@ private:
|
|||
double flow_temperature_c_ { 127 };
|
||||
};
|
||||
|
||||
MeterHydrus::MeterHydrus(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::HYDRUS, MANUFACTURER_DME)
|
||||
MeterHydrus::MeterHydrus(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::HYDRUS, MANUFACTURER_DME)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -81,9 +81,9 @@ MeterHydrus::MeterHydrus(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createHydrus(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createHydrus(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterHydrus(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterHydrus(mi));
|
||||
}
|
||||
|
||||
void MeterHydrus::processContent(Telegram *t)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterIperl : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterIperl(WMBus *bus, MeterInfo &mi);
|
||||
MeterIperl(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -40,8 +40,8 @@ private:
|
|||
double max_flow_m3h_ {};
|
||||
};
|
||||
|
||||
MeterIperl::MeterIperl(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::IPERL, MANUFACTURER_SEN)
|
||||
MeterIperl::MeterIperl(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::IPERL, MANUFACTURER_SEN)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -64,9 +64,9 @@ MeterIperl::MeterIperl(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createIperl(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createIperl(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterIperl(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterIperl(mi));
|
||||
}
|
||||
|
||||
void MeterIperl::processContent(Telegram *t)
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef struct _izar_alarms {
|
|||
} izar_alarms;
|
||||
|
||||
struct MeterIzar : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterIzar(WMBus *bus, MeterInfo &mi);
|
||||
MeterIzar(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -75,13 +75,13 @@ private:
|
|||
vector<uint32_t> keys;
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createIzar(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createIzar(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterIzar(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterIzar(mi));
|
||||
}
|
||||
|
||||
MeterIzar::MeterIzar(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::IZAR, MANUFACTURER_SAP)
|
||||
MeterIzar::MeterIzar(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::IZAR, MANUFACTURER_SAP)
|
||||
{
|
||||
addManufacturer(MANUFACTURER_DME);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define INFO_CODE_OPEN 0x0055
|
||||
|
||||
struct MeterLansenDW : public virtual DoorWindowDetector, public virtual MeterCommonImplementation {
|
||||
MeterLansenDW(WMBus *bus, MeterInfo &mi);
|
||||
MeterLansenDW(MeterInfo &mi);
|
||||
|
||||
string status();
|
||||
bool open();
|
||||
|
@ -40,8 +40,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
MeterLansenDW::MeterLansenDW(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::LANSENSM, MANUFACTURER_LAS)
|
||||
MeterLansenDW::MeterLansenDW(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::LANSENSM, MANUFACTURER_LAS)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -57,9 +57,9 @@ MeterLansenDW::MeterLansenDW(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<DoorWindowDetector> createLansenDW(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<DoorWindowDetector> createLansenDW(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<DoorWindowDetector>(new MeterLansenDW(bus, mi));
|
||||
return unique_ptr<DoorWindowDetector>(new MeterLansenDW(mi));
|
||||
}
|
||||
|
||||
bool MeterLansenDW::open()
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include"wmbus_utils.h"
|
||||
|
||||
struct MeterLansenPU : public virtual PulseCounter, public virtual MeterCommonImplementation {
|
||||
MeterLansenPU(WMBus *bus, MeterInfo &mi);
|
||||
MeterLansenPU(MeterInfo &mi);
|
||||
|
||||
double counterA();
|
||||
double counterB();
|
||||
|
@ -38,8 +38,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
MeterLansenPU::MeterLansenPU(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::LANSENPU, MANUFACTURER_LAS)
|
||||
MeterLansenPU::MeterLansenPU(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::LANSENPU, MANUFACTURER_LAS)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -60,9 +60,9 @@ MeterLansenPU::MeterLansenPU(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<PulseCounter> createLansenPU(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<PulseCounter> createLansenPU(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<PulseCounter>(new MeterLansenPU(bus, mi));
|
||||
return unique_ptr<PulseCounter>(new MeterLansenPU(mi));
|
||||
}
|
||||
|
||||
double MeterLansenPU::counterA()
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define INFO_CODE_TEST 0x0008
|
||||
|
||||
struct MeterLansenSM : public virtual SmokeDetector, public virtual MeterCommonImplementation {
|
||||
MeterLansenSM(WMBus *bus, MeterInfo &mi);
|
||||
MeterLansenSM(MeterInfo &mi);
|
||||
|
||||
string status();
|
||||
bool smokeDetected();
|
||||
|
@ -40,8 +40,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
MeterLansenSM::MeterLansenSM(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::LANSENSM, MANUFACTURER_LAS)
|
||||
MeterLansenSM::MeterLansenSM(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::LANSENSM, MANUFACTURER_LAS)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -57,9 +57,9 @@ MeterLansenSM::MeterLansenSM(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<SmokeDetector> createLansenSM(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<SmokeDetector> createLansenSM(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<SmokeDetector>(new MeterLansenSM(bus, mi));
|
||||
return unique_ptr<SmokeDetector>(new MeterLansenSM(mi));
|
||||
}
|
||||
|
||||
bool MeterLansenSM::smokeDetected()
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include"wmbus_utils.h"
|
||||
|
||||
struct MeterLansenTH : public virtual TempHygroMeter, public virtual MeterCommonImplementation {
|
||||
MeterLansenTH(WMBus *bus, MeterInfo &mi);
|
||||
MeterLansenTH(MeterInfo &mi);
|
||||
|
||||
double currentTemperature(Unit u);
|
||||
double currentRelativeHumidity();
|
||||
|
@ -39,8 +39,8 @@ private:
|
|||
double average_relative_humidity_24h_rh_ {};
|
||||
};
|
||||
|
||||
MeterLansenTH::MeterLansenTH(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::LANSENTH, MANUFACTURER_LAS)
|
||||
MeterLansenTH::MeterLansenTH(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::LANSENTH, MANUFACTURER_LAS)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -81,9 +81,9 @@ MeterLansenTH::MeterLansenTH(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<TempHygroMeter> createLansenTH(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<TempHygroMeter> createLansenTH(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<TempHygroMeter>(new MeterLansenTH(bus, mi));
|
||||
return unique_ptr<TempHygroMeter>(new MeterLansenTH(mi));
|
||||
}
|
||||
|
||||
double MeterLansenTH::currentTemperature(Unit u)
|
||||
|
|
|
@ -26,7 +26,7 @@ using namespace std;
|
|||
|
||||
struct MKRadio3 : public virtual WaterMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MKRadio3(WMBus *bus, MeterInfo &mi);
|
||||
MKRadio3(MeterInfo &mi);
|
||||
|
||||
double totalWaterConsumption(Unit u);
|
||||
bool hasTotalWaterConsumption();
|
||||
|
@ -40,8 +40,8 @@ private:
|
|||
double target_water_consumption_m3_ {};
|
||||
};
|
||||
|
||||
MKRadio3::MKRadio3(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::MKRADIO3, MANUFACTURER_TCH)
|
||||
MKRadio3::MKRadio3(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::MKRADIO3, MANUFACTURER_TCH)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -63,9 +63,9 @@ MKRadio3::MKRadio3(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createMKRadio3(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createMKRadio3(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MKRadio3(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MKRadio3(mi));
|
||||
}
|
||||
|
||||
void MKRadio3::processContent(Telegram *t)
|
||||
|
|
|
@ -39,7 +39,7 @@ using namespace std;
|
|||
#define INFO_CODE_BURST_SHIFT (4+9)
|
||||
|
||||
struct MeterMultical21 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterMultical21(WMBus *bus, MeterInfo &mi, MeterType mt);
|
||||
MeterMultical21(MeterInfo &mi, MeterType mt);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -91,8 +91,8 @@ private:
|
|||
int expected_version_ {}; // 0x1b for Multical21 and 0x1d for FlowIQ3100
|
||||
};
|
||||
|
||||
MeterMultical21::MeterMultical21(WMBus *bus, MeterInfo &mi, MeterType mt) :
|
||||
MeterCommonImplementation(bus, mi, mt, MANUFACTURER_KAM)
|
||||
MeterMultical21::MeterMultical21(MeterInfo &mi, MeterType mt) :
|
||||
MeterCommonImplementation(mi, mt, MANUFACTURER_KAM)
|
||||
{
|
||||
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
|
||||
|
||||
|
@ -219,22 +219,22 @@ bool MeterMultical21::hasExternalTemperature()
|
|||
return has_external_temperature_;
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createMulticalWaterMeter(WMBus *bus, MeterInfo &mi, MeterType mt)
|
||||
unique_ptr<WaterMeter> createMulticalWaterMeter(MeterInfo &mi, MeterType mt)
|
||||
{
|
||||
if (mt != MeterType::MULTICAL21 && mt != MeterType::FLOWIQ3100) {
|
||||
error("Internal error! Not a proper meter type when creating a multical21 style meter.\n");
|
||||
}
|
||||
return unique_ptr<WaterMeter>(new MeterMultical21(bus,mi,mt));
|
||||
return unique_ptr<WaterMeter>(new MeterMultical21(mi,mt));
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createMultical21(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createMultical21(MeterInfo &mi)
|
||||
{
|
||||
return createMulticalWaterMeter(bus, mi, MeterType::MULTICAL21);
|
||||
return createMulticalWaterMeter(mi, MeterType::MULTICAL21);
|
||||
}
|
||||
|
||||
unique_ptr<WaterMeter> createFlowIQ3100(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createFlowIQ3100(MeterInfo &mi)
|
||||
{
|
||||
return createMulticalWaterMeter(bus, mi, MeterType::FLOWIQ3100);
|
||||
return createMulticalWaterMeter(mi, MeterType::FLOWIQ3100);
|
||||
}
|
||||
|
||||
void MeterMultical21::processContent(Telegram *t)
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define INFO_CODE_VOLTAGE_TOO_LOW 128
|
||||
|
||||
struct MeterMultical302 : public virtual HeatMeter, public virtual MeterCommonImplementation {
|
||||
MeterMultical302(WMBus *bus, MeterInfo &mi);
|
||||
MeterMultical302(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
double targetEnergyConsumption(Unit u);
|
||||
|
@ -51,8 +51,8 @@ private:
|
|||
string target_date_ {};
|
||||
};
|
||||
|
||||
MeterMultical302::MeterMultical302(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::MULTICAL302, MANUFACTURER_KAM)
|
||||
MeterMultical302::MeterMultical302(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::MULTICAL302, MANUFACTURER_KAM)
|
||||
{
|
||||
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
|
||||
|
||||
|
@ -92,8 +92,8 @@ MeterMultical302::MeterMultical302(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<HeatMeter> createMultical302(WMBus *bus, MeterInfo &mi) {
|
||||
return unique_ptr<HeatMeter>(new MeterMultical302(bus, mi));
|
||||
unique_ptr<HeatMeter> createMultical302(MeterInfo &mi) {
|
||||
return unique_ptr<HeatMeter>(new MeterMultical302(mi));
|
||||
}
|
||||
|
||||
double MeterMultical302::totalEnergyConsumption(Unit u)
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#define INFO_CODE_TEMP_DIFF_WRONG_POLARITY 128
|
||||
|
||||
struct MeterMultical403 : public virtual HeatMeter, public virtual MeterCommonImplementation {
|
||||
MeterMultical403(WMBus *bus, MeterInfo &mi);
|
||||
MeterMultical403(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
string status();
|
||||
|
@ -60,8 +60,8 @@ private:
|
|||
string target_date_ {};
|
||||
};
|
||||
|
||||
MeterMultical403::MeterMultical403(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::MULTICAL403, MANUFACTURER_KAM)
|
||||
MeterMultical403::MeterMultical403(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::MULTICAL403, MANUFACTURER_KAM)
|
||||
{
|
||||
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
|
||||
|
||||
|
@ -108,8 +108,8 @@ MeterMultical403::MeterMultical403(WMBus *bus, MeterInfo &mi) :
|
|||
true, true);
|
||||
}
|
||||
|
||||
unique_ptr<HeatMeter> createMultical403(WMBus *bus, MeterInfo &mi) {
|
||||
return unique_ptr<HeatMeter>(new MeterMultical403(bus, mi));
|
||||
unique_ptr<HeatMeter> createMultical403(MeterInfo &mi) {
|
||||
return unique_ptr<HeatMeter>(new MeterMultical403(mi));
|
||||
}
|
||||
|
||||
double MeterMultical403::totalEnergyConsumption(Unit u)
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include"util.h"
|
||||
|
||||
struct MeterOmnipower : public virtual ElectricityMeter, public virtual MeterCommonImplementation {
|
||||
MeterOmnipower(WMBus *bus, MeterInfo &mi);
|
||||
MeterOmnipower(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
|
||||
|
@ -34,13 +34,13 @@ private:
|
|||
double total_energy_kwh_ {};
|
||||
};
|
||||
|
||||
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<ElectricityMeter> createOmnipower(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<ElectricityMeter>(new MeterOmnipower(bus, mi));
|
||||
return unique_ptr<ElectricityMeter>(new MeterOmnipower(mi));
|
||||
}
|
||||
|
||||
MeterOmnipower::MeterOmnipower(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::OMNIPOWER, MANUFACTURER_KAM)
|
||||
MeterOmnipower::MeterOmnipower(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::OMNIPOWER, MANUFACTURER_KAM)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterQ400 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterQ400(WMBus *bus, MeterInfo &mi);
|
||||
MeterQ400(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -42,13 +42,13 @@ private:
|
|||
double consumption_at_set_date_m3_ {};
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createQ400(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createQ400(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterQ400(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterQ400(mi));
|
||||
}
|
||||
|
||||
MeterQ400::MeterQ400(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::Q400, MANUFACTURER_AXI)
|
||||
MeterQ400::MeterQ400(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::Q400, MANUFACTURER_AXI)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include"wmbus_utils.h"
|
||||
|
||||
struct MeterQCaloric : public virtual HeatCostMeter, public virtual MeterCommonImplementation {
|
||||
MeterQCaloric(WMBus *bus, MeterInfo &mi);
|
||||
MeterQCaloric(MeterInfo &mi);
|
||||
|
||||
double currentConsumption(Unit u);
|
||||
string setDate();
|
||||
|
@ -45,8 +45,8 @@ private:
|
|||
string device_date_time_;
|
||||
};
|
||||
|
||||
MeterQCaloric::MeterQCaloric(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::QCALORIC, MANUFACTURER_QDS)
|
||||
MeterQCaloric::MeterQCaloric(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::QCALORIC, MANUFACTURER_QDS)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -102,9 +102,9 @@ MeterQCaloric::MeterQCaloric(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<HeatCostMeter> createQCaloric(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<HeatCostMeter>(new MeterQCaloric(bus, mi));
|
||||
return unique_ptr<HeatCostMeter>(new MeterQCaloric(mi));
|
||||
}
|
||||
|
||||
double MeterQCaloric::currentConsumption(Unit u)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include"wmbus_utils.h"
|
||||
|
||||
struct MeterRfmAmb : public virtual TempHygroMeter, public virtual MeterCommonImplementation {
|
||||
MeterRfmAmb(WMBus *bus, MeterInfo &mi);
|
||||
MeterRfmAmb(MeterInfo &mi);
|
||||
|
||||
double currentTemperature(Unit u);
|
||||
double maximumTemperature(Unit u);
|
||||
|
@ -58,8 +58,8 @@ private:
|
|||
string device_date_time_;
|
||||
};
|
||||
|
||||
MeterRfmAmb::MeterRfmAmb(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::RFMAMB, MANUFACTURER_BMT)
|
||||
MeterRfmAmb::MeterRfmAmb(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::RFMAMB, MANUFACTURER_BMT)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
@ -145,9 +145,9 @@ MeterRfmAmb::MeterRfmAmb(WMBus *bus, MeterInfo &mi) :
|
|||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<TempHygroMeter> createRfmAmb(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<TempHygroMeter> createRfmAmb(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<TempHygroMeter>(new MeterRfmAmb(bus, mi));
|
||||
return unique_ptr<TempHygroMeter>(new MeterRfmAmb(mi));
|
||||
}
|
||||
|
||||
double MeterRfmAmb::currentTemperature(Unit u)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterRfmTX1 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterRfmTX1(WMBus *bus, MeterInfo &mi);
|
||||
MeterRfmTX1(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -38,13 +38,13 @@ private:
|
|||
string meter_datetime_;
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createRfmTX1(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createRfmTX1(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterRfmTX1(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterRfmTX1(mi));
|
||||
}
|
||||
|
||||
MeterRfmTX1::MeterRfmTX1(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::RFMTX1, MANUFACTURER_BMT)
|
||||
MeterRfmTX1::MeterRfmTX1(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::RFMTX1, MANUFACTURER_BMT)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterSupercom587 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterSupercom587(WMBus *bus, MeterInfo &mi);
|
||||
MeterSupercom587(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -37,13 +37,13 @@ private:
|
|||
double total_water_consumption_m3_ {};
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createSupercom587(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterSupercom587(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterSupercom587(mi));
|
||||
}
|
||||
|
||||
MeterSupercom587::MeterSupercom587(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::SUPERCOM587, MANUFACTURER_SON)
|
||||
MeterSupercom587::MeterSupercom587(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::SUPERCOM587, MANUFACTURER_SON)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
struct MeterVario451 : public virtual HeatMeter, public virtual MeterCommonImplementation
|
||||
{
|
||||
MeterVario451(WMBus *bus, MeterInfo &mi);
|
||||
MeterVario451(MeterInfo &mi);
|
||||
|
||||
double totalEnergyConsumption(Unit u);
|
||||
double currentPeriodEnergyConsumption(Unit u);
|
||||
|
@ -40,13 +40,13 @@ struct MeterVario451 : public virtual HeatMeter, public virtual MeterCommonImple
|
|||
double prev_energy_gj_ {};
|
||||
};
|
||||
|
||||
unique_ptr<HeatMeter> createVario451(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<HeatMeter> createVario451(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<HeatMeter>(new MeterVario451(bus, mi));
|
||||
return unique_ptr<HeatMeter>(new MeterVario451(mi));
|
||||
}
|
||||
|
||||
MeterVario451::MeterVario451(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::VARIO451, MANUFACTURER_TCH)
|
||||
MeterVario451::MeterVario451(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::VARIO451, MANUFACTURER_TCH)
|
||||
{
|
||||
addMedia(0x04); // C telegrams
|
||||
addMedia(0xC3); // T telegrams
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace std;
|
||||
|
||||
struct MeterWaterstarM : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterWaterstarM(WMBus *bus, MeterInfo &mi);
|
||||
MeterWaterstarM(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
|
@ -44,13 +44,13 @@ private:
|
|||
string parameter_set_ {};
|
||||
};
|
||||
|
||||
unique_ptr<WaterMeter> createWaterstarM(WMBus *bus, MeterInfo &mi)
|
||||
unique_ptr<WaterMeter> createWaterstarM(MeterInfo &mi)
|
||||
{
|
||||
return unique_ptr<WaterMeter>(new MeterWaterstarM(bus, mi));
|
||||
return unique_ptr<WaterMeter>(new MeterWaterstarM(mi));
|
||||
}
|
||||
|
||||
MeterWaterstarM::MeterWaterstarM(WMBus *bus, MeterInfo &mi) :
|
||||
MeterCommonImplementation(bus, mi, MeterType::WATERSTARM, MANUFACTURER_DWZ)
|
||||
MeterWaterstarM::MeterWaterstarM(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::WATERSTARM, MANUFACTURER_DWZ)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
|
|
|
@ -25,19 +25,20 @@
|
|||
#include<memory.h>
|
||||
#include<time.h>
|
||||
|
||||
MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, MeterInfo &mi,
|
||||
MeterType type, int manufacturer) :
|
||||
type_(type), name_(mi.name), bus_(bus)
|
||||
MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi,
|
||||
MeterType type,
|
||||
int manufacturer) :
|
||||
type_(type), name_(mi.name)
|
||||
{
|
||||
ids_ = splitMatchExpressions(mi.id);
|
||||
if (mi.key.length() > 0)
|
||||
{
|
||||
hex2bin(mi.key, &meter_keys_.confidentiality_key);
|
||||
}
|
||||
if (bus->type() == DEVICE_SIMULATOR)
|
||||
/*if (bus->type() == DEVICE_SIMULATOR)
|
||||
{
|
||||
meter_keys_.simulation = true;
|
||||
}
|
||||
}*/
|
||||
if (manufacturer) {
|
||||
manufacturers_.insert(manufacturer);
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ MeterCommonImplementation::MeterCommonImplementation(WMBus *bus, MeterInfo &mi,
|
|||
for (auto j : mi.jsons) {
|
||||
addJson(j);
|
||||
}
|
||||
MeterCommonImplementation::bus()->onTelegram([this](vector<uchar>input_frame){return this->handleTelegram(input_frame);});
|
||||
//MeterCommonImplementation::bus()->onTelegram([this](vector<uchar>input_frame){return this->handleTelegram(input_frame);});
|
||||
}
|
||||
|
||||
void MeterCommonImplementation::addConversions(std::vector<Unit> cs)
|
||||
|
@ -139,11 +140,6 @@ string MeterCommonImplementation::name()
|
|||
return name_;
|
||||
}
|
||||
|
||||
WMBus *MeterCommonImplementation::bus()
|
||||
{
|
||||
return bus_;
|
||||
}
|
||||
|
||||
void MeterCommonImplementation::onUpdate(function<void(Telegram*,Meter*)> cb)
|
||||
{
|
||||
on_update_.push_back(cb);
|
||||
|
|
63
src/meters.h
63
src/meters.h
|
@ -101,7 +101,6 @@ struct Meter
|
|||
virtual string name() = 0;
|
||||
virtual MeterType type() = 0;
|
||||
virtual vector<int> media() = 0;
|
||||
virtual WMBus *bus() = 0;
|
||||
|
||||
virtual string datetimeOfUpdateHumanReadable() = 0;
|
||||
virtual string datetimeOfUpdateRobot() = 0;
|
||||
|
@ -222,36 +221,36 @@ struct GenericMeter : public virtual Meter {
|
|||
string toMeterName(MeterType mt);
|
||||
MeterType toMeterType(string& type);
|
||||
LinkModeSet toMeterLinkModeSet(string& type);
|
||||
unique_ptr<WaterMeter> createMultical21(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createFlowIQ3100(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<HeatMeter> createMultical302(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<HeatMeter> createMultical403(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<HeatMeter> createVario451(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createWaterstarM(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createAmiplus(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createMKRadio3(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createApator08(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createApator162(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createIperl(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createHydrus(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createHydrodigit(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createIzar(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createQ400(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<HeatCostMeter> createQCaloric(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<HeatCostMeter> createEurisII(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<HeatCostMeter> createFHKVDataIII(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<TempHygroMeter> createLansenTH(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<SmokeDetector> createLansenSM(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<PulseCounter> createLansenPU(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<DoorWindowDetector> createLansenDW(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<TempHygroMeter> createCMa12w(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<TempHygroMeter> createRfmAmb(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createRfmTX1(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createEHZP(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createESYSWM(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createEBZWMBE(WMBus *bus, MeterInfo &m);
|
||||
GenericMeter *createGeneric(WMBus *bus, MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createMultical21(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createFlowIQ3100(MeterInfo &m);
|
||||
unique_ptr<HeatMeter> createMultical302(MeterInfo &m);
|
||||
unique_ptr<HeatMeter> createMultical403(MeterInfo &m);
|
||||
unique_ptr<HeatMeter> createVario451(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createWaterstarM(MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createOmnipower(MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createAmiplus(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createSupercom587(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createMKRadio3(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createApator08(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createApator162(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createIperl(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createHydrus(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createHydrodigit(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createIzar(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createQ400(MeterInfo &m);
|
||||
unique_ptr<HeatCostMeter> createQCaloric(MeterInfo &m);
|
||||
unique_ptr<HeatCostMeter> createEurisII(MeterInfo &m);
|
||||
unique_ptr<HeatCostMeter> createFHKVDataIII(MeterInfo &m);
|
||||
unique_ptr<TempHygroMeter> createLansenTH(MeterInfo &m);
|
||||
unique_ptr<SmokeDetector> createLansenSM(MeterInfo &m);
|
||||
unique_ptr<PulseCounter> createLansenPU(MeterInfo &m);
|
||||
unique_ptr<DoorWindowDetector> createLansenDW(MeterInfo &m);
|
||||
unique_ptr<TempHygroMeter> createCMa12w(MeterInfo &m);
|
||||
unique_ptr<TempHygroMeter> createRfmAmb(MeterInfo &m);
|
||||
unique_ptr<WaterMeter> createRfmTX1(MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createEHZP(MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createESYSWM(MeterInfo &m);
|
||||
unique_ptr<ElectricityMeter> createEBZWMBE(MeterInfo &m);
|
||||
GenericMeter *createGeneric(MeterInfo &m);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,6 @@ struct MeterCommonImplementation : public virtual Meter
|
|||
string name();
|
||||
MeterType type();
|
||||
vector<int> media();
|
||||
WMBus *bus();
|
||||
|
||||
ELLSecurityMode expectedELLSecurityMode();
|
||||
TPLSecurityMode expectedTPLSecurityMode();
|
||||
|
@ -61,8 +60,7 @@ struct MeterCommonImplementation : public virtual Meter
|
|||
double getRecordAsDouble(std::string record);
|
||||
uint16_t getRecordAsUInt16(std::string record);
|
||||
|
||||
MeterCommonImplementation(WMBus *bus, MeterInfo &mi,
|
||||
MeterType type, int manufacturer);
|
||||
MeterCommonImplementation(MeterInfo &mi, MeterType type, int manufacturer);
|
||||
|
||||
~MeterCommonImplementation() = default;
|
||||
|
||||
|
|
165
src/serial.cc
165
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<SerialDevice> createSerialDeviceSimulator();
|
||||
|
||||
void listenTo(SerialDevice *sd, function<void()> cb);
|
||||
void onDisappear(SerialDevice *sd, function<void()> cb);
|
||||
void stop();
|
||||
void startEventLoop();
|
||||
void waitForStop();
|
||||
|
@ -87,13 +88,13 @@ struct SerialCommunicationManagerImp : public SerialCommunicationManager
|
|||
void closeAll();
|
||||
|
||||
time_t reopenAfter() { return reopen_after_seconds_; }
|
||||
int startRegularCallback(int seconds, function<void()> callback, string name);
|
||||
int startRegularCallback(string name, int seconds, function<void()> callback);
|
||||
void stopRegularCallback(int id);
|
||||
|
||||
void resetInitiated() { debug("(serial) initiate reset\n"); resetting_ = true; }
|
||||
void resetCompleted() { debug("(serial) reset completed\n"); resetting_ = false; }
|
||||
vector<string> listSerialDevices();
|
||||
|
||||
SerialDevice *lookup(std::string device);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -118,8 +119,9 @@ private:
|
|||
pthread_mutex_t devices_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
vector<SerialDeviceImp*> devices_;
|
||||
vector<Timer> timers_;
|
||||
pthread_mutex_t timer_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t timers_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
bool calling_timers_ {};
|
||||
pthread_mutex_t timer_thread_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
};
|
||||
|
||||
SerialCommunicationManagerImp::~SerialCommunicationManagerImp()
|
||||
|
@ -129,14 +131,15 @@ SerialCommunicationManagerImp::~SerialCommunicationManagerImp()
|
|||
// Stop the event loop.
|
||||
stop();
|
||||
// Grab the event_loop_lock. This can only be done when the eventLoop has stopped running.
|
||||
pthread_mutex_lock(&event_loop_lock_);
|
||||
LOCK("(serial)", "destructor", event_loop_lock_);
|
||||
// Now we can be sure the eventLoop has stopped and it is safe to
|
||||
// free this Manager object.
|
||||
}
|
||||
|
||||
struct SerialDeviceImp : public SerialDevice
|
||||
{
|
||||
int fd() { return fd_; }
|
||||
void doNotUseCallbacks() { no_callbacks_ = true; }
|
||||
bool skippingCallbacks() { return no_callbacks_; }
|
||||
void fill(vector<uchar> &data) {};
|
||||
int receive(vector<uchar> *data);
|
||||
bool working() { return fd_ != -1; }
|
||||
|
@ -146,16 +149,19 @@ struct SerialDeviceImp : public SerialDevice
|
|||
void setIsFile() { is_file_ = true; }
|
||||
void setIsStdin() { is_stdin_ = true; }
|
||||
string device() { return ""; }
|
||||
int fd() { return fd_; }
|
||||
|
||||
protected:
|
||||
|
||||
pthread_mutex_t read_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t write_lock_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
function<void()> on_data_;
|
||||
function<void()> on_disappear_;
|
||||
int fd_ = -1;
|
||||
bool expecting_ascii_ {}; // If true, print using safeString instead if bin2hex
|
||||
bool is_file_ = false;
|
||||
bool is_stdin_ = false;
|
||||
bool no_callbacks_ = false;
|
||||
|
||||
friend struct SerialCommunicationManagerImp;
|
||||
|
||||
|
@ -166,7 +172,7 @@ int SerialDeviceImp::receive(vector<uchar> *data)
|
|||
{
|
||||
bool close_me = false;
|
||||
|
||||
pthread_mutex_lock(&read_lock_);
|
||||
LOCK("(serial)", "receive", read_lock_);
|
||||
data->clear();
|
||||
int num_read = 0;
|
||||
|
||||
|
@ -216,7 +222,7 @@ int SerialDeviceImp::receive(vector<uchar> *data)
|
|||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&read_lock_);
|
||||
UNLOCK("(serial)", "receive", read_lock_);
|
||||
|
||||
if (close_me) close();
|
||||
|
||||
|
@ -302,6 +308,11 @@ void SerialDeviceTTY::close()
|
|||
::flock(fd_, LOCK_UN);
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
if (on_disappear_)
|
||||
{
|
||||
on_disappear_();
|
||||
on_disappear_ = NULL;
|
||||
}
|
||||
manager_->closed(this);
|
||||
verbose("(serialtty) closed %s\n", device_.c_str());
|
||||
}
|
||||
|
@ -348,7 +359,7 @@ bool SerialDeviceTTY::send(vector<uchar> &data)
|
|||
{
|
||||
if (data.size() == 0) return true;
|
||||
|
||||
pthread_mutex_lock(&write_lock_);
|
||||
LOCK("(serial)", "send", write_lock_);
|
||||
|
||||
bool rc = true;
|
||||
int n = data.size();
|
||||
|
@ -370,7 +381,7 @@ bool SerialDeviceTTY::send(vector<uchar> &data)
|
|||
}
|
||||
|
||||
end:
|
||||
pthread_mutex_unlock(&write_lock_);
|
||||
UNLOCK("(serial)", "send", write_lock_);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -476,7 +487,7 @@ bool SerialDeviceCommand::send(vector<uchar> &data)
|
|||
{
|
||||
if (data.size() == 0) return true;
|
||||
|
||||
pthread_mutex_lock(&write_lock_);
|
||||
LOCK("(serial)", "sendcmd", write_lock_);
|
||||
|
||||
bool rc = true;
|
||||
int n = data.size();
|
||||
|
@ -498,7 +509,7 @@ bool SerialDeviceCommand::send(vector<uchar> &data)
|
|||
}
|
||||
|
||||
end:
|
||||
pthread_mutex_unlock(&write_lock_);
|
||||
UNLOCK("(serial)", "sendcmd", write_lock_);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -629,7 +640,7 @@ SerialCommunicationManagerImp::SerialCommunicationManagerImp(time_t exit_after_s
|
|||
// Block the event loop until everything is configured.
|
||||
if (start_event_loop)
|
||||
{
|
||||
pthread_mutex_lock(&event_loop_lock_);
|
||||
LOCK("(serial)", "constructor", event_loop_lock_);
|
||||
pthread_create(&select_thread_, NULL, startLoop, this);
|
||||
}
|
||||
wakeMeUpOnSigChld(select_thread_);
|
||||
|
@ -649,7 +660,8 @@ void *SerialCommunicationManagerImp::runTimers(void *a)
|
|||
auto t = (SerialCommunicationManagerImp*)a;
|
||||
t->executeTimerCallbacks();
|
||||
t->calling_timers_ = false;
|
||||
pthread_mutex_unlock(&t->timer_lock_);
|
||||
// Now unlock the previously trylocked mutex.
|
||||
UNLOCK("(serial)", "runTimers", t->timer_thread_lock_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -688,6 +700,17 @@ void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function<void()>
|
|||
si->on_data_ = cb;
|
||||
}
|
||||
|
||||
void SerialCommunicationManagerImp::onDisappear(SerialDevice *sd, function<void()> cb)
|
||||
{
|
||||
if (sd == NULL) return;
|
||||
SerialDeviceImp *si = dynamic_cast<SerialDeviceImp*>(sd);
|
||||
if (!si)
|
||||
{
|
||||
error("Internal error: Invalid serial device passed to onDisappear.\n");
|
||||
}
|
||||
si->on_disappear_ = cb;
|
||||
}
|
||||
|
||||
void SerialCommunicationManagerImp::stop()
|
||||
{
|
||||
// Notify the main waitForStop thread that we are stopped!
|
||||
|
@ -709,20 +732,20 @@ void SerialCommunicationManagerImp::stop()
|
|||
void SerialCommunicationManagerImp::startEventLoop()
|
||||
{
|
||||
// Release the event loop!
|
||||
pthread_mutex_unlock(&event_loop_lock_);
|
||||
UNLOCK("(serial)", "startEventLoop", event_loop_lock_);
|
||||
}
|
||||
|
||||
void SerialCommunicationManagerImp::waitForStop()
|
||||
{
|
||||
debug("(serial) waiting for stop\n");
|
||||
|
||||
expect_devices_to_work_ = true;
|
||||
//expect_devices_to_work_ = true;
|
||||
main_thread_ = pthread_self();
|
||||
while (running_)
|
||||
{
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "waitForStop", devices_lock_);
|
||||
size_t s = devices_.size();
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "waitForStop", devices_lock_);
|
||||
|
||||
if (s == 0) {
|
||||
break;
|
||||
|
@ -751,19 +774,19 @@ void SerialCommunicationManagerImp::setReopenAfter(int seconds)
|
|||
|
||||
void SerialCommunicationManagerImp::opened(SerialDeviceImp *sd)
|
||||
{
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "opened", devices_lock_);
|
||||
max_fd_ = max(sd->fd(), max_fd_);
|
||||
devices_.push_back(sd);
|
||||
if (signalsInstalled())
|
||||
{
|
||||
if (select_thread_) pthread_kill(select_thread_, SIGUSR1);
|
||||
}
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "opened", devices_lock_);
|
||||
}
|
||||
|
||||
void SerialCommunicationManagerImp::closed(SerialDeviceImp *sd)
|
||||
{
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "closed", devices_lock_);
|
||||
auto p = find(devices_.begin(), devices_.end(), sd);
|
||||
if (p != devices_.end())
|
||||
{
|
||||
|
@ -782,17 +805,23 @@ void SerialCommunicationManagerImp::closed(SerialDeviceImp *sd)
|
|||
debug("(serial) no devices working emergency exit!\n");
|
||||
stop();
|
||||
}
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "opened", devices_lock_);
|
||||
}
|
||||
|
||||
void SerialCommunicationManagerImp::closeAll()
|
||||
{
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "closeAll", devices_lock_);
|
||||
vector<SerialDeviceImp*> copy = devices_;
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "closeAll", devices_lock_);
|
||||
|
||||
for (SerialDeviceImp *d : copy)
|
||||
{
|
||||
if (d->on_disappear_)
|
||||
{
|
||||
d->on_disappear_();
|
||||
d->on_disappear_ = NULL;
|
||||
}
|
||||
|
||||
closed(d);
|
||||
}
|
||||
}
|
||||
|
@ -800,7 +829,11 @@ void SerialCommunicationManagerImp::closeAll()
|
|||
void SerialCommunicationManagerImp::executeTimerCallbacks()
|
||||
{
|
||||
time_t curr = time(NULL);
|
||||
for (Timer &t : timers_)
|
||||
LOCK("(serial)", "executeTimerCallbacks", timers_lock_);
|
||||
vector<Timer> timers_copy = timers_;
|
||||
UNLOCK("(serial)", "executeTimerCallbacks", timers_lock_);
|
||||
|
||||
for (Timer &t : timers_copy)
|
||||
{
|
||||
if (t.isTime(curr))
|
||||
{
|
||||
|
@ -831,69 +864,57 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
{
|
||||
fd_set readfds;
|
||||
|
||||
pthread_mutex_lock(&event_loop_lock_);
|
||||
LOCK("(serial)", "eventLoop", event_loop_lock_);
|
||||
|
||||
while (running_)
|
||||
{
|
||||
FD_ZERO(&readfds);
|
||||
|
||||
bool all_working = true;
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "opened", devices_lock_);
|
||||
for (SerialDevice *d : devices_)
|
||||
{
|
||||
FD_SET(d->fd(), &readfds);
|
||||
if (!d->skippingCallbacks())
|
||||
{
|
||||
FD_SET(d->fd(), &readfds);
|
||||
}
|
||||
if (!d->working()) all_working = false;
|
||||
}
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "opened", devices_lock_);
|
||||
|
||||
if (!all_working && resetting_ == false)
|
||||
if (!all_working && expect_devices_to_work_ && resetting_ == false)
|
||||
{
|
||||
debug("(serial) not all devices working, emergency exit!\n");
|
||||
stop();
|
||||
break;
|
||||
}
|
||||
|
||||
int default_timeout = isInternalTestingEnabled() ? CHECKSTATUS_TIMER_INTERNAL_TESTING : CHECKSTATUS_TIMER;
|
||||
|
||||
struct timeval timeout { default_timeout, 0 };
|
||||
// Perform a select call every second.
|
||||
struct timeval timeout { 1, 0 };
|
||||
time_t curr = time(NULL);
|
||||
|
||||
// Default timeout is once every 10 seconds. See timings.h
|
||||
// This means that we will poll the status of tty:s and commands
|
||||
// once every 10 seconds.
|
||||
|
||||
// However sometimes the timeout should be shorter.
|
||||
// We might have an exit coming up...
|
||||
if (exit_after_seconds_ > 0)
|
||||
{
|
||||
time_t diff = curr-start_time_;
|
||||
if (diff > exit_after_seconds_) {
|
||||
if (diff > exit_after_seconds_)
|
||||
{
|
||||
// Running time limit hit, now stop.
|
||||
verbose("(serial) exit after %ld seconds\n", diff);
|
||||
stop();
|
||||
break;
|
||||
}
|
||||
timeout.tv_sec = exit_after_seconds_ - diff;
|
||||
if (timeout.tv_sec < 0) timeout.tv_sec = 0;
|
||||
}
|
||||
|
||||
// We might have a regular timer callback coming up.
|
||||
if (timers_.size() > 0 && !calling_timers_)
|
||||
{
|
||||
time_t remaining = calculateTimeToNearestTimerCallback(curr);
|
||||
if (remaining < 0) remaining = 1;
|
||||
if (timeout.tv_sec > remaining) timeout.tv_sec = remaining;
|
||||
}
|
||||
|
||||
trace("(trace serial) select timeout %d s\n", timeout.tv_sec);
|
||||
|
||||
bool num_devices = 0;
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "eventLoop2", devices_lock_);
|
||||
for (SerialDevice *d : devices_)
|
||||
{
|
||||
d->checkIfShouldReopen();
|
||||
}
|
||||
num_devices = devices_.size();
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "eventLoop2", devices_lock_);
|
||||
|
||||
if (num_devices == 0 && expect_devices_to_work_ && resetting_ == false)
|
||||
{
|
||||
|
@ -912,7 +933,7 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
{
|
||||
// Something has happened that caused the sleeping select to wake up.
|
||||
vector<SerialDeviceImp*> to_be_notified;
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "eventLoop3", devices_lock_);
|
||||
for (SerialDevice *d : devices_)
|
||||
{
|
||||
if (FD_ISSET(d->fd(), &readfds))
|
||||
|
@ -921,7 +942,7 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
to_be_notified.push_back(si);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "eventLoop3", devices_lock_);
|
||||
|
||||
for (SerialDeviceImp *si : to_be_notified)
|
||||
{
|
||||
|
@ -933,12 +954,12 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
}
|
||||
vector<SerialDeviceImp*> non_working;
|
||||
|
||||
pthread_mutex_lock(&devices_lock_);
|
||||
LOCK("(serial)", "eventLoop4", devices_lock_);
|
||||
for (SerialDeviceImp *d : devices_)
|
||||
{
|
||||
if (!d->working()) non_working.push_back(d);
|
||||
}
|
||||
pthread_mutex_unlock(&devices_lock_);
|
||||
UNLOCK("(serial)", "eventLoop4", devices_lock_);
|
||||
|
||||
for (SerialDeviceImp *d : non_working)
|
||||
{
|
||||
|
@ -954,7 +975,7 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
|
||||
if (timer_found)
|
||||
{
|
||||
int rc = pthread_mutex_trylock(&timer_lock_);
|
||||
int rc = pthread_mutex_trylock(&timer_thread_lock_);
|
||||
// Only start timer thread if it is not running already.
|
||||
if (rc == 0)
|
||||
{
|
||||
|
@ -969,7 +990,7 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
}
|
||||
}
|
||||
|
||||
if (non_working.size() > 0 && resetting_ == false)
|
||||
if (non_working.size() > 0 && expect_devices_to_work_ && resetting_ == false)
|
||||
{
|
||||
debug("(serial) non working devices found, exiting.\n");
|
||||
stop();
|
||||
|
@ -977,7 +998,7 @@ void *SerialCommunicationManagerImp::eventLoop()
|
|||
}
|
||||
}
|
||||
verbose("(serial) event loop stopped!\n");
|
||||
pthread_mutex_unlock(&event_loop_lock_);
|
||||
UNLOCK("(serial)", "eventLoop", event_loop_lock_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1077,26 +1098,42 @@ SerialCommunicationManager::~SerialCommunicationManager()
|
|||
{
|
||||
}
|
||||
|
||||
int SerialCommunicationManagerImp::startRegularCallback(int seconds, function<void()> callback, string name)
|
||||
int SerialCommunicationManagerImp::startRegularCallback(string name, int seconds, function<void()> callback)
|
||||
{
|
||||
Timer t = { (int)timers_.size(), seconds, time(NULL), callback, name };
|
||||
LOCK("(serial)", "startRegularCallback", timers_lock_);
|
||||
timers_.push_back(t);
|
||||
UNLOCK("(serial)", "startRegularCallback", timers_lock_);
|
||||
debug("(serial) registered regular callback %d %s every %d seconds\n", t.id, name.c_str(), seconds);
|
||||
return t.id;
|
||||
}
|
||||
|
||||
void SerialCommunicationManagerImp::stopRegularCallback(int id)
|
||||
{
|
||||
debug("(serial) stopping regular callback %d\n", id);
|
||||
LOCK("(serial)", "stopRegularCallback", timers_lock_);
|
||||
for (auto i = timers_.begin(); i != timers_.end(); ++i)
|
||||
{
|
||||
if ((*i).id == id)
|
||||
{
|
||||
timers_.erase(i);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
UNLOCK("(serial)", "startRegularCallback", timers_lock_);
|
||||
}
|
||||
|
||||
|
||||
SerialDevice *SerialCommunicationManagerImp::lookup(string device)
|
||||
{
|
||||
for (auto sd : devices_)
|
||||
{
|
||||
if (sd->device() == device) return sd;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
vector<string> SerialCommunicationManagerImp::listSerialDevices()
|
||||
{
|
||||
|
@ -1201,7 +1238,11 @@ vector<string> SerialCommunicationManagerImp::listSerialDevices()
|
|||
{
|
||||
string name = entries[i]->d_name;
|
||||
|
||||
if (name == ".." || name == ".") continue;
|
||||
if (name == ".." || name == ".")
|
||||
{
|
||||
free(entries[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
string tty = sysdir+name;
|
||||
check_if_serial(tty, &found_serials, &found_8250s);
|
||||
|
|
13
src/serial.h
13
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<SerialDevice> createSerialDeviceSimulator() = 0;
|
||||
|
||||
// Invoke cb callback when data arrives on the serial device.
|
||||
virtual void listenTo(SerialDevice *sd, function<void()> cb) = 0;
|
||||
// Invoke cb callback when the serial device has disappeared!
|
||||
virtual void onDisappear(SerialDevice *sd, function<void()> cb) = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void startEventLoop() = 0;
|
||||
virtual void waitForStop() = 0;
|
||||
|
@ -78,7 +85,7 @@ struct SerialCommunicationManager
|
|||
virtual void setReopenAfter(int seconds) = 0;
|
||||
// Register a new timer that regularly, every seconds, invokes the callback.
|
||||
// Returns an id for the timer.
|
||||
virtual int startRegularCallback(int seconds, function<void()> callback, std::string name) = 0;
|
||||
virtual int startRegularCallback(std::string name, int seconds, function<void()> callback) = 0;
|
||||
virtual void stopRegularCallback(int id) = 0;
|
||||
|
||||
virtual void resetInitiated() = 0;
|
||||
|
@ -86,6 +93,8 @@ struct SerialCommunicationManager
|
|||
|
||||
// List all real serial devices.
|
||||
virtual std::vector<std::string> listSerialDevices() = 0;
|
||||
// Return a serial device for the given device, if it exists! Otherwise NULL.
|
||||
virtual SerialDevice *lookup(std::string device) = 0;
|
||||
virtual ~SerialCommunicationManager();
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -49,8 +49,11 @@ std::string safeString(std::vector<uchar> &target);
|
|||
void strprintf(std::string &s, const char* fmt, ...);
|
||||
// Return for example: 2010-03-21
|
||||
std::string strdate(struct tm *date);
|
||||
// Return for example: 2010-03-21 15:22:03
|
||||
// Return for example: 2010-03-21 15:22
|
||||
std::string strdatetime(struct tm *date);
|
||||
// Return for example: 2010-03-21 15:22:03
|
||||
std::string strdatetimesec(struct tm *date);
|
||||
|
||||
|
||||
void xorit(uchar *srca, uchar *srcb, uchar *dest, int len);
|
||||
void shiftLeft(uchar *srca, uchar *srcb, int len);
|
||||
|
@ -163,4 +166,7 @@ bool startsWith(std::string s, std::vector<uchar> &data);
|
|||
// Sum the memory used by the heap and stack.
|
||||
size_t memoryUsage();
|
||||
|
||||
#define LOCK(module,func,x) { trace("TRACE " module " " func " locking " #x "\n"); pthread_mutex_lock(&x); trace(module " " func " locked " #x "\n"); }
|
||||
#define UNLOCK(module,func,x) { trace("TRACE " module " " func " unlocking " #x "\n"); pthread_mutex_unlock(&x); trace(module " " func " unlocked " #x "\n"); }
|
||||
|
||||
#endif
|
||||
|
|
182
src/wmbus.cc
182
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<uchar> *format_byt
|
|||
return ok;
|
||||
}
|
||||
|
||||
WMBusCommonImplementation::~WMBusCommonImplementation()
|
||||
{
|
||||
info("(wmbus) deleted %s\n", toString(type()));
|
||||
}
|
||||
|
||||
WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t,
|
||||
SerialCommunicationManager *manager,
|
||||
unique_ptr<SerialDevice> serial)
|
||||
: manager_(manager),
|
||||
is_working_(true),
|
||||
type_(t),
|
||||
serial_(std::move(serial))
|
||||
{
|
||||
|
@ -3331,7 +3345,7 @@ WMBusCommonImplementation::WMBusCommonImplementation(WMBusDeviceType t,
|
|||
|
||||
// Invoke the check status once per minute. Unless internal testing, then it is every 2 seconds.
|
||||
int default_timer = isInternalTestingEnabled() ? CHECKSTATUS_TIMER_INTERNAL_TESTING : CHECKSTATUS_TIMER;
|
||||
manager_->startRegularCallback(default_timer, call(this,checkStatus), toString(t));
|
||||
manager_->startRegularCallback(toString(t), default_timer, call(this,checkStatus));
|
||||
}
|
||||
|
||||
WMBusDeviceType WMBusCommonImplementation::type()
|
||||
|
@ -3437,6 +3451,20 @@ bool WMBusCommonImplementation::reset()
|
|||
return true;
|
||||
}
|
||||
|
||||
void WMBusCommonImplementation::disconnectedFromDevice()
|
||||
{
|
||||
if (is_working_)
|
||||
{
|
||||
info("(wmbus) lost %s closing %s\n", device().c_str(), toString(type()));
|
||||
is_working_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WMBusCommonImplementation::isWorking()
|
||||
{
|
||||
return is_working_;
|
||||
}
|
||||
|
||||
void WMBusCommonImplementation::checkStatus()
|
||||
{
|
||||
if (protocol_error_count_ >= 20)
|
||||
|
@ -3673,6 +3701,7 @@ AccessCheck findAndDetect(SerialCommunicationManager *manager,
|
|||
AccessCheck rc = check(dev, manager);
|
||||
if (rc == AccessCheck::AccessOK) return AccessCheck::AccessOK;
|
||||
}
|
||||
|
||||
if (ac == AccessCheck::NotSameGroup)
|
||||
{
|
||||
// Device exists, but you do not belong to its group!
|
||||
|
@ -3682,27 +3711,6 @@ AccessCheck findAndDetect(SerialCommunicationManager *manager,
|
|||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
|
||||
for (int n=0; n < 9; ++n)
|
||||
{
|
||||
dev = device_root+"_"+to_string(n);
|
||||
debug("(%s) exists? %s\n", dongle_name.c_str(), dev.c_str());
|
||||
AccessCheck ac = checkIfExistsAndSameGroup(dev);
|
||||
*out_device = dev;
|
||||
if (ac == AccessCheck::AccessOK)
|
||||
{
|
||||
debug("(%s) checking %s\n", dongle_name.c_str(), dev.c_str());
|
||||
AccessCheck rc = check(dev, manager);
|
||||
if (rc == AccessCheck::AccessOK) return AccessCheck::AccessOK;
|
||||
// If we get here, the device /dev/im871a_0 could be locked
|
||||
// try /dev/im871a_1 etc...
|
||||
}
|
||||
if (ac == AccessCheck::NotSameGroup)
|
||||
{
|
||||
// Device exists, but you do not belong to its group!
|
||||
return AccessCheck::NotSameGroup;
|
||||
}
|
||||
}
|
||||
|
||||
*out_device = "";
|
||||
// No device found!
|
||||
return AccessCheck::NotThere;
|
||||
|
@ -3935,3 +3943,33 @@ LIST_OF_MBUS_DEVICES
|
|||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
bool isPossibleDevice(string arg, Device *device)
|
||||
{
|
||||
size_t colon = arg.find(":");
|
||||
|
||||
if (colon == string::npos)
|
||||
{
|
||||
|
||||
device->file = arg;
|
||||
device->suffix = "";
|
||||
device->linkmodes = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
device->file = arg.substr(0, colon);
|
||||
string rest = arg.substr(colon+1);
|
||||
|
||||
colon = rest.find(":");
|
||||
if (colon == string::npos)
|
||||
{
|
||||
device->suffix = rest;
|
||||
device->linkmodes = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
device->suffix = rest.substr(0, colon);
|
||||
device->linkmodes = rest.substr(colon+1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
106
src/wmbus.h
106
src/wmbus.h
|
@ -30,6 +30,56 @@
|
|||
bool trimCRCsFrameFormatA(std::vector<uchar> &payload);
|
||||
bool trimCRCsFrameFormatB(std::vector<uchar> &payload);
|
||||
|
||||
struct Device
|
||||
{
|
||||
// A typical device is:
|
||||
// /dev/ttyUSB0:im871a:c1,t1
|
||||
// /dev/ttyUSB1:amb8465
|
||||
// /rtlwmbus::any
|
||||
std::string file; // /dev/ttyUSB0, simulation_meter.txt, stdin file.raw
|
||||
std::string suffix; // rtlwmbus im871a amb8465 38400 rtl433
|
||||
std::string linkmodes; // c1,t1,s1
|
||||
};
|
||||
|
||||
#define LIST_OF_MBUS_DEVICES \
|
||||
X(DEVICE_UNKNOWN) \
|
||||
X(DEVICE_CUL)\
|
||||
X(DEVICE_D1TC)\
|
||||
X(DEVICE_IM871A)\
|
||||
X(DEVICE_AMB8465)\
|
||||
X(DEVICE_RFMRX2)\
|
||||
X(DEVICE_SIMULATOR)\
|
||||
X(DEVICE_RTLWMBUS)\
|
||||
X(DEVICE_RTL433)\
|
||||
X(DEVICE_RAWTTY)\
|
||||
X(DEVICE_WMB13U)
|
||||
|
||||
enum WMBusDeviceType {
|
||||
#define X(name) name,
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
};
|
||||
|
||||
const char *toString(WMBusDeviceType t);
|
||||
|
||||
struct Detected
|
||||
{
|
||||
Device device; // Device information.
|
||||
WMBusDeviceType type; // IM871A, AMB8465 etc.
|
||||
int baudrate; // Baudrate to tty.
|
||||
// If the override_tty is true, then do not allow the wmbus driver to open the device->file as a tty,
|
||||
// instead open the device->file as a file instead . This is to allows feeding the wmbus drivers
|
||||
// using stdin or a file. This is primarily used for internal testing.
|
||||
bool override_tty;
|
||||
|
||||
void set(WMBusDeviceType t, int br, bool ot)
|
||||
{
|
||||
type = t;
|
||||
baudrate = br;
|
||||
override_tty = ot;
|
||||
}
|
||||
};
|
||||
|
||||
#define LIST_OF_LINK_MODES \
|
||||
X(Any,any,--anylinkmode,0xffff) \
|
||||
X(C1,c1,--c1,0x1) \
|
||||
|
@ -390,27 +440,6 @@ private:
|
|||
|
||||
struct Meter;
|
||||
|
||||
#define LIST_OF_MBUS_DEVICES \
|
||||
X(DEVICE_UNKNOWN) \
|
||||
X(DEVICE_CUL)\
|
||||
X(DEVICE_D1TC)\
|
||||
X(DEVICE_IM871A)\
|
||||
X(DEVICE_AMB8465)\
|
||||
X(DEVICE_RFMRX2)\
|
||||
X(DEVICE_SIMULATOR)\
|
||||
X(DEVICE_RTLWMBUS)\
|
||||
X(DEVICE_RTL433)\
|
||||
X(DEVICE_RAWTTY)\
|
||||
X(DEVICE_WMB13U)
|
||||
|
||||
enum WMBusDeviceType {
|
||||
#define X(name) name,
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
};
|
||||
|
||||
const char *toString(WMBusDeviceType t);
|
||||
|
||||
struct WMBus
|
||||
{
|
||||
virtual WMBusDeviceType type() = 0;
|
||||
|
@ -426,7 +455,9 @@ struct WMBus
|
|||
virtual void onTelegram(function<bool(vector<uchar>)> cb) = 0;
|
||||
virtual SerialDevice *serial() = 0;
|
||||
virtual void simulate() = 0;
|
||||
// This will check if the wmbus devices needs reset.
|
||||
// Return true if underlying device is ok and device in general seems to be working.
|
||||
virtual bool isWorking() = 0;
|
||||
// This will check if the wmbus devices needs a reset and then immediately perform the reset.
|
||||
virtual void checkStatus() = 0;
|
||||
// Close any underlying ttys or software and restart/reinitialize.
|
||||
// Return true if ok.
|
||||
|
@ -438,21 +469,12 @@ struct WMBus
|
|||
virtual ~WMBus() = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Detected
|
||||
{
|
||||
WMBusDeviceType type; // IM871A, AMB8465 etc
|
||||
string devicefile; // /dev/ttyUSB0 /dev/ttyACM0 stdin simulation_abc.txt telegrams.raw
|
||||
int baudrate; // If the suffix is a number, store the number here.
|
||||
// If the override_tty is true, then do not allow the wmbus driver to open the tty,
|
||||
// instead open the devicefile first. This is to allow feeding the wmbus drivers using stdin
|
||||
// or a file or for internal testing.
|
||||
bool override_tty;
|
||||
};
|
||||
|
||||
Detected detectWMBusDeviceSetting(string devicefile, string suffix,
|
||||
SerialCommunicationManager *manager);
|
||||
|
||||
|
||||
bool isPossibleDevice(string arg, Device *device);
|
||||
|
||||
unique_ptr<WMBus> openIM871A(string device, SerialCommunicationManager *manager,
|
||||
unique_ptr<SerialDevice> serial_override);
|
||||
unique_ptr<WMBus> openAMB8465(string device, SerialCommunicationManager *manager,
|
||||
|
@ -518,15 +540,19 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
|
|||
int *payload_len_out,
|
||||
int *payload_offset);
|
||||
|
||||
AccessCheck detectIM871A(string device, SerialCommunicationManager *handler);
|
||||
AccessCheck detectAMB8465(string device, SerialCommunicationManager *handler);
|
||||
AccessCheck detectRawTTY(string device, int baud, SerialCommunicationManager *handler);
|
||||
AccessCheck detectRTLSDR(string device, SerialCommunicationManager *handler);
|
||||
AccessCheck detectCUL(string device, SerialCommunicationManager *handler);
|
||||
AccessCheck detectWMB13U(string device, SerialCommunicationManager *handler);
|
||||
AccessCheck detectIM871A(string file, Detected *detected, SerialCommunicationManager *handler);
|
||||
AccessCheck detectAMB8465(string file, Detected *detected, SerialCommunicationManager *handler);
|
||||
AccessCheck detectRawTTY(string file, int baud, Detected *detected, SerialCommunicationManager *handler);
|
||||
AccessCheck detectRTLSDR(string file, Detected *detected, SerialCommunicationManager *handler);
|
||||
AccessCheck detectCUL(string file, Detected *detected, SerialCommunicationManager *handler);
|
||||
AccessCheck detectWMB13U(string file, Detected *detected, SerialCommunicationManager *handler);
|
||||
|
||||
// Try to factory reset an AMB8465 by trying all possible serial speeds and
|
||||
// restore to factory settings.
|
||||
AccessCheck factoryResetAMB8465(string device, SerialCommunicationManager *handler, int *was_baud);
|
||||
|
||||
Detected detectImstAmberCul(string file,
|
||||
string suffix,
|
||||
SerialCommunicationManager *handler);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -109,6 +109,7 @@ WMBusAmber::WMBusAmber(unique_ptr<SerialDevice> serial, SerialCommunicationManag
|
|||
{
|
||||
sem_init(&command_wait_, 0, 0);
|
||||
manager_->listenTo(this->serial(),call(this,processSerialData));
|
||||
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
|
||||
rssi_expected_ = true;
|
||||
reset();
|
||||
}
|
||||
|
@ -131,9 +132,9 @@ bool WMBusAmber::ping()
|
|||
{
|
||||
if (serial()->readonly()) return true; // Feeding from stdin or file.
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(amb8465)", "ping", command_lock_);
|
||||
// Ping it...
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(amb8465)", "ping", command_lock_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -142,7 +143,7 @@ uint32_t WMBusAmber::getDeviceId()
|
|||
{
|
||||
if (serial()->readonly()) { return 0; } // Feeding from stdin or file.
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(amb8465)", "getDeviceId", command_lock_);
|
||||
|
||||
vector<uchar> msg(4);
|
||||
msg[0] = AMBER_SERIAL_SOF;
|
||||
|
@ -172,7 +173,7 @@ uint32_t WMBusAmber::getDeviceId()
|
|||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(amb8465)", "getDeviceId", command_lock_);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -190,7 +191,7 @@ void WMBusAmber::getConfiguration()
|
|||
{
|
||||
if (serial()->readonly()) { return; } // Feeding from stdin or file.
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(amb8465)", "getConfiguration", command_lock_);
|
||||
|
||||
vector<uchar> msg(6);
|
||||
msg[0] = AMBER_SERIAL_SOF;
|
||||
|
@ -207,7 +208,7 @@ void WMBusAmber::getConfiguration()
|
|||
|
||||
if (!sent)
|
||||
{
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(amb8465)", "getConfiguration", command_lock_);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -233,7 +234,7 @@ void WMBusAmber::getConfiguration()
|
|||
verbose("(amb8465) config: mode Preselect %02x\n", received_payload_[70+2]);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(amb8465)", "getConfiguration", command_lock_);
|
||||
}
|
||||
|
||||
void WMBusAmber::deviceSetLinkModes(LinkModeSet lms)
|
||||
|
@ -246,7 +247,7 @@ void WMBusAmber::deviceSetLinkModes(LinkModeSet lms)
|
|||
error("(amb8465) setting link mode(s) %s is not supported for amb8465\n", modes.c_str());
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(amb8465)", "deviceSetLinkModes", command_lock_);
|
||||
|
||||
vector<uchar> msg(8);
|
||||
msg[0] = AMBER_SERIAL_SOF;
|
||||
|
@ -281,7 +282,7 @@ void WMBusAmber::deviceSetLinkModes(LinkModeSet lms)
|
|||
if (sent) waitForResponse();
|
||||
|
||||
link_modes_ = lms;
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(amb8465)", "deviceSetLinkModes", command_lock_);
|
||||
}
|
||||
|
||||
void WMBusAmber::waitForResponse()
|
||||
|
@ -518,10 +519,11 @@ void WMBusAmber::handleMessage(int msgid, vector<uchar> &frame)
|
|||
}
|
||||
}
|
||||
|
||||
AccessCheck detectAMB8465(string device, SerialCommunicationManager *manager)
|
||||
AccessCheck detectAMB8465(string device, Detected *detected, SerialCommunicationManager *manager)
|
||||
{
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
|
||||
serial->doNotUseCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
|
||||
|
@ -565,6 +567,9 @@ AccessCheck detectAMB8465(string device, SerialCommunicationManager *manager)
|
|||
data[7] != xorChecksum(data, 7)) {
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
detected->set(WMBusDeviceType::DEVICE_AMB8465, 9600, false);
|
||||
|
||||
return AccessCheck::AccessOK;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ WMBusCUL::WMBusCUL(unique_ptr<SerialDevice> serial, SerialCommunicationManager *
|
|||
{
|
||||
sem_init(&command_wait_, 0, 0);
|
||||
manager_->listenTo(this->serial(),call(this,processSerialData));
|
||||
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -355,10 +356,11 @@ FrameStatus WMBusCUL::checkCULFrame(vector<uchar> &data,
|
|||
}
|
||||
}
|
||||
|
||||
AccessCheck detectCUL(string device, SerialCommunicationManager *manager)
|
||||
AccessCheck detectCUL(string device, Detected *detected, SerialCommunicationManager *manager)
|
||||
{
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 38400);
|
||||
serial->doNotUseCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
|
||||
|
@ -399,5 +401,8 @@ AccessCheck detectCUL(string device, SerialCommunicationManager *manager)
|
|||
// TODO: check version string somehow
|
||||
|
||||
serial->close();
|
||||
|
||||
detected->set(WMBusDeviceType::DEVICE_CUL, 38400, false);
|
||||
|
||||
return AccessCheck::AccessOK;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ private:
|
|||
static FrameStatus checkIM871AFrame(vector<uchar> &data,
|
||||
size_t *frame_length, int *endpoint_out, int *msgid_out,
|
||||
int *payload_len_out, int *payload_offset);
|
||||
friend AccessCheck detectIM871A(string device, SerialCommunicationManager *manager);
|
||||
friend AccessCheck detectIM871A(string device, Detected *detected, SerialCommunicationManager *manager);
|
||||
void handleDevMgmt(int msgid, vector<uchar> &payload);
|
||||
void handleRadioLink(int msgid, vector<uchar> &payload);
|
||||
void handleRadioLinkTest(int msgid, vector<uchar> &payload);
|
||||
|
@ -101,6 +101,7 @@ WMBusIM871A::WMBusIM871A(unique_ptr<SerialDevice> serial, SerialCommunicationMan
|
|||
{
|
||||
sem_init(&command_wait_, 0, 0);
|
||||
manager_->listenTo(this->serial(),call(this,processSerialData));
|
||||
manager_->onDisappear(this->serial(),call(this,disconnectedFromDevice));
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -108,7 +109,7 @@ bool WMBusIM871A::ping()
|
|||
{
|
||||
if (serial()->readonly()) return true; // Feeding from stdin or file.
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(im871)", "ping", command_lock_);
|
||||
|
||||
vector<uchar> msg(4);
|
||||
msg[0] = IM871A_SERIAL_SOF;
|
||||
|
@ -122,7 +123,7 @@ bool WMBusIM871A::ping()
|
|||
|
||||
if (sent) waitForResponse();
|
||||
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(im871)", "ping", command_lock_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -130,7 +131,7 @@ uint32_t WMBusIM871A::getDeviceId()
|
|||
{
|
||||
if (serial()->readonly()) return 0; // Feeding from stdin or file.
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(im871)", "getDeviceId", command_lock_);
|
||||
|
||||
vector<uchar> msg(4);
|
||||
msg[0] = IM871A_SERIAL_SOF;
|
||||
|
@ -165,7 +166,7 @@ uint32_t WMBusIM871A::getDeviceId()
|
|||
id = 0;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(im871)", "getDeviceId", command_lock_);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -173,7 +174,7 @@ LinkModeSet WMBusIM871A::getLinkModes()
|
|||
{
|
||||
if (serial()->readonly()) { return Any_bit; } // Feeding from stdin or file.
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(im871)", "getLinkModes", command_lock_);
|
||||
|
||||
vector<uchar> msg(4);
|
||||
msg[0] = IM871A_SERIAL_SOF;
|
||||
|
@ -188,7 +189,7 @@ LinkModeSet WMBusIM871A::getLinkModes()
|
|||
{
|
||||
// If we are using a serial override that will not respond,
|
||||
// then just return a value.
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(im871)", "getLinkModes", command_lock_);
|
||||
// Use the remembered link modes set before.
|
||||
return protectedGetLinkModes();
|
||||
}
|
||||
|
@ -320,7 +321,8 @@ LinkModeSet WMBusIM871A::getLinkModes()
|
|||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(im871)", "getLinkModes", command_lock_);
|
||||
|
||||
LinkModeSet lms;
|
||||
lms.addLinkMode(lm);
|
||||
return lms;
|
||||
|
@ -344,7 +346,7 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
|
|||
error("(im871a) setting link mode(s) %s is not supported for im871a\n", modes.c_str());
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&command_lock_);
|
||||
LOCK("(im871)", "deviceSetLinkModes", command_lock_);
|
||||
|
||||
vector<uchar> msg(10);
|
||||
msg[0] = IM871A_SERIAL_SOF;
|
||||
|
@ -386,14 +388,16 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
|
|||
|
||||
if (sent) waitForResponse();
|
||||
|
||||
pthread_mutex_unlock(&command_lock_);
|
||||
UNLOCK("(im871)", "deviceSetLinkModes", command_lock_);
|
||||
}
|
||||
|
||||
void WMBusIM871A::waitForResponse()
|
||||
{
|
||||
while (manager_->isRunning())
|
||||
{
|
||||
trace("(im871) waitForResponse sem_wait command_wait_\n");
|
||||
int rc = sem_wait(&command_wait_);
|
||||
trace("(im871) waitForResponse waited command_wait_\n");
|
||||
if (rc==0) break;
|
||||
if (rc==-1) {
|
||||
if (errno==EINTR) continue;
|
||||
|
@ -649,10 +653,11 @@ void WMBusIM871A::handleHWTest(int msgid, vector<uchar> &payload)
|
|||
}
|
||||
}
|
||||
|
||||
AccessCheck detectIM871A(string device, SerialCommunicationManager *manager)
|
||||
AccessCheck detectIM871A(string file, Detected *detected, SerialCommunicationManager *manager)
|
||||
{
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
|
||||
auto serial = manager->createSerialDeviceTTY(file.c_str(), 57600);
|
||||
serial->doNotUseCallbacks();
|
||||
AccessCheck rc = serial->open(false);
|
||||
if (rc != AccessCheck::AccessOK) return AccessCheck::NotThere;
|
||||
|
||||
|
@ -688,5 +693,7 @@ AccessCheck detectIM871A(string device, SerialCommunicationManager *manager)
|
|||
{
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
detected->set(WMBusDeviceType::DEVICE_IM871A, 57600, false);
|
||||
|
||||
return AccessCheck::AccessOK;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -288,8 +288,15 @@ FrameStatus WMBusRTLWMBUS::checkRTLWMBUSFrame(vector<uchar> &data,
|
|||
return FullFrame;
|
||||
}
|
||||
|
||||
AccessCheck detectRTLSDR(string device, SerialCommunicationManager *manager)
|
||||
AccessCheck detectRTLSDR(string device, Detected *detected, SerialCommunicationManager *manager)
|
||||
{
|
||||
// No more advanced test than that the /dev/rtlsdr link exists.
|
||||
return checkIfExistsAndSameGroup(device);
|
||||
AccessCheck rc = checkIfExistsAndSameGroup(device);
|
||||
|
||||
if (rc == AccessCheck::AccessOK)
|
||||
{
|
||||
detected->set(WMBusDeviceType::DEVICE_RTLWMBUS,0, false);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -29,14 +29,17 @@ string frameTypeKamstrupC1(int ft);
|
|||
struct WMBusCommonImplementation : public virtual WMBus
|
||||
{
|
||||
WMBusCommonImplementation(WMBusDeviceType t, SerialCommunicationManager *manager, unique_ptr<SerialDevice> serial_override);
|
||||
~WMBusCommonImplementation();
|
||||
|
||||
WMBusDeviceType type();
|
||||
void setMeters(vector<unique_ptr<Meter>> *meters);
|
||||
void onTelegram(function<bool(vector<uchar>)> cb);
|
||||
bool handleTelegram(vector<uchar> frame);
|
||||
void checkStatus();
|
||||
bool isWorking();
|
||||
void setTimeout(int seconds, std::string expected_activity);
|
||||
void setLinkModes(LinkModeSet lms);
|
||||
void disconnectedFromDevice();
|
||||
bool reset();
|
||||
SerialDevice *serial() { if (serial_) return serial_.get(); else return NULL; }
|
||||
string device() { if (serial_) return serial_->device(); else return "?"; }
|
||||
|
@ -55,6 +58,7 @@ struct WMBusCommonImplementation : public virtual WMBus
|
|||
|
||||
private:
|
||||
|
||||
bool is_working_ {};
|
||||
vector<function<bool(vector<uchar>)>> telegram_listeners_;
|
||||
vector<unique_ptr<Meter>> *meters_;
|
||||
WMBusDeviceType type_ {};
|
||||
|
|
|
@ -203,7 +203,7 @@ void WMBusWMB13U::processSerialData()
|
|||
// Receive and accumulated serial data until a full frame has been received.
|
||||
serial()->receive(&data);
|
||||
// Unlock the serial lock.
|
||||
pthread_mutex_unlock(&serial_lock_);
|
||||
UNLOCK("(wmb13u)", "processSerialData", serial_lock_);
|
||||
|
||||
read_buffer_.insert(read_buffer_.end(), data.begin(), data.end());
|
||||
|
||||
|
@ -245,7 +245,7 @@ void WMBusWMB13U::processSerialData()
|
|||
|
||||
bool WMBusWMB13U::enterConfigModee()
|
||||
{
|
||||
pthread_mutex_lock(&serial_lock_);
|
||||
LOCK("(wmb13u)", "enterConfigMode", serial_lock_);
|
||||
|
||||
vector<uchar> data;
|
||||
|
||||
|
@ -272,7 +272,8 @@ bool WMBusWMB13U::enterConfigModee()
|
|||
return true;
|
||||
|
||||
fail:
|
||||
pthread_mutex_unlock(&serial_lock_);
|
||||
|
||||
UNLOCK("(wmb13u)", "enterConfigMode", serial_lock_);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -291,7 +292,7 @@ bool WMBusWMB13U::exitConfigModee()
|
|||
serial()->receive(&data);
|
||||
|
||||
// Always unlock....
|
||||
pthread_mutex_unlock(&serial_lock_);
|
||||
UNLOCK("(wmb13u)", "exitConfigMode", serial_lock_);
|
||||
|
||||
if (!startsWith("OK", data)) return false;
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue