diff --git a/Makefile b/Makefile index 01670d1..5824015 100644 --- a/Makefile +++ b/Makefile @@ -377,5 +377,8 @@ extract_fuzz_telegram_seeds: @rm -f fuzz_testcases/telegrams/seed_* @SEED=1; while read -r line; do echo "$${line}" | xxd -r -p - > "fuzz_testcases/telegrams/seed_$${SEED}"; SEED=$$((SEED + 1)); done < $(BUILD)/seeds; echo "Extracted $${SEED} seeds from simulations." +relay: utils/relay.c + gcc -g utils/relay.c -o relay -O0 -ggdb -fsanitize=address -fno-omit-frame-pointer -fprofile-arcs -ftest-coverage + # Include dependency information generated by gcc in a previous compile. include $(wildcard $(patsubst %.o,%.d,$(METER_OBJS))) diff --git a/utils/relay.c b/utils/relay.c new file mode 100644 index 0000000..e240a50 --- /dev/null +++ b/utils/relay.c @@ -0,0 +1,250 @@ +/* + Copyright (C) 2021 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// Utility to relay serial port SND_NR telegrams using mosquitto pub. + +#define DEBUG 0 + +#define HOMEDIR "/home/yourdir" + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char uchar; + +typedef uchar bool; +#define true 1 +#define false 0 + +int open_serial(const char *tty, int baud_rate) +{ + int rc = 0; + speed_t speed = 0; + struct termios tios; + //int DTR_flag = TIOCM_DTR; + + int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd == -1) { + usleep(1000*1000); + fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd == -1) goto err; + } + + switch (baud_rate) + { + case 300: speed = B300; break; + case 600: speed = B600; break; + case 1200: speed = B1200; break; + case 2400: speed = B2400; break; + case 4800: speed = B4800; break; + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + case 38400: speed = B38400; break; + case 57600: speed = B57600; break; + case 115200: speed = B115200;break; + default: + goto err; + } + + memset(&tios, 0, sizeof(tios)); + + rc = cfsetispeed(&tios, speed); + if (rc < 0) goto err; + rc = cfsetospeed(&tios, speed); + if (rc < 0) goto err; + + + // CREAD=Enable receive CLOCAL=Ignore any Carrier Detect signal. + tios.c_cflag |= (CREAD | CLOCAL); + tios.c_cflag &= ~CSIZE; + tios.c_cflag |= CS8; + tios.c_cflag &=~ CSTOPB; + // Disable parity bit. + tios.c_cflag &=~ PARENB; + + tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tios.c_iflag &= ~INPCK; + + tios.c_iflag &= ~(IXON | IXOFF | IXANY); + + tios.c_oflag &=~ OPOST; + tios.c_cc[VMIN] = 0; + tios.c_cc[VTIME] = 0; + + rc = tcsetattr(fd, TCSANOW, &tios); + if (rc < 0) goto err; + + + // This code can toggle DTR... maybe necessary + // for the pl2303 usb2serial driver/device. + //rc = ioctl(fd, TIOCMBIC, &DTR_flag); + //if (rc != 0) goto err; + + return fd; + +err: + if (fd > 0) + { + close(fd); + fd = -1; + } + return fd; +} + +void manufacturerFlag(uchar lo, uchar hi, uchar *mfct) +{ + int m_field = (hi*256)+lo; + mfct[0] = (m_field/1024)%32+64; + mfct[1] = (m_field/32)%32+64; + mfct[2] = (m_field)%32+64; +} + +bool find_telegram(uchar *buf, size_t *len) +{ + size_t l = *len; + if (*len < 10) return false; + size_t tl = buf[0]; + if (buf[1] != 0x44) return false; + if (tl+1 > l) return false; + size_t hl = 2*(tl+1)+1; + uchar hex[hl]; + for (size_t i=0; i= sizeof(buf)) + { + // Oups, a lot of random data fills up the buffer with no telegrams! + len = 0; + count_to_clear = 0; + if (DEBUG) fprintf(stderr, "overflow clear\n"); + } + if (DEBUG) fprintf(stderr, "Reading..."); + ssize_t n = read(fd, buf+len, sizeof(buf)-len); + if (n <= 0) + { + if (errno == EBADF) + { + fprintf(stderr, "Could not read from serial port.\n"); + break; + } + sleep(1); + count_to_clear++; + if (count_to_clear >= 2) + { + // After 2 seconds of no traffic, we clear the buffer. + // Any existing telegrams should have been found already. + len = 0; + count_to_clear = 0; + if (DEBUG) fprintf(stderr, "timeout clear\n"); + } + else + { + if (DEBUG) fprintf(stderr, "no data.\n"); + } + continue; + } + len+=n; + if (DEBUG) fprintf(stderr, "received data, buffer len %zu\n", len); + bool ok = find_telegram(buf, &len); + if (!ok) + { + if (DEBUG) fprintf(stderr, "No telegram found in data."); + } + } + close(fd); +}