Compare commits

..

56 Commits

Author SHA1 Message Date
1474fba3b8
commands 2020-09-05 18:42:21 +02:00
8202570561 fix 2020-09-05 15:59:25 +01:00
c99b380c03
output 2020-09-05 16:58:25 +02:00
25a966609e Merge branch 'master' of ssh://home.hottis.de:2922/wolutator/mbus-gateway 2020-09-04 19:39:13 +01:00
8fa628a262
fix 2020-09-04 20:38:48 +02:00
c9333850c3 Merge branch 'master' of ssh://home.hottis.de:2922/wolutator/mbus-gateway 2020-09-04 19:34:45 +01:00
0485ae4687
Merge branch 'master' of ssh://home.hottis.de:2922/wolutator/mbus-gateway 2020-09-04 20:34:21 +02:00
17137ed11d
fix engine's error handling 2020-09-04 20:34:10 +02:00
7898b6fde8 makefile and baudrate 2020-09-04 19:17:45 +01:00
9dd62f109a makefile 2020-09-04 19:15:57 +01:00
fbc2077d60 fix 2020-09-04 18:32:43 +01:00
0071051c18
more error codes 2020-09-04 19:31:20 +02:00
3ec9dca233
fix 2020-09-04 18:48:33 +02:00
3a7fd4a501
disable request 2020-09-04 18:46:50 +02:00
7aa21c4e4f
fix 2020-09-04 18:37:25 +02:00
bb6682c385
fix 2020-09-04 18:33:06 +02:00
275b29e6a4
error handling 2020-09-04 18:26:18 +02:00
d4ce143298 use 2400 Baud 2020-09-03 21:08:35 +01:00
33d715ca83 use 9600 Baud 2020-09-03 20:50:42 +01:00
fdcd37c125
termination handler 2020-09-03 21:41:12 +02:00
20d617a10d shorter loop enable period 2020-09-03 20:35:27 +01:00
c0556dfa1c
fix 2020-09-03 17:09:25 +02:00
4a02773d6d
fix 2020-09-03 16:09:51 +02:00
5b6a9fa1ad
fix 2020-09-03 16:08:29 +02:00
ff515e202a
fix 2020-09-03 16:07:09 +02:00
76db8066b9
rename 2020-09-03 16:05:14 +02:00
0371c2174e
fix 2020-09-03 16:03:50 +02:00
d65b0b1203
fix 2020-09-03 16:01:52 +02:00
7e6e6d8df0
logging 2020-09-03 14:40:35 +02:00
fb44b8b237
logging 2020-09-03 14:20:41 +02:00
59f4c2d972
error handling and reporting 2020-09-03 14:05:25 +02:00
dfee439030 works also in line mode so far 2020-08-31 22:32:37 +01:00
fb1b6dbc3a works so far 2020-08-31 21:58:34 +01:00
132dd92b37 c translation initial 2020-08-31 18:29:37 +01:00
32f7e1c87c ignore o files and executable 2020-08-31 18:29:11 +01:00
cee0a5de71 count cycles 2020-08-30 21:21:20 +01:00
910be985b1 disable debugging 2020-08-30 21:18:48 +01:00
8c694753f7
debugging 2020-08-30 22:15:59 +02:00
93adb7a5d4
code beautifying 2020-08-30 22:13:30 +02:00
4e07e84ce7 pretty print 2020-08-30 10:54:02 +01:00
bbdd078da8 fix 2020-08-29 17:01:54 +01:00
13cced9c64
stats 2020-08-29 18:00:39 +02:00
4393f3747b
decrease delay 2020-08-29 17:54:00 +02:00
11f963f911
fix 2020-08-29 17:52:14 +02:00
4e85de2225
error handling 2020-08-29 17:51:16 +02:00
1b03a1187e
ord 2020-08-29 17:43:30 +02:00
aab02ca10b
forgot to call open 2020-08-29 17:42:07 +02:00
436fbb720d
timeout 2020-08-29 17:40:47 +02:00
8ebab69fca fix 2020-08-29 16:29:56 +01:00
f8e317bb09 cycling 2020-08-29 13:54:42 +01:00
3052af1de5 works so far 2020-08-29 13:38:34 +01:00
d3411ad48f
Merge branch 'master' of ssh://home.hottis.de:2922/wolutator/mbus-gateway 2020-08-29 14:33:48 +02:00
0e01b0b1df
wait for tx empty 2020-08-29 14:33:32 +02:00
6d7aaa3cb7 format 2020-08-29 12:52:16 +01:00
1ecc18dfee
fix 2020-08-29 13:50:24 +02:00
a2717e1a2e use ord here too 2020-08-29 12:49:27 +01:00
5 changed files with 800 additions and 18 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
*.pyc *.pyc
.*.sw? .*.sw?
*.o
mbusgw

View File

@ -2,6 +2,12 @@ import wiringpi
from time import sleep from time import sleep
import serial import serial
from enum import Enum from enum import Enum
import array
import fcntl
import termios
import pprint
LOOP_ENABLE = 18 LOOP_ENABLE = 18
LOOP_DISABLE = 23 LOOP_DISABLE = 23
@ -89,12 +95,13 @@ class MeterbusResponseStates(Enum):
START2 = 4 START2 = 4
C_FIELD = 5 C_FIELD = 5
A_FIELD = 6 A_FIELD = 6
C_FIELD = 7 CI_FIELD = 7
USERDATA = 8 USERDATA = 8
CHKSUM = 9 CHKSUM = 9
STOP = 10 STOP = 10
DONE = 99 DONE = 99
ERROR = 100 ERROR = 100
TIMEOUT = 101
def a2h(a): def a2h(a):
return [ hex(x) for x in a ] return [ hex(x) for x in a ]
@ -102,24 +109,33 @@ def a2h(a):
class MeterbusSerial(object): class MeterbusSerial(object):
def __init__(self): def __init__(self):
self.port = serial.Serial('/dev/ttyAMA0', baudrate=2400, bytesize=8, parity='E', self.port = serial.Serial('/dev/ttyAMA0', baudrate=2400, bytesize=8, parity='E',
stopbits=1, timeout=None, xonxoff=0, rtscts=0) stopbits=1, timeout=1.0, xonxoff=0, rtscts=0)
def open(self):
loop(True)
sleep(0.5)
def close(self):
loop(False)
def shortFrameRequest(self, cmd, addr): def shortFrameRequest(self, cmd, addr):
chksum = (cmd + addr) & 0x00ff chksum = (cmd + addr) & 0x00ff
msg = bytearray([0x10, cmd, addr, chksum, 0x16]) msg = bytearray([0x10, cmd, addr, chksum, 0x16])
print(a2h(msg)) # print(a2h(msg))
frontendSample() frontendSample()
frontendRxEnable(False)
self.port.write(msg) self.port.write(msg)
# FIXME: Attention, the actual write time of the interface is not considered. buf = array.array('h', [0])
# This is a measured value. while True:
sleep(0.030) fcntl.ioctl(self.port.fileno(), termios.TIOCSERGETLSR, buf, 1)
if buf[0] & termios.TIOCSER_TEMT:
break
sleep(0.001)
frontendHold() frontendHold()
frontendRxEnable(True)
frameData = [] frameData = []
frame = { frame = {
@ -131,21 +147,132 @@ class MeterbusSerial(object):
} }
expectedUserDataOctets = 0 expectedUserDataOctets = 0
state = MeterbusResponseStates.START1 state = MeterbusResponseStates.START1
while (state not in [MeterbusResponseStates.DONE, MeterbusResponseStates.ERROR]): while (state not in [MeterbusResponseStates.DONE, MeterbusResponseStates.ERROR, MeterbusResponseStates.TIMEOUT]):
print("Waiting for input ... ") # print("Waiting for input ... ")
c = self.port.read() c = self.port.read(1)
if len(c) == 0:
state = MeterbusResponseStates.TIMEOUT
continue
c = ord(c)
print("State {}, Octet {:02X}".format(state, ord(c))) # print("State {}, Octet 0x{:02X}".format(state, c))
if state == MeterbusResponseStates.START1:
if c == 0x68:
frameData.append(c)
state = MeterbusResponseStates.LENGTH1
else:
print('Invalid start1 symbol')
state = MeterbusResponseStates.ERROR
elif state == MeterbusResponseStates.LENGTH1:
frameData.append(c)
frame['l'] = c
expectedUserDataOctets = frame['l'] - 3
state = MeterbusResponseStates.LENGTH2
elif state == MeterbusResponseStates.LENGTH2:
frameData.append(c)
if frame['l'] == c:
state = MeterbusResponseStates.START2
else:
print('Invalid length 2 octet')
state = MeterbusResponseStates.ERROR
elif state == MeterbusResponseStates.START2:
frameData.append(c)
if c == 0x68:
frameData.append(c)
state = MeterbusResponseStates.C_FIELD
else:
print('Invalid start2 symbol')
state = MeterbusResponseStates.ERROR
elif state == MeterbusResponseStates.C_FIELD:
frameData.append(c)
frame['c'] = c
state = MeterbusResponseStates.A_FIELD
elif state == MeterbusResponseStates.A_FIELD:
frameData.append(c)
frame['a'] = c
state = MeterbusResponseStates.CI_FIELD
elif state == MeterbusResponseStates.CI_FIELD:
frameData.append(c)
frame['ci'] = c
state = MeterbusResponseStates.USERDATA
elif state == MeterbusResponseStates.USERDATA:
frameData.append(c)
frame['userdata'].append(c)
expectedUserDataOctets -= 1
if expectedUserDataOctets == 0:
state = MeterbusResponseStates.CHKSUM
elif state == MeterbusResponseStates.CHKSUM:
frameData.append(c)
responseChksum = c
calculatedChksum = (frame['c'] + frame['a'] + frame['ci'] + sum(frame['userdata'])) & 0x00ff
if responseChksum != calculatedChksum:
print('Invalid checksum {} {}'.format(responseChksum, calculatedChksum))
state = MeterbusResponseStates.ERROR
else:
state = MeterbusResponseStates.STOP
elif state == MeterbusResponseStates.STOP:
frameData.append(c)
if c == 0x16:
state = MeterbusResponseStates.DONE
else:
print('Invalid stop symbol')
state = MeterbusResponseStates.ERROR
else:
print('Invalid state')
state = MeterbusResponseStates.ERROR
# print(a2h(frameData))
res = {}
if state == MeterbusResponseStates.DONE:
res = {'status': 'OK', 'frame': frameData, 'c': frame['c'], 'a': frame['a'], 'ci': frame['ci'], 'userdata': frame['userdata']}
else:
res = {'status': 'ERROR', 'code': state }
return res
if __name__ == "__main__": if __name__ == "__main__":
init() init()
loop(False) loop(False)
sleep(5.0) sleep(2.0)
loop(True)
sleep(5.0)
m = MeterbusSerial() m = MeterbusSerial()
m.shortFrameRequest(0x5b, 84) m.open()
devices = [ 84, 87, 86, 85, 82, 81, 83, 80 ]
stats = {
'total': {
'cycles': 0,
'ok': 0,
'error': 0
},
'devices': { x: { 'ok': 0, 'error': 0 } for x in devices }
}
pp = pprint.PrettyPrinter(indent=4)
while True:
for a in devices:
r = m.shortFrameRequest(0x5b, a)
stats['total']['cycles'] += 1
if r['status'] == 'ERROR':
stats['total']['error'] += 1
stats['devices'][a]['error'] += 1
print("Error for {}, last state was {}, restarting loop".format(a, r['code']))
m.close()
sleep(5)
m.open()
else:
stats['total']['ok'] += 1
stats['devices'][a]['ok'] += 1
sleep(1)
pp.pprint(stats)
print("")
sleep(15)

23
src/Makefile Normal file
View File

@ -0,0 +1,23 @@
CC=gcc
CFLAGS=-Wall
LDFLAGS=-lwiringPi
mbusgw: mbusgw.o
$(CC) -o $@ $(LDFLAGS) $^
mbusgw.o: mbusgw.c mbusgw.h
%.o : %.c
$(CC) $(CFLAGS) -c $<
.PHONY: all
all: mbusgw
.PHONY: install
install: all
sudo cp mbusgw /usr/local/bin/
.PHONY: clean
clean:
-rm -f *.o mbusgw

569
src/mbusgw.c Normal file
View File

@ -0,0 +1,569 @@
#include <wiringPi.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include "mbusgw.h"
typedef enum {
e_START1,
e_LENGTH1,
e_LENGTH2,
e_START2,
e_C_FIELD,
e_A_FIELD,
e_CI_FIELD,
e_USERDATA,
e_CHKSUM,
e_STOP,
e_DONE,
e_ERROR,
e_TIMEOUT
} t_state;
int serialFd;
bool verbose = false;
bool loopActiveFlag = false;
bool loopEnabled = false;
void msleep(uint32_t t) {
usleep(t * 1000);
}
void infolog(const char *format, ...) {
va_list ap;
va_start(ap, format);
if (verbose) {
vfprintf(stderr, format, ap);
}
va_end(ap);
}
void errlog(const char *format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
void ledRed(bool v) {
if (v) {
digitalWrite(LED_RED, HIGH);
} else {
digitalWrite(LED_RED, LOW);
}
}
void ledGreen(bool v) {
if (v) {
digitalWrite(LED_GREEN, HIGH);
} else {
digitalWrite(LED_GREEN, LOW);
}
}
void frontendReset() {
digitalWrite(FRONTEND_RESET, LOW);
msleep(25);
digitalWrite(FRONTEND_RESET, HIGH);
msleep(100);
}
void loopControl(bool v) {
if (v) {
digitalWrite(LOOP_ENABLE, HIGH);
msleep(5);
digitalWrite(LOOP_ENABLE, LOW);
loopEnabled = true;
} else {
loopEnabled = false;
digitalWrite(LOOP_DISABLE, HIGH);
digitalWrite(LOOP_DISABLE, LOW);
}
}
void frontendSample() {
digitalWrite(FRONTEND_SAMPLE_HOLD, LOW);
}
void frontendHold() {
digitalWrite(FRONTEND_SAMPLE_HOLD, HIGH);
}
void loopStatusISR() {
loopActiveFlag = digitalRead(LOOP_STATUS) == LOW;
if ((! loopActiveFlag) && (loopEnabled)) {
loopEnabled = false;
ledRed(true);
}
}
void myExit(int e) {
ledRed(false);
ledGreen(false);
loopControl(false);
frontendSample();
exit(e);
}
void termHandler(int signum)
{
infolog("Termination requested via signal\n");
myExit(0);
}
void init() {
infolog("Register termination handler\n");
signal(SIGTERM, termHandler);
signal(SIGINT, termHandler);
infolog("setting up gpios\n");
wiringPiSetupGpio();
pinMode(LOOP_ENABLE, OUTPUT);
digitalWrite(LOOP_ENABLE, LOW);
pinMode(LOOP_DISABLE, OUTPUT);
digitalWrite(LOOP_DISABLE, LOW);
pinMode(FRONTEND_RESET, OUTPUT);
digitalWrite(FRONTEND_RESET, LOW);
pinMode(FRONTEND_SAMPLE_HOLD, OUTPUT);
digitalWrite(FRONTEND_SAMPLE_HOLD, LOW);
pinMode(LED_RED, OUTPUT);
digitalWrite(LED_RED, LOW);
pinMode(LED_GREEN, OUTPUT);
digitalWrite(LED_GREEN, LOW);
pinMode(LOOP_STATUS, INPUT);
pullUpDnControl(LOOP_STATUS, PUD_UP);
wiringPiISR(LOOP_STATUS, INT_EDGE_BOTH, loopStatusISR);
frontendReset();
loopControl(false);
}
int openSerial(char *serialDevice, uint32_t speedNum) {
int fd = open(serialDevice, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
errlog("error %d opening serial device %s: %s\n",
errno, serialDevice, strerror(errno));
return -1;
}
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
errlog("error %d getting attributes for serial device %s: %s\n",
errno, serialDevice, strerror(errno));
return -1;
}
int speed;
switch (speedNum) {
case 1200:
speed = B1200;
break;
case 2400:
speed = B2400;
break;
case 4800:
speed = B4800;
break;
case 9600:
speed = B9600;
break;
default:
errlog("speed %d not supported\n", speedNum);
return -1;
}
cfsetospeed(&tty, speed);
cfsetispeed(&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag &= ~(CRTSCTS | CSTOPB | PARODD);
tty.c_cflag |= (CLOCAL | CREAD | PARENB);
tty.c_lflag = 0;
tty.c_oflag = 0;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 50;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_iflag |= IGNBRK;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
errlog("error %d setting attributes for serial device %s: %s\n",
errno, serialDevice, strerror(errno));
return -1;
}
loopControl(true);
msleep(2000);
return fd;
}
void closeSerial(int fd) {
loopControl(false);
close(fd);
}
uint8_t request(int fd, uint8_t cmd, uint8_t addr, t_longframe **retFrame) {
uint8_t retCode = SUCCESS;
t_longframe *frame = (t_longframe*) malloc(sizeof(t_longframe));
if (! frame) {
errlog("unable to allocate memory for frame\n");
return ERROR_OUT_OF_MEMORY__FRAME;
}
frame->userdata = NULL;
uint8_t chksum = cmd + addr;
frontendSample();
uint8_t sendBuf[5];
sendBuf[0] = 0x10;
sendBuf[1] = cmd;
sendBuf[2] = addr;
sendBuf[3] = chksum;
sendBuf[4] = 0x16;
write(fd, sendBuf, 5);
while (1) {
int r;
if (ioctl(fd, TIOCSERGETLSR, &r) == -1) {
errlog("error %d getting TIOCSERGETLSR for fd %d: %s\n",
errno, fd, strerror(errno));
free(frame);
frame = NULL;
return ERROR_TX_REG_UNACCESSIBLE;
}
if (r & TIOCSER_TEMT) {
break;
}
}
msleep(1);
frontendHold();
uint8_t userdataIdx = 0;
uint8_t calculatedChksum = 0;
t_state state = e_START1;
while ((state != e_DONE) &&
(state != e_TIMEOUT)) {
infolog("waiting for input ...\n");
uint8_t c;
ssize_t s = read(fd, &c, 1);
if (s == 0) {
errlog("timeout waiting for input\n");
state = e_TIMEOUT;
continue;
}
infolog("state %d, Octet %02x\n", state, c);
switch(state) {
case e_START1:
if (c == 0x68) {
frame->start1 = c;
state = e_LENGTH1;
} else {
errlog("invalid start1 symbol %02x\n", c);
retCode = ERROR_STATE_ENGINE__START1;
state = e_ERROR;
}
break;
case e_LENGTH1:
if (c <= 3) {
errlog("length to small %02x\n", c);
retCode = ERROR_STATE_ENGINE__LENGTH1;
state = e_ERROR;
} else {
frame->length1 = c;
frame->userdata = (uint8_t*) malloc(frame->length1 - 3);
if (! frame->userdata) {
errlog("unable to allocate memory for userdata\n");
retCode = ERROR_OUT_OF_MEMORY__USERDATA;
state = e_ERROR;
}
state = e_LENGTH2;
}
break;
case e_LENGTH2:
if (frame->length1 != c) {
errlog("invalid length2 %02x vs. %02x\n", frame->length1, c);
retCode = ERROR_STATE_ENGINE__LENGTH2;
state = e_ERROR;
} else {
frame->length2 = c;
state = e_START2;
}
break;
case e_START2:
if (c == 0x68) {
frame->start2 = c;
state = e_C_FIELD;
} else {
errlog("invalid start2 symbol %02x\n", c);
retCode = ERROR_STATE_ENGINE__START2;
state = e_ERROR;
}
break;
case e_C_FIELD:
frame->c = c;
calculatedChksum += c;
state = e_A_FIELD;
break;
case e_A_FIELD:
frame->a = c;
calculatedChksum += c;
state = e_CI_FIELD;
break;
case e_CI_FIELD:
frame->ci = c;
calculatedChksum += c;
state = e_USERDATA;
break;
case e_USERDATA:
frame->userdata[userdataIdx] = c;
calculatedChksum += c;
userdataIdx++;
if (userdataIdx == (frame->length1 - 3)) {
state = e_CHKSUM;
}
break;
case e_CHKSUM:
if (c != calculatedChksum) {
errlog("invalid checksum %02x vs %02x\n", calculatedChksum, c);
retCode = ERROR_STATE_ENGINE__INVALID_CHKSUM;
state = e_ERROR;
} else {
frame->chksum = c;
state = e_STOP;
}
break;
case e_STOP:
if (c == 0x16) {
frame->stop = c;
state = e_DONE;
} else {
errlog("invalid stop symbol %02x\n", c);
retCode = ERROR_STATE_ENGINE__STOP;
state = e_ERROR;
}
break;
case e_ERROR:
ledRed(true);
infolog("already error, read the rest (now: %02x) until timeout\n", c);
break;
default:
errlog("illegal state %d\n", state);
retCode = ERROR_STATE_ENGINE__ILLEGAL_STATE;
state = e_ERROR;
break;
}
}
if ((state == e_ERROR) || (state == e_TIMEOUT)) {
if (state == e_ERROR) {
if (retCode == SUCCESS) {
retCode = ERROR_STATE_ENGINE__UNKNOWN;
}
} else if (state == e_TIMEOUT) {
if (retCode == SUCCESS) {
retCode = ERROR_TIMEOUT;
}
}
if (frame->userdata) {
free(frame->userdata);
frame->userdata = NULL;
}
free(frame);
frame = NULL;
}
*retFrame = frame;
return retCode;
}
void printFrame(bool hexOut, t_longframe *frame) {
if (hexOut) {
fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n",
frame->start1, frame->length1, frame->length2, frame->start2,
frame->c, frame->a, frame->ci);
for (uint8_t i = 0; i < (frame->length1 - 3); i++) {
if (i && !(i % 16)) {
fprintf(stderr, "\n");
}
fprintf(stderr, "%02x ", frame->userdata[i]);
}
fprintf(stderr, "\n");
fprintf(stderr, "%02x %02x\n", frame->chksum, frame->stop);
} else {
fprintf(stdout, "%c%c", 0, frame->length1 + 6);
fprintf(stdout, "%c%c%c%c%c%c%c",
frame->start1, frame->length1, frame->length2, frame->start2,
frame->c, frame->a, frame->ci);
for (uint8_t i = 0; i < (frame->length1 - 3); i++) {
fprintf(stdout, "%c", frame->userdata[i]);
}
fprintf(stdout, "%c%c", frame->chksum, frame->stop);
fflush(stdout);
}
}
int main(int argc, char *argv[]) {
init();
ledGreen(true);
int exitCode = 0;
bool hexOut = false;
bool lineMode = false;
uint8_t addr = 0;
uint8_t cmd = 0x5b;
int opt;
while ((opt = getopt(argc, argv, "lhvxc:a:")) != -1) {
switch(opt) {
case 'h':
errlog("mbusgw - interface access tool for meterbus gateway\n");
errlog("-h ... Show this help page\n");
errlog("-v ... Verbose output\n");
errlog("-x ... Output as hex string in 'human-readable' form\n");
errlog("-a addr ... Address of device to be queried\n");
errlog("-c cmd ... Command to be sent, default is 0x5b\n");
errlog("-l ... Read cmd and addr from stdin unless\n");
errlog(" 0x00 0x00 is provided and return the\n");
errlog(" result on stdout.\n");
errlog(" It is preceeds by 0x00 for okay and the\n");
errlog(" length.\n");
errlog(" In case of an error it will by 0xff followed\n");
errlog(" by one octet with an error code\n");
errlog("\n");
break;
case 'v':
verbose = true;
break;
case 'l':
lineMode = true;
break;
case 'x':
hexOut = true;
break;
case 'a':
addr = (uint8_t) strtol(optarg, NULL, 0);
break;
case 'c':
cmd = (uint8_t) strtol(optarg, NULL, 0);
break;
}
}
infolog("opening device\n");
int fd = openSerial(DEFAULT_SERIAL_DEVICE, BAUDRATE);
if (fd == -1) {
errlog("unable to open device, fatal error\n");
myExit(-1);
}
while (1) {
if (lineMode) {
infolog("lineMode, waiting for input\n");
fread(&cmd, 1, 1, stdin);
fread(&addr, 1, 1, stdin);
}
if (lineMode && (cmd == LINEMODE_CMD_PREFIX)) {
if (addr == LINEMODE_CMD_TERMINATE) {
infolog("termination requested\n");
break;
}
if (addr == LINEMODE_CMD_LOOP_SHUTDOWN) {
infolog("loop shutdown requested\n");
loopControl(false);
continue;
}
}
if (! loopActiveFlag) {
errlog("loop is not active, enable it and delay\n");
loopControl(true);
msleep(2000);
}
infolog("sending request %02x %02x\n", cmd, addr);
t_longframe *frame = NULL;
uint8_t requestReturnCode = 0;
if (loopActiveFlag) {
ledRed(false);
requestReturnCode = request(fd, cmd, addr, &frame);
} else {
errlog("loop is currently inactive, no need to try\n");
requestReturnCode = ERROR_LOOP_FAILURE;
}
if (requestReturnCode == SUCCESS) {
infolog("received a valid frame\n");
printFrame(hexOut, frame);
free(frame->userdata);
frame->userdata = NULL;
free(frame);
frame = NULL;
} else {
ledRed(true);
if (! loopActiveFlag) {
requestReturnCode = ERROR_LOOP_FAILURE;
}
errlog("error %04x occured\n", requestReturnCode);
if (! hexOut) {
fprintf(stdout, "%c%c", requestReturnCode, 0);
fflush(stdout);
}
if (! lineMode) {
exitCode = -2;
}
}
if (! lineMode) {
break;
}
}
infolog("closing device\n");
closeSerial(fd);
myExit(exitCode);
}

60
src/mbusgw.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef _MBUSGW_H_
#define _MBUSGW_H_
#include <stdint.h>
#define LOOP_ENABLE 18
#define LOOP_DISABLE 23
#define LOOP_STATUS 22
#define FRONTEND_RESET 26
#define FRONTEND_SAMPLE_HOLD 19
#define LED_RED 5
#define LED_GREEN 6
#define DEFAULT_SERIAL_DEVICE "/dev/ttyAMA0"
#define BAUDRATE 2400
#define LINEMODE_CMD_PREFIX 0
#define LINEMODE_CMD_TERMINATE 0
#define LINEMODE_CMD_LOOP_SHUTDOWN 1
#define SUCCESS 0
#define ERROR_TIMEOUT 1
#define ERROR_LOOP_FAILURE 2
#define ERROR_TX_REG_UNACCESSIBLE 3
#define ERROR_OUT_OF_MEMORY__FRAME 4
#define ERROR_OUT_OF_MEMORY__USERDATA 5
#define ERROR_STATE_ENGINE__START1 10
#define ERROR_STATE_ENGINE__LENGTH1 11
#define ERROR_STATE_ENGINE__LENGTH2 12
#define ERROR_STATE_ENGINE__START2 13
#define ERROR_STATE_ENGINE__INVALID_CHKSUM 14
#define ERROR_STATE_ENGINE__STOP 15
#define ERROR_STATE_ENGINE__ILLEGAL_STATE 16
#define ERROR_STATE_ENGINE__UNKNOWN 17
typedef struct {
uint8_t start1;
uint8_t length1;
uint8_t length2;
uint8_t start2;
uint8_t l;
uint8_t c;
uint8_t a;
uint8_t ci;
uint8_t *userdata;
uint8_t chksum;
uint8_t stop;
} t_longframe;
#endif