17 Commits

3 changed files with 115 additions and 79 deletions

View File

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

View File

@ -32,15 +32,17 @@ typedef enum {
} t_state; } t_state;
static bool verbose = false; int serialFd;
static bool loopActiveFlag = false; bool verbose = false;
bool loopActiveFlag = false;
bool loopEnabled = false;
static void msleep(uint32_t t) { void msleep(uint32_t t) {
usleep((useconds_t)(t * 1000)); usleep(t * 1000);
} }
static void infolog(const char *format, ...) { void infolog(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
if (verbose) { if (verbose) {
@ -49,7 +51,7 @@ static void infolog(const char *format, ...) {
va_end(ap); va_end(ap);
} }
static void errlog(const char *format, ...) { void errlog(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
vfprintf(stderr, format, ap); vfprintf(stderr, format, ap);
@ -57,7 +59,7 @@ static void errlog(const char *format, ...) {
} }
static void ledRed(bool v) { void ledRed(bool v) {
if (v) { if (v) {
digitalWrite(LED_RED, HIGH); digitalWrite(LED_RED, HIGH);
} else { } else {
@ -65,64 +67,67 @@ static void ledRed(bool v) {
} }
} }
static void ledGreen(bool v) { void ledGreen(bool v) {
if (v) { if (v) {
digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_GREEN, HIGH);
} else { } else {
digitalWrite(LED_GREEN, LOW); digitalWrite(LED_GREEN, LOW);
} }
} }
void frontendReset() {
static void frontendReset() {
digitalWrite(FRONTEND_RESET, LOW); digitalWrite(FRONTEND_RESET, LOW);
msleep(25); msleep(25);
digitalWrite(FRONTEND_RESET, HIGH); digitalWrite(FRONTEND_RESET, HIGH);
msleep(100); msleep(100);
} }
static void loopControl(bool v) { void loopControl(bool v) {
if (v) { if (v) {
digitalWrite(LOOP_ENABLE, HIGH); digitalWrite(LOOP_ENABLE, HIGH);
msleep(5); msleep(5);
digitalWrite(LOOP_ENABLE, LOW); digitalWrite(LOOP_ENABLE, LOW);
loopEnabled = true;
} else { } else {
loopEnabled = false;
digitalWrite(LOOP_DISABLE, HIGH); digitalWrite(LOOP_DISABLE, HIGH);
digitalWrite(LOOP_DISABLE, LOW); digitalWrite(LOOP_DISABLE, LOW);
} }
} }
static void frontendSample() { void frontendSample() {
digitalWrite(FRONTEND_SAMPLE_HOLD, LOW); digitalWrite(FRONTEND_SAMPLE_HOLD, LOW);
} }
static void frontendHold() { void frontendHold() {
digitalWrite(FRONTEND_SAMPLE_HOLD, HIGH); digitalWrite(FRONTEND_SAMPLE_HOLD, HIGH);
} }
static void loopStatusISR() { void loopStatusISR() {
loopActiveFlag = digitalRead(LOOP_STATUS) == LOW; loopActiveFlag = digitalRead(LOOP_STATUS) == LOW;
if (! loopActiveFlag) { if ((! loopActiveFlag) && (loopEnabled)) {
loopEnabled = false;
ledRed(true); ledRed(true);
} }
} }
static void deinit() { void myExit(int e) {
ledRed(false); ledRed(false);
ledGreen(false); ledGreen(false);
loopControl(false); loopControl(false);
frontendSample(); frontendSample();
exit(e);
} }
static void termHandler(/*@unused@*/ int signum) void termHandler(int signum)
{ {
infolog("Termination requested via signal\n"); infolog("Termination requested via signal\n");
deinit(); myExit(0);
exit(EXIT_SUCCESS);
} }
static void init() { void init() {
infolog("Register termination handler\n"); infolog("Register termination handler\n");
signal(SIGTERM, termHandler); signal(SIGTERM, termHandler);
signal(SIGINT, termHandler); signal(SIGINT, termHandler);
@ -159,7 +164,7 @@ static void init() {
loopControl(false); loopControl(false);
} }
static int openSerial(char *serialDevice, uint32_t speedNum) { int openSerial(char *serialDevice, uint32_t speedNum) {
int fd = open(serialDevice, O_RDWR | O_NOCTTY | O_SYNC); int fd = open(serialDevice, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) { if (fd < 0) {
errlog("error %d opening serial device %s: %s\n", errlog("error %d opening serial device %s: %s\n",
@ -221,20 +226,20 @@ static int openSerial(char *serialDevice, uint32_t speedNum) {
return fd; return fd;
} }
static void closeSerial(int fd) { void closeSerial(int fd) {
loopControl(false); loopControl(false);
close(fd); close(fd);
} }
static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) { uint8_t request(int fd, uint8_t cmd, uint8_t addr, t_longframe **retFrame) {
errno = 0; uint8_t retCode = SUCCESS;
t_longframe *frame = (t_longframe*) malloc(sizeof(t_longframe)); t_longframe *frame = (t_longframe*) malloc(sizeof(t_longframe));
if (! frame) { if (! frame) {
errlog("unable to allocate memory for frame\n"); errlog("unable to allocate memory for frame\n");
return NULL; return ERROR_OUT_OF_MEMORY__FRAME;
} }
memset(frame, 0, sizeof(t_longframe)); frame->userdata = NULL;
uint8_t chksum = cmd + addr; uint8_t chksum = cmd + addr;
@ -248,20 +253,16 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
sendBuf[4] = 0x16; sendBuf[4] = 0x16;
write(fd, sendBuf, 5); write(fd, sendBuf, 5);
while (true) { while (1) {
int r = 0; int r;
if (ioctl(fd, TIOCSERGETLSR, &r) == -1) { if (ioctl(fd, TIOCSERGETLSR, &r) == -1) {
errlog("error %d getting TIOCSERGETLSR for fd %d: %s\n", errlog("error %d getting TIOCSERGETLSR for fd %d: %s\n",
errno, fd, strerror(errno)); errno, fd, strerror(errno));
errno = ERROR_APP_SPECIFIC_ERROR_FLAG | ERROR_TX_REG_UNACCESSIBLE;
if (frame->userdata) {
free(frame->userdata);
}
free(frame); free(frame);
frame = NULL; frame = NULL;
return NULL; return ERROR_TX_REG_UNACCESSIBLE;
} }
if ((r & TIOCSER_TEMT) != 0) { if (r & TIOCSER_TEMT) {
break; break;
} }
} }
@ -274,7 +275,6 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
t_state state = e_START1; t_state state = e_START1;
while ((state != e_DONE) && while ((state != e_DONE) &&
(state != e_ERROR) &&
(state != e_TIMEOUT)) { (state != e_TIMEOUT)) {
infolog("waiting for input ...\n"); infolog("waiting for input ...\n");
@ -295,21 +295,21 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
state = e_LENGTH1; state = e_LENGTH1;
} else { } else {
errlog("invalid start1 symbol %02x\n", c); errlog("invalid start1 symbol %02x\n", c);
retCode = ERROR_STATE_ENGINE__START1;
state = e_ERROR; state = e_ERROR;
} }
break; break;
case e_LENGTH1: case e_LENGTH1:
if (c <= 3) { if (c <= 3) {
errlog("length to small %02x\n", c); errlog("length to small %02x\n", c);
retCode = ERROR_STATE_ENGINE__LENGTH1;
state = e_ERROR; state = e_ERROR;
} else { } else {
frame->length1 = c; frame->length1 = c;
if (frame->userdata) {
free(frame->userdata);
}
frame->userdata = (uint8_t*) malloc(frame->length1 - 3); frame->userdata = (uint8_t*) malloc(frame->length1 - 3);
if (! frame->userdata) { if (! frame->userdata) {
errlog("unable to allocate memory for userdata\n"); errlog("unable to allocate memory for userdata\n");
retCode = ERROR_OUT_OF_MEMORY__USERDATA;
state = e_ERROR; state = e_ERROR;
} }
state = e_LENGTH2; state = e_LENGTH2;
@ -318,6 +318,7 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
case e_LENGTH2: case e_LENGTH2:
if (frame->length1 != c) { if (frame->length1 != c) {
errlog("invalid length2 %02x vs. %02x\n", frame->length1, c); errlog("invalid length2 %02x vs. %02x\n", frame->length1, c);
retCode = ERROR_STATE_ENGINE__LENGTH2;
state = e_ERROR; state = e_ERROR;
} else { } else {
frame->length2 = c; frame->length2 = c;
@ -330,6 +331,7 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
state = e_C_FIELD; state = e_C_FIELD;
} else { } else {
errlog("invalid start2 symbol %02x\n", c); errlog("invalid start2 symbol %02x\n", c);
retCode = ERROR_STATE_ENGINE__START2;
state = e_ERROR; state = e_ERROR;
} }
break; break;
@ -359,6 +361,7 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
case e_CHKSUM: case e_CHKSUM:
if (c != calculatedChksum) { if (c != calculatedChksum) {
errlog("invalid checksum %02x vs %02x\n", calculatedChksum, c); errlog("invalid checksum %02x vs %02x\n", calculatedChksum, c);
retCode = ERROR_STATE_ENGINE__INVALID_CHKSUM;
state = e_ERROR; state = e_ERROR;
} else { } else {
frame->chksum = c; frame->chksum = c;
@ -371,11 +374,17 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
state = e_DONE; state = e_DONE;
} else { } else {
errlog("invalid stop symbol %02x\n", c); errlog("invalid stop symbol %02x\n", c);
retCode = ERROR_STATE_ENGINE__STOP;
state = e_ERROR; state = e_ERROR;
} }
break; break;
case e_ERROR:
ledRed(true);
infolog("already error, read the rest (now: %02x) until timeout\n", c);
break;
default: default:
errlog("illegal state %d\n", state); errlog("illegal state %d\n", state);
retCode = ERROR_STATE_ENGINE__ILLEGAL_STATE;
state = e_ERROR; state = e_ERROR;
break; break;
} }
@ -383,9 +392,13 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
if ((state == e_ERROR) || (state == e_TIMEOUT)) { if ((state == e_ERROR) || (state == e_TIMEOUT)) {
if (state == e_ERROR) { if (state == e_ERROR) {
errno = ERROR_TX_REG_UNACCESSIBLE | ERROR_STATE_ENGINE; if (retCode == SUCCESS) {
retCode = ERROR_STATE_ENGINE__UNKNOWN;
}
} else if (state == e_TIMEOUT) { } else if (state == e_TIMEOUT) {
errno = ERROR_TX_REG_UNACCESSIBLE | ERROR_TIMEOUT; if (retCode == SUCCESS) {
retCode = ERROR_TIMEOUT;
}
} }
if (frame->userdata) { if (frame->userdata) {
free(frame->userdata); free(frame->userdata);
@ -395,17 +408,17 @@ static /*@null@*/ t_longframe *request(int fd, uint8_t cmd, uint8_t addr) {
frame = NULL; frame = NULL;
} }
return frame; *retFrame = frame;
return retCode;
} }
static void printFrame(bool hexOut, t_longframe *frame) { void printFrame(bool hexOut, t_longframe *frame) {
if (hexOut) { if (hexOut) {
fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n", fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n",
frame->start1, frame->length1, frame->length2, frame->start2, frame->start1, frame->length1, frame->length2, frame->start2,
frame->c, frame->a, frame->ci); frame->c, frame->a, frame->ci);
uint8_t i = 0; for (uint8_t i = 0; i < (frame->length1 - 3); i++) {
for (i = 0; i < (frame->length1 - 3); i++) { if (i && !(i % 16)) {
if ((i != 0) && ((i % 16) == 0)) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
fprintf(stderr, "%02x ", frame->userdata[i]); fprintf(stderr, "%02x ", frame->userdata[i]);
@ -417,8 +430,7 @@ static void printFrame(bool hexOut, t_longframe *frame) {
fprintf(stdout, "%c%c%c%c%c%c%c", fprintf(stdout, "%c%c%c%c%c%c%c",
frame->start1, frame->length1, frame->length2, frame->start2, frame->start1, frame->length1, frame->length2, frame->start2,
frame->c, frame->a, frame->ci); frame->c, frame->a, frame->ci);
uint8_t i = 0; for (uint8_t i = 0; i < (frame->length1 - 3); i++) {
for (i = 0; i < (frame->length1 - 3); i++) {
fprintf(stdout, "%c", frame->userdata[i]); fprintf(stdout, "%c", frame->userdata[i]);
} }
fprintf(stdout, "%c%c", frame->chksum, frame->stop); fprintf(stdout, "%c%c", frame->chksum, frame->stop);
@ -476,41 +488,49 @@ int main(int argc, char *argv[]) {
infolog("opening device\n"); infolog("opening device\n");
int fd = openSerial(DEFAULT_SERIAL_DEVICE, 2400); int fd = openSerial(DEFAULT_SERIAL_DEVICE, BAUDRATE);
if (fd == -1) { if (fd == -1) {
errlog("unable to open device, fatal error\n"); errlog("unable to open device, fatal error\n");
deinit(); myExit(-1);
exit(EXIT_FAILURE);
} }
while (true) { 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) { if (! loopActiveFlag) {
errlog("loop is not active, enable it and delay\n"); errlog("loop is not active, enable it and delay\n");
loopControl(true); loopControl(true);
msleep(2000); msleep(2000);
} }
if (lineMode) {
infolog("lineMode, waiting for input\n");
fread(&cmd, 1, 1, stdin);
fread(&addr, 1, 1, stdin);
}
if ((cmd == 0) && (addr == 0)) {
errlog("termination requested\n");
break;
}
infolog("sending request %02x %02x\n", cmd, addr); infolog("sending request %02x %02x\n", cmd, addr);
t_longframe *frame = NULL; t_longframe *frame = NULL;
uint8_t requestReturnCode = 0;
if (loopActiveFlag) { if (loopActiveFlag) {
ledRed(false); ledRed(false);
frame = request(fd, cmd, addr); requestReturnCode = request(fd, cmd, addr, &frame);
} else { } else {
errlog("loop is currently inactive, no need to try\n"); errlog("loop is currently inactive, no need to try\n");
requestReturnCode = ERROR_LOOP_FAILURE;
} }
if (frame) { if (requestReturnCode == SUCCESS) {
infolog("received a valid frame\n"); infolog("received a valid frame\n");
printFrame(hexOut, frame); printFrame(hexOut, frame);
free(frame->userdata); free(frame->userdata);
@ -520,12 +540,11 @@ int main(int argc, char *argv[]) {
} else { } else {
ledRed(true); ledRed(true);
if (! loopActiveFlag) { if (! loopActiveFlag) {
errno = ERROR_APP_SPECIFIC_ERROR_FLAG | ERROR_LOOP_FAILURE; requestReturnCode = ERROR_LOOP_FAILURE;
} }
errlog("error %04x occured\n", errno); errlog("error %04x occured\n", requestReturnCode);
if (! hexOut) { if (! hexOut) {
uint8_t maskedError = (uint8_t)(errno & ~ERROR_APP_SPECIFIC_ERROR_FLAG); fprintf(stdout, "%c%c", requestReturnCode, 0);
fprintf(stdout, "%c%c", maskedError, 0);
fflush(stdout); fflush(stdout);
} }
if (! lineMode) { if (! lineMode) {
@ -541,8 +560,7 @@ int main(int argc, char *argv[]) {
infolog("closing device\n"); infolog("closing device\n");
closeSerial(fd); closeSerial(fd);
deinit(); myExit(exitCode);
return exitCode;
} }

View File

@ -16,14 +16,26 @@
#define DEFAULT_SERIAL_DEVICE "/dev/ttyAMA0" #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_TIMEOUT 1
#define ERROR_STATE_ENGINE 2 #define ERROR_LOOP_FAILURE 2
#define ERROR_LOOP_FAILURE 3 #define ERROR_TX_REG_UNACCESSIBLE 3
#define ERROR_TX_REG_UNACCESSIBLE 4 #define ERROR_OUT_OF_MEMORY__FRAME 4
#define ERROR_OUT_OF_MEMORY__USERDATA 5
#define ERROR_APP_SPECIFIC_ERROR_FLAG 0x4000 #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 { typedef struct {