From dd3523febe248f2f77b7d2fcdb1c980381931a9f Mon Sep 17 00:00:00 2001 From: sedlons Date: Tue, 22 Oct 2024 10:06:29 +0200 Subject: [PATCH 1/7] Data receive fix --- include/link.h | 25 ++++++++++++++++++------- include/mbrtu.h | 1 - 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/link.h b/include/link.h index cec6f4f..2fabc03 100755 --- a/include/link.h +++ b/include/link.h @@ -252,8 +252,8 @@ class Link goto serfail; } - // default config - sattr.c_cflag &= ~(ICANON | ECHO | ECHOE | ISIG); + // default config - sets the terminal to something like "raw" mode + cfmakeraw(&sattr); // set to 8-bits, no parity, 1 stop bit sattr.c_cflag &= ~(PARENB | CSTOPB | CRTSCTS); sattr.c_cflag &= ~CSIZE; @@ -470,25 +470,36 @@ class Link if (m_fd < 0) return -ENXIO; + int rlen = 0; + + // because we don't know datalen of received data, + // just read until timeout occur memcpy(&timeout, &m_timeout_recv, sizeof(timeout)); do { FD_ZERO (&read_fd); FD_SET (m_fd, &read_fd); - if ((rc = select (m_fd + 1, &read_fd, NULL, NULL, &timeout)) < 0) { + rc = select(m_fd + 1, &read_fd, NULL, NULL, &timeout); + if (rc < 0) { if (errno == EINTR) continue; rc = -errno; perror ("select"); return rc; } else if (rc == 0) { // timeout - rc = -ETIMEDOUT; + return (rlen > 0) ? rlen : -ETIMEDOUT; } else { // we have only one descriptor - rc = read(m_fd, buf, size); - if (rc < 0) + rc = read(m_fd, buf+rlen, size-rlen); + + if(rc > 0) { + rlen += rc; + } + + if (rc < 0) { return -errno; + } } - } while(0); + } while(1); return rc; } diff --git a/include/mbrtu.h b/include/mbrtu.h index 4dfe177..b773589 100755 --- a/include/mbrtu.h +++ b/include/mbrtu.h @@ -198,7 +198,6 @@ class mbRTU : public Link { if (ret < 0) return ret; if ((size_t)ret == len) { - usleep(m_recvdelay); if ((ret = recv(rbuf, size)) >= 0) { #ifdef MBDEBUG if (m_debug) From f561b417fc645cd5f7417a4b78084c34a8bc9106 Mon Sep 17 00:00:00 2001 From: sedlons Date: Tue, 22 Oct 2024 11:05:47 +0200 Subject: [PATCH 2/7] Added option -o for older KP184 firmware (before 2020). Changed receive timeout delay form 500ms to 50ms --- cmdUI/cmdUI.cpp | 9 ++++++--- cmdUI/dev_KP184.cpp | 3 ++- cmdUI/device.h | 2 +- include/link.h | 2 +- include/mbrtu.h | 20 +++++++++++++++----- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cmdUI/cmdUI.cpp b/cmdUI/cmdUI.cpp index 4fd9228..1531cec 100755 --- a/cmdUI/cmdUI.cpp +++ b/cmdUI/cmdUI.cpp @@ -231,7 +231,8 @@ static int process_command(int fd, char *line, int len) void usage(const char *prog) { - printf("usage: %s <-t tty|-s host[:port]> [-B conf] [\"cmd 1\"] ...\n", prog); + printf("usage: %s <-t tty|-s host[:port]> [-o] [-B conf] [\"cmd 1\"] ...\n", prog); + printf(" -o: older KP184 firmware before 2020\n"); printf(" -t: communicate via TTY port\n"); printf(" -s: communicate via socket\n"); printf(" -B: serial configuration string [%s]\n", getDefaultConfig(Link::SERIAL)); @@ -247,10 +248,12 @@ int main(int argc, char *argv[]) Link::linktype_t ltype = Link::SERIAL; const char *link = NULL, *lconf = NULL, *prog = basename(argv[0]); char c; + bool isOldFirmware = false; opterr = 0; - while ((c = getopt(argc, argv, "t:s:B:")) != -1) { + while ((c = getopt(argc, argv, "ot:s:B:")) != -1) { switch(c) { + case 'o': isOldFirmware = true; break; case 't': ltype = Link::SERIAL; link = optarg; break; case 's': ltype = Link::SOCKET; link = optarg; break; case 'B': lconf = optarg; break; @@ -275,7 +278,7 @@ int main(int argc, char *argv[]) sigaction(SIGINT, &_sigact, NULL); sigaction(SIGQUIT, &_sigact, NULL); - if (openDevice(ltype, link, lconf)) + if (openDevice(ltype, link, lconf, isOldFirmware)) return -ENOTCONN; #ifdef HAVE_READLINE diff --git a/cmdUI/dev_KP184.cpp b/cmdUI/dev_KP184.cpp index 7ccee90..326319e 100755 --- a/cmdUI/dev_KP184.cpp +++ b/cmdUI/dev_KP184.cpp @@ -356,8 +356,9 @@ cmd_t devcmds[] = { CMD_END }; -int openDevice(Link::linktype_t type, const char *link, const char *config) +int openDevice(Link::linktype_t type, const char *link, const char *config, bool isOldFW) { + kp184.setCRCLSBfirst(!isOldFW); // new 2020 FW and above have swapped CRC return kp184.open(type, link, config); } diff --git a/cmdUI/device.h b/cmdUI/device.h index 560cfd3..0d5ab42 100755 --- a/cmdUI/device.h +++ b/cmdUI/device.h @@ -12,7 +12,7 @@ typedef struct _cmd_t { extern cmd_t devcmds[]; // misc -int openDevice(Link::linktype_t type, const char link[], const char config[]); +int openDevice(Link::linktype_t type, const char link[], const char config[], bool isOldFW); int reOpenDevice(); const char *getDefaultConfig(Link::linktype_t type); const char *getPrompt(); diff --git a/include/link.h b/include/link.h index 2fabc03..ad15851 100755 --- a/include/link.h +++ b/include/link.h @@ -43,7 +43,7 @@ class Link m_fd(-1) , m_type(NONE) , m_timeout_send({ 2, 0 }) - , m_timeout_recv({ 0, 500000L }) { + , m_timeout_recv({ 0, 50000L }) { } ~Link() { diff --git a/include/mbrtu.h b/include/mbrtu.h index b773589..ac468b4 100755 --- a/include/mbrtu.h +++ b/include/mbrtu.h @@ -21,7 +21,7 @@ template > 8) & 0x00ff); + buf[len++] = (uint8_t)((crc >> 8) & 0xFF); buf[len++] = (uint8_t)(crc & 0xFF); return len; @@ -143,12 +149,16 @@ class mbRTU : public Link { // len is full length of the frame (inc. CRC) // returns payload length on match (excl. CRC), -1 if no match - static ssize_t checkCRC(const uint8_t buf[], size_t len) { + virtual ssize_t checkCRC(const uint8_t buf[], size_t len) { if (len <= 2) return -ENODATA; len -= 2; uint16_t crc = CRC16(buf, len); + + if(crcLSBfirst) + crc = ((crc << 8) & 0xff00) | ((crc >> 8) & 0x00ff); + if (buf[len] == (uint8_t)((crc >> 8) & 0xFF) && buf[len + 1] == (uint8_t)(crc & 0xFF)) return len; @@ -215,7 +225,7 @@ class mbRTU : public Link { private: devaddr_t m_devaddr; - useconds_t m_recvdelay; + bool crcLSBfirst; // CRC LSB first - New 2020 FW and above #ifdef MBDEBUG bool m_debug; #endif From 55c9d42e1acb43ae50dbc52d6b67e73e9fac6a76 Mon Sep 17 00:00:00 2001 From: sedlons Date: Tue, 22 Oct 2024 11:10:15 +0200 Subject: [PATCH 3/7] Note about KP184 firmware diff in readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 09e4177..c6af16f 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,5 @@ Remote utility programs for Kunkin KP184 electronic load for Linux/Cygwin. **kp184cmd** interactive command line utility **battery** battery discharge utility **kp184.py** battery capacity calculator and graph plotter based on discharge utility CSV data + +NOTE: KP184 communication CRC is different from 2020 firmware and above. You should check and try -o program option. From d02cf26e16122d7d30d4f9043cf214c118608823 Mon Sep 17 00:00:00 2001 From: sedlons Date: Tue, 22 Oct 2024 11:20:22 +0200 Subject: [PATCH 4/7] Old firmware switch option changed from small -o to large -O and added also to battery app --- README.md | 2 +- battery.cpp | 9 +++++++-- cmdUI/cmdUI.cpp | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c6af16f..a8968f1 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,4 @@ Remote utility programs for Kunkin KP184 electronic load for Linux/Cygwin. **battery** battery discharge utility **kp184.py** battery capacity calculator and graph plotter based on discharge utility CSV data -NOTE: KP184 communication CRC is different from 2020 firmware and above. You should check and try -o program option. +NOTE: KP184 communication CRC is different from 2020 firmware and above. You should check and try -O program option. diff --git a/battery.cpp b/battery.cpp index 88ea24f..88e24dd 100755 --- a/battery.cpp +++ b/battery.cpp @@ -167,7 +167,8 @@ void usage(const char prog[]) { printf("usage: %s <-t tty|-s host[:port]> <-l load> <-v Volt> [-B conf] [-a addr]" " [-V Volt] [-c Amp] [-C Amp] [-i interval] [-N samples] [-n samples]" - " [-f path] [-o] [-q]\n", prog); + " [-f path] [-o] [-O] [-q]\n", prog); + printf(" -O: older KP184 firmware before 2020\n"); printf(" -t: communicate via TTY port\n"); printf(" -s: communicate via socket\n"); printf(" -B: serial configuration string [%s]\n", defconf_serial); @@ -208,10 +209,13 @@ int main(int argc, char *argv[]) static struct sigaction sigact; siginfo_t sinfo; struct winsize ws; + bool isOldFirmware = false; + opterr = 0; - while ((op = getopt(argc, argv, "t:s:B:a:l:v:V:c:C:T:i:N:n:f:oq")) != -1) { + while ((op = getopt(argc, argv, "Ot:s:B:a:l:v:V:c:C:T:i:N:n:f:oq")) != -1) { switch(op) { + case 'O': isOldFirmware = true; break; case 't': ltype = Link::SERIAL; link = optarg; break; case 's': ltype = Link::SOCKET; link = optarg; break; case 'B': lconf = optarg; break; @@ -361,6 +365,7 @@ int main(int argc, char *argv[]) sigaction(SIGINT, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); + kp184.setCRCLSBfirst(!isOldFirmware); // new 2020 FW and above have swapped CRC rc = kp184.open(ltype, link, lconf); if (rc) return rc; diff --git a/cmdUI/cmdUI.cpp b/cmdUI/cmdUI.cpp index 1531cec..89b4db7 100755 --- a/cmdUI/cmdUI.cpp +++ b/cmdUI/cmdUI.cpp @@ -232,7 +232,7 @@ static int process_command(int fd, char *line, int len) void usage(const char *prog) { printf("usage: %s <-t tty|-s host[:port]> [-o] [-B conf] [\"cmd 1\"] ...\n", prog); - printf(" -o: older KP184 firmware before 2020\n"); + printf(" -O: older KP184 firmware before 2020\n"); printf(" -t: communicate via TTY port\n"); printf(" -s: communicate via socket\n"); printf(" -B: serial configuration string [%s]\n", getDefaultConfig(Link::SERIAL)); @@ -251,9 +251,9 @@ int main(int argc, char *argv[]) bool isOldFirmware = false; opterr = 0; - while ((c = getopt(argc, argv, "ot:s:B:")) != -1) { + while ((c = getopt(argc, argv, "Ot:s:B:")) != -1) { switch(c) { - case 'o': isOldFirmware = true; break; + case 'O': isOldFirmware = true; break; case 't': ltype = Link::SERIAL; link = optarg; break; case 's': ltype = Link::SOCKET; link = optarg; break; case 'B': lconf = optarg; break; From 4e40d4c5cc47eb1f5b2a569607f544960532206b Mon Sep 17 00:00:00 2001 From: sedlons Date: Tue, 22 Oct 2024 17:06:06 +0200 Subject: [PATCH 5/7] modbus answer is shorter, than send. Maybe something with newer fw? --- include/KP184.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/KP184.h b/include/KP184.h index abcd79c..4c99042 100755 --- a/include/KP184.h +++ b/include/KP184.h @@ -255,14 +255,15 @@ class KP184: public mbRTU<24, 1, 1, 250> { rc = (int)doIO(sbuf, slen, rbuf, sizeof(rbuf)); if (rc < 0) return rc; - if (rc != 7) + if (rc < 6) return -ENODATA; if (rbuf[0] != getAddress()) return -EFAULT; if (rbuf[1] != OP_WRITE1AO) return -ENOMSG; - if (memcmp(rbuf + 2, sbuf + 2, 4) != 0) // addr + code + reg[2] + val[2] + if (memcmp(rbuf + rc - 2, sbuf + slen -2, 2) != 0) { // check only part of rec value. newer fw return shorter answers (6B) ? return -ENODATA; + } return 0; } From 6a82fecc427f9339dfdfef0c348a03951b75fd37 Mon Sep 17 00:00:00 2001 From: sedlons Date: Tue, 22 Oct 2024 17:19:45 +0200 Subject: [PATCH 6/7] better data receive link timeout --- include/link.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/link.h b/include/link.h index ad15851..5601e5b 100755 --- a/include/link.h +++ b/include/link.h @@ -43,7 +43,7 @@ class Link m_fd(-1) , m_type(NONE) , m_timeout_send({ 2, 0 }) - , m_timeout_recv({ 0, 50000L }) { + , m_timeout_recv({ 0, 1500000L }) { } ~Link() { @@ -493,6 +493,9 @@ class Link if(rc > 0) { rlen += rc; + // after first rec data, next select timeout can be shorter + timeout.tv_sec = 0; + timeout.tv_usec = 50000L; } if (rc < 0) { From 361a7c3e78a516a3e0aabc3ee40dcd1970e0f5b6 Mon Sep 17 00:00:00 2001 From: sedlons Date: Wed, 23 Oct 2024 16:24:39 +0200 Subject: [PATCH 7/7] Fix behaviour of load termination timer, because timer_create() does not put new tendid value inside si_value --- battery.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/battery.cpp b/battery.cpp index 88e24dd..d6295c4 100755 --- a/battery.cpp +++ b/battery.cpp @@ -176,7 +176,7 @@ void usage(const char prog[]) printf(" -l: load mode and value: val[m]\n"); printf(" -v: voltage threshold, V\n"); printf(" -V: voltage threshold to set half load, V\n"); - printf(" -c: cuurent low threshold, A\n"); + printf(" -c: current low threshold, A\n"); printf(" -C: current high threshold, load is immediately off, A\n"); printf(" -T: maximum load time, h:m:s\n"); printf(" -i: sample interval, s [%g s]\n", @@ -188,6 +188,8 @@ void usage(const char prog[]) printf(" -q: produce no additional information\n"); } +#define SIGTIMEEND (SIGRTMIN+1) + int main(int argc, char *argv[]) { int rc = 0, op; @@ -206,8 +208,8 @@ int main(int argc, char *argv[]) struct itimerspec tsint, tsend = {}; sigset_t timset; timer_t tintid = 0, tendid = 0; + struct sigevent sevEnd; static struct sigaction sigact; - siginfo_t sinfo; struct winsize ws; bool isOldFirmware = false; @@ -376,6 +378,7 @@ int main(int argc, char *argv[]) sigemptyset(&timset); sigaddset(&timset, SIGALRM); + sigaddset(&timset, SIGTIMEEND); sigprocmask(SIG_BLOCK, &timset, NULL); rc = timer_create(CLOCK_MONOTONIC, NULL, &tintid); if (rc == EAGAIN) @@ -386,9 +389,12 @@ int main(int argc, char *argv[]) } if (ts_cmp(tsend.it_value, { 0, 0 }) > 0) { - rc = timer_create(CLOCK_MONOTONIC, NULL, &tendid); + memset(&sevEnd, 0x00, sizeof(sevEnd)); + sevEnd.sigev_notify = SIGEV_SIGNAL; + sevEnd.sigev_signo = SIGTIMEEND; + rc = timer_create(CLOCK_MONOTONIC, &sevEnd, &tendid); if (rc == EAGAIN) - rc = timer_create(CLOCK_MONOTONIC, NULL, &tendid); + rc = timer_create(CLOCK_MONOTONIC, &sevEnd, &tendid); if (rc) { perror("ERR Can't create termination timer"); goto close; @@ -526,11 +532,11 @@ int main(int argc, char *argv[]) // wait for timers while (term == TERM_NONE) { - int sret = sigwaitinfo(&timset, &sinfo); - if ((sret != SIGALRM) || (sinfo.si_value.sival_ptr == 0)) - continue; - if ((timer_t)sinfo.si_value.sival_ptr != tintid) + int sret = sigwaitinfo(&timset, NULL); + if (sret == SIGTIMEEND) term = TERM_TIME; + if (sret != SIGALRM) + continue; break; }