From 567d5010d0f14077a79f393e112db9a473711291 Mon Sep 17 00:00:00 2001 From: Tomasz Fortuna Date: Mon, 31 Jul 2023 22:20:59 +0200 Subject: [PATCH 1/7] drivers/nutdrv_qx.c: improve Armac subdriver Based on a debug output from a newer device (*/PF1) we've improved understanding on how: - those devices encode the length of a chunk of data. - how the end of transmission can be marked / detected. Changed: - Empty buffer before sending command to clear any residual data. - Detect end of message by end of line character \r (0x0d). - Refactor "6" into a READ_SIZE constant. - Limit bytes_available nibble to available READ_SIZE. Signed-off-by: Tomasz bla Fortuna --- NEWS | 2 ++ data/driver.list.in | 2 +- drivers/nutdrv_qx.c | 68 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 11385cf61d..8cf46b9413 100644 --- a/NEWS +++ b/NEWS @@ -99,6 +99,8 @@ as part of https://github.com/networkupstools/nut/issues/1410 solution. - nutdrv_qx updates: * the `voltronic_qs_protocol` should now accept both "V" (as before) and newly "H" dialects, which otherwise seem interchangeable [#1623] + * the `armac` subdriver was enhanced to support devices with a different + response pattern than previously expected per initial contribution [#1978] - usbhid-ups updates: * cps-hid subdriver now applies same report descriptor fixing logic to diff --git a/data/driver.list.in b/data/driver.list.in index e175a6bc4d..f51801fc0b 100644 --- a/data/driver.list.in +++ b/data/driver.list.in @@ -115,7 +115,7 @@ "ARTronic" "ups" "2" "ARTon Platinium Combo 3.1 10/15/20 kVA" "USB" "blazer_usb" "ARTronic" "ups" "2" "ARTon Platinium RT 1/2/3/6/10 kVA" "USB" "blazer_usb" -"Armac" "ups" "2" "R/2000I/PSW" "(USB ID 0925:1234)" "nutdrv_qx" +"Armac" "ups" "2" "R/2000I/PSW and PF1 series" "(USB ID 0925:1234)" "nutdrv_qx" "ASEM SPA" "ups" "5" "PB1300 UPS" "i2c" "asem" diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index 350c555a06..dcdda5010b 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1761,9 +1761,10 @@ static void *ablerex_subdriver_fun(USBDevice_t *device) */ static int armac_command(const char *cmd, char *buf, size_t buflen) { - char tmpbuf[6]; - int ret = 0; - size_t i, bufpos; + const int READ_SIZE = 6; + char tmpbuf[READ_SIZE]; + int ret = 0; + size_t i, bufpos; const size_t cmdlen = strlen(cmd); /* UPS ignores (doesn't echo back) unsupported commands which makes @@ -1788,6 +1789,17 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) } upsdebugx(4, "armac command %.*s", (int)strcspn(cmd, "\r"), cmd); + /* Cleanup buffer before sending a new command */ + for (i = 0; i < 10; i++) { + ret = usb_interrupt_read(udev, 0x81, + (usb_ctrl_charbuf)tmpbuf, READ_SIZE, 100); + if (ret != READ_SIZE) { + // Timeout - buffer is clean. + break; + } + upsdebugx(4, "armac cleanup ret i=%ld ret=%d ctrl=%02hhx", i, ret, tmpbuf[0]); + } + /* Send command to the UPS in 3-byte chunks. Most fit 1 chunk, except for eg. * parameterized tests. */ for (i = 0; i < cmdlen;) { @@ -1810,21 +1822,25 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) return ret; } + /* Wait for response to buffer */ + usleep(2000); memset(buf, 0, buflen); bufpos = 0; - while (bufpos + 6 < buflen) { + while (bufpos + READ_SIZE < buflen) { size_t bytes_available; /* Read data in 6-byte chunks */ - ret = usb_interrupt_read(udev, - 0x81, - (usb_ctrl_charbuf)tmpbuf, 6, 1000); + ret = usb_interrupt_read(udev, 0x81, + (usb_ctrl_charbuf)tmpbuf, READ_SIZE, 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ - if (ret != 6) { + if (ret != READ_SIZE) { + /* NOTE: If end condition is invalid for particular UPS we might make one + * request more and get this error. If bufpos > (say) 10 this could be ignored + * and the reply correctly read. */ upsdebugx(1, "interrupt read error: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", @@ -1838,20 +1854,50 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) tmpbuf[0], tmpbuf[1], tmpbuf[2], tmpbuf[3], tmpbuf[4], tmpbuf[5], tmpbuf[1], tmpbuf[2], tmpbuf[3], tmpbuf[4], tmpbuf[5]); + /* + * On most tested devices (including R/2000I/PSW) this was equal to the number of + * bytes returned in the buffer, but on some newer UPS (R/3000I/PF1) it was 1 more + * (1 control + 5 bytes transferred and bytes_available equal to 6 instead of 5). + * + * Current assumption is that this is number of bytes available on the UPS side + * with up to 5 (ret - 1) transferred. + */ bytes_available = (unsigned char)tmpbuf[0] & 0x0f; if (bytes_available == 0) { /* End of transfer */ break; } - memcpy(buf + bufpos, tmpbuf + 1, bytes_available); - bufpos += bytes_available; + if (bytes_available > READ_SIZE - 1) { + /* Single interrupt transfer has 1 control + 5 data bytes */ + bytes_available = READ_SIZE - 1; + } + + /* Copy bytes into the final buffer while detecting end of line - \r */ + for (i = 0; i < bytes_available; i++) { + buf[bufpos++] = tmpbuf[i + 1]; + if (tmpbuf[i + 1] == 0x0d) { + if (i + 1 != bytes_available) { + upsdebugx(3, "trailing bytes in serial transmission found: %" PRIuSIZE " copied out of %" PRIuSIZE, + i + 1, bytes_available + ); + } + /* Break through two loops */ + goto end_of_message; + } + if (tmpbuf[i + 1] == 0x00) { + /* Happens when a manually turned off UPS is connected to the USB */ + upsdebugx(3, "null byte read - is UPS off?"); + return 0; + } + } if (bytes_available <= 2) { /* Slow down, let the UPS buffer more bytes */ - usleep(15000); + usleep(10000); } } +end_of_message: if (bufpos + 6 >= buflen) { upsdebugx(2, "Protocol error, too much data read."); From 87e94fafea9fa5499876e7cae80acd6d846b1a23 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 3 Aug 2023 18:43:20 +0200 Subject: [PATCH 2/7] Update drivers/nutdrv_qx.c Fix debug printout Signed-off-by: Jim Klimov --- drivers/nutdrv_qx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index dcdda5010b..eb2d3badde 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1797,7 +1797,7 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) // Timeout - buffer is clean. break; } - upsdebugx(4, "armac cleanup ret i=%ld ret=%d ctrl=%02hhx", i, ret, tmpbuf[0]); + upsdebugx(4, "armac cleanup ret i=%" PRIuSIZE " ret=%d ctrl=%02hhx", i, ret, tmpbuf[0]); } /* Send command to the UPS in 3-byte chunks. Most fit 1 chunk, except for eg. From 6547c613f7dcbfd7364d04f189b61aaccf5eb7a2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 4 Aug 2023 09:38:21 +0200 Subject: [PATCH 3/7] drivers/nutdrv_qx.c: cast signed/unsigned int comparison Signed-off-by: Jim Klimov --- drivers/nutdrv_qx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index eb2d3badde..5c13460461 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1868,7 +1868,7 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) break; } - if (bytes_available > READ_SIZE - 1) { + if (bytes_available > (size_t)(READ_SIZE - 1)) { /* Single interrupt transfer has 1 control + 5 data bytes */ bytes_available = READ_SIZE - 1; } From db0272a9444228944bfa2daf1b7fd6cda4a39718 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 5 Aug 2023 14:05:07 +0200 Subject: [PATCH 4/7] drivers/nutdrv_qx.c: convert to ARMAC_READ_SIZE as a macro Signed-off-by: Jim Klimov --- drivers/nutdrv_qx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index 5c13460461..b1f236c663 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1759,10 +1759,10 @@ static void *ablerex_subdriver_fun(USBDevice_t *device) * Richcomm Technologies, Inc. Dec 27 2005 ver 1.1." Maybe other Richcomm UPSes * would work with this - better than with the richcomm_usb driver. */ +#define ARMAC_READ_SIZE 6 static int armac_command(const char *cmd, char *buf, size_t buflen) { - const int READ_SIZE = 6; - char tmpbuf[READ_SIZE]; + char tmpbuf[ARMAC_READ_SIZE]; int ret = 0; size_t i, bufpos; const size_t cmdlen = strlen(cmd); @@ -1792,8 +1792,8 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) /* Cleanup buffer before sending a new command */ for (i = 0; i < 10; i++) { ret = usb_interrupt_read(udev, 0x81, - (usb_ctrl_charbuf)tmpbuf, READ_SIZE, 100); - if (ret != READ_SIZE) { + (usb_ctrl_charbuf)tmpbuf, ARMAC_READ_SIZE, 100); + if (ret != ARMAC_READ_SIZE) { // Timeout - buffer is clean. break; } @@ -1827,17 +1827,17 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) memset(buf, 0, buflen); bufpos = 0; - while (bufpos + READ_SIZE < buflen) { + while (bufpos + ARMAC_READ_SIZE < buflen) { size_t bytes_available; /* Read data in 6-byte chunks */ ret = usb_interrupt_read(udev, 0x81, - (usb_ctrl_charbuf)tmpbuf, READ_SIZE, 1000); + (usb_ctrl_charbuf)tmpbuf, ARMAC_READ_SIZE, 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ - if (ret != READ_SIZE) { + if (ret != ARMAC_READ_SIZE) { /* NOTE: If end condition is invalid for particular UPS we might make one * request more and get this error. If bufpos > (say) 10 this could be ignored * and the reply correctly read. */ @@ -1868,9 +1868,9 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) break; } - if (bytes_available > (size_t)(READ_SIZE - 1)) { + if (bytes_available > ARMAC_READ_SIZE - 1) { /* Single interrupt transfer has 1 control + 5 data bytes */ - bytes_available = READ_SIZE - 1; + bytes_available = ARMAC_READ_SIZE - 1; } /* Copy bytes into the final buffer while detecting end of line - \r */ From 8049ca38ee30f9262a113443565994c46cff1bf7 Mon Sep 17 00:00:00 2001 From: Tomasz bla Fortuna Date: Tue, 8 Aug 2023 16:13:29 +0200 Subject: [PATCH 5/7] drivers/nutdrv_qx.c: Support a quirk in Vultech V2000 UPS. This UPS seems to use null bytes within status bits. This might mean "unsupported". We will treat them as zeroes. Signed-off-by: Tomasz bla Fortuna --- drivers/nutdrv_qx.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/nutdrv_qx.c b/drivers/nutdrv_qx.c index b1f236c663..9abaa1de3b 100644 --- a/drivers/nutdrv_qx.c +++ b/drivers/nutdrv_qx.c @@ -1875,7 +1875,28 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) /* Copy bytes into the final buffer while detecting end of line - \r */ for (i = 0; i < bytes_available; i++) { + if (tmpbuf[i + 1] == 0x00 && bufpos == 0) { + /* Happens when a manually turned off UPS is connected to the USB */ + upsdebugx(3, "null byte read - is UPS off?"); + return 0; + } + + /* Vultech V2000 seems to use 0x00 within status bits. This might mean "unsupported". + * or something else completely. */ + if (tmpbuf[i + 1] == 0x00) { + if (bufpos >= 38) { + upsdebugx(3, "found null byte in status bits at %" PRIuSIZE " byte, assuming 0.", bufpos); + buf[bufpos++] = '0'; + continue; + } else { + upsdebugx(3, "found null byte in data stream - interrupting read."); + /* Break through two loops */ + goto end_of_message; + } + } + buf[bufpos++] = tmpbuf[i + 1]; + if (tmpbuf[i + 1] == 0x0d) { if (i + 1 != bytes_available) { upsdebugx(3, "trailing bytes in serial transmission found: %" PRIuSIZE " copied out of %" PRIuSIZE, @@ -1885,11 +1906,6 @@ static int armac_command(const char *cmd, char *buf, size_t buflen) /* Break through two loops */ goto end_of_message; } - if (tmpbuf[i + 1] == 0x00) { - /* Happens when a manually turned off UPS is connected to the USB */ - upsdebugx(3, "null byte read - is UPS off?"); - return 0; - } } if (bytes_available <= 2) { From 1555fb7949ae6059a69928dab0c05bdab8d71a44 Mon Sep 17 00:00:00 2001 From: Tomasz Fortuna Date: Sun, 13 Aug 2023 09:27:12 +0200 Subject: [PATCH 6/7] drivers/nutdrv_qx.c: Add documentation file. Document various possible transmissions. Might be required to construct testcases one day - adding new UPS shouldn't cause regressions in older ones. Signed-off-by: Tomasz Fortuna --- NEWS | 3 +- docs/nut.dict | 1 + docs/nutdrv_qx-subdrivers.txt | 170 ++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 8cf46b9413..72dc477fb7 100644 --- a/NEWS +++ b/NEWS @@ -100,7 +100,8 @@ as part of https://github.com/networkupstools/nut/issues/1410 solution. * the `voltronic_qs_protocol` should now accept both "V" (as before) and newly "H" dialects, which otherwise seem interchangeable [#1623] * the `armac` subdriver was enhanced to support devices with a different - response pattern than previously expected per initial contribution [#1978] + response pattern than previously expected per initial contribution. + It was tested to work with Vultech V2000 and Armac PF1 series. [#1978] - usbhid-ups updates: * cps-hid subdriver now applies same report descriptor fixing logic to diff --git a/docs/nut.dict b/docs/nut.dict index 21f5195b53..d712e5ba24 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -3195,3 +3195,4 @@ zwfa zzz Åstrand Ørpetveit +Vultech diff --git a/docs/nutdrv_qx-subdrivers.txt b/docs/nutdrv_qx-subdrivers.txt index 8d786450b9..31dba9964d 100644 --- a/docs/nutdrv_qx-subdrivers.txt +++ b/docs/nutdrv_qx-subdrivers.txt @@ -960,6 +960,176 @@ Return the currently processed status so that it can be checked with one of the If you need to edit the current status call this function with one of the NUT status (all but +OB+ are supported, simply set it as not +OL+); prefix them with an exclamation mark if you want to clear them from the status (e.g. +!OL+). +Armac Subdriver +~~~~~~~~~~~~~~~ + +Armac subdriver is based on reverse engineering of Power Manager II software by +Richcomm Technologies writen in 2005 that is still (as of 2023) being +distributed as a valid software for freshly sold UPS of various manufacturers. +It uses commands as defined for Megatec protocol - but has a different +communication mechanism. + +It uses two types of USB interrupt transfers: +- 4 bytes to send a command (usually single transfer). +- 6 byte chunk to read a reply (multiple transfers). + +Transfers are similar to those of the richcomm nut driver, but the transferred +data is not short binary commands. Instead, serial text data is overlayed in +these transfers in a way that creates a badly made USB serial interface. UPS +reply looks similar to this: + + 0 1 2 3 4 5 +HL 00 00 00 00 00 + +HL is a control byte. Its high nibble meaning is unknown. It changes between +two possible values during transmission. Low nibble encodes number of bytes +that have a meaning in the transaction. For example there are 5 bytes that +might contain ASCII serial data, but only some might be valid, and other might +be random, stale buffer data, etc. + +What follows is set of observed transmissions by various UPSes gathered from +Github issues. + +Transfer dumps +^^^^^^^^^^^^^^ + +#### Vultech V2000 + +---- +419.987514 [D4] armac command Q1 +419.988307 [D4] armac cleanup ret i=0 ret=6 ctrl=c0 +420.119402 [D4] read: ret 6 buf 81: 28 30 31 30 30 >(0100< +420.130383 [D4] read: ret 6 buf c1: 32 30 31 30 30 >20100< +420.141408 [D4] read: ret 6 buf 82: 33 33 31 30 30 >33100< +420.152201 [D4] read: ret 6 buf c3: 2e 30 20 30 30 >.0 00< +420.153237 [D4] read: ret 6 buf 82: 30 30 20 30 30 >00 00< +420.164299 [D4] read: ret 6 buf c1: 30 30 20 30 30 >00 00< +420.175293 [D4] read: ret 6 buf 82: 2e 30 20 30 30 >.0 00< +420.186358 [D4] read: ret 6 buf c3: 20 32 33 30 30 > 2300< +420.190322 [D4] read: ret 6 buf 83: 33 2e 30 30 30 >3.000< +420.194323 [D4] read: ret 6 buf c1: 20 2e 30 30 30 > .000< +420.205358 [D4] read: ret 6 buf 81: 30 2e 30 30 30 >0.000< +420.216318 [D4] read: ret 6 buf c2: 31 34 30 30 30 >14000< +420.227445 [D4] read: ret 6 buf 83: 20 34 39 30 30 > 4900< +420.228334 [D4] read: ret 6 buf c2: 2e 30 39 30 30 >.0900< +420.239461 [D4] read: ret 6 buf 81: 20 30 39 30 30 > 0900< +420.250411 [D4] read: ret 6 buf c2: 32 37 39 30 30 >27900< +420.261405 [D4] read: ret 6 buf 83: 2e 30 20 30 30 >.0 00< +420.265468 [D4] read: ret 6 buf c3: 32 30 2e 30 30 >20.00< +420.269465 [D4] read: ret 6 buf 81: 38 30 2e 30 30 >80.00< +420.280322 [D4] read: ret 6 buf c1: 20 30 2e 30 30 > 0.00< +420.291469 [D4] read: ret 6 buf 82: 30 30 2e 30 30 >00.00< +420.302465 [D4] read: ret 6 buf c3: 30 30 31 30 30 >00100< +420.303511 [D4] read: ret 6 buf 82: 00 30 31 30 30 > <- This has 0x00 and '0', will be read as "00" +420.303515 [D3] found null byte in status bits at 43 byte, assuming 0. +420.314425 [D4] read: ret 6 buf c1: 31 30 31 30 30 >10100< <- this has '1' +420.325432 [D4] read: ret 6 buf 81: 0d 30 31 30 30 >.0100< <- and this finishes with `\r`. +420.325442 [D3] armac command Q1 response read: '(233.0 000.0 233.0 014 49.0 27.0 20.8 00001001' +---- + +---- +1.185164 [D4] armac command ID +1.316257 [D4] read: ret 6 buf c1: 23 31 00 30 30 >#1 +1.327309 [D4] read: ret 6 buf 81: 20 31 00 30 30 > 1 +1.338264 [D4] read: ret 6 buf c2: 20 20 00 30 30 > +1.349151 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< +1.360277 [D4] read: ret 6 buf c2: 20 20 20 30 30 > 00< +1.371322 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< +1.382265 [D4] read: ret 6 buf c3: 20 20 20 30 30 > 00< +1.393156 [D4] read: ret 6 buf 82: 20 20 20 30 30 > 00< +1.404324 [D4] read: ret 6 buf c3: 20 20 20 30 30 > 00< +1.415342 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< +1.426292 [D4] read: ret 6 buf c2: 20 20 20 30 30 > 00< +1.437203 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< +1.448328 [D4] read: ret 6 buf c3: 56 34 2e 30 30 >V4.00< +1.459293 [D4] read: ret 6 buf 82: 31 30 2e 30 30 >10.00< +1.470274 [D4] read: ret 6 buf c3: 20 20 20 30 30 > 00< +1.481208 [D4] read: ret 6 buf 82: 20 20 20 30 30 > 00< +1.492261 [D4] read: ret 6 buf c1: 0d 20 20 30 30 > +1.492270 [D3] armac command ID response read: '# V4.10 ' +---- + +---- +4.749667 [D4] armac command F +4.876638 [D4] read: ret 6 buf 81: 23 31 00 30 30 >#1 +4.887614 [D4] read: ret 6 buf c1: 32 31 00 30 30 >21 +4.898644 [D4] read: ret 6 buf 82: 32 30 00 30 30 >20 +4.909595 [D4] read: ret 6 buf c3: 2e 30 20 30 30 >.0 00< +4.920648 [D4] read: ret 6 buf 82: 30 30 20 30 30 >00 00< +4.931629 [D4] read: ret 6 buf c3: 35 20 32 30 30 >5 200< +4.942601 [D4] read: ret 6 buf 83: 34 2e 30 30 30 >4.000< +4.953666 [D4] read: ret 6 buf c2: 30 20 30 30 30 >0 000< +4.964535 [D4] read: ret 6 buf 83: 35 30 2e 30 30 >50.00< +4.975540 [D4] read: ret 6 buf c2: 30 0d 2e 30 30 >0 +4.975546 [D3] armac command F response read: '#220.0 005 24.00 50.0' +---- + +#### Armac R/2000I/PSW + +---- +112.966856 [D4] armac command Q1 +112.968197 [D4] armac cleanup ret i=0 ret=6 ctrl=c0 <- Cleanups required. +113.091193 [D4] read: ret 6 buf 81: 28 30 0d 2e 30 >(0 <- Usually 1-3 bytes available in transfer. +113.103211 [D4] read: ret 6 buf c1: 30 30 0d 2e 30 >00 +113.115180 [D4] read: ret 6 buf 82: 30 30 0d 2e 30 >00 +113.117144 [D4] read: ret 6 buf c3: 2e 30 20 2e 30 >.0 .0< +113.120150 [D4] read: ret 6 buf 81: 31 30 20 2e 30 >10 .0< +113.132178 [D4] read: ret 6 buf c1: 34 30 20 2e 30 >40 .0< +113.144159 [D4] read: ret 6 buf 82: 30 2e 20 2e 30 >0. .0< +113.146149 [D4] read: ret 6 buf c3: 30 20 32 2e 30 >0 2.0< +113.149173 [D4] read: ret 6 buf 81: 32 20 32 2e 30 >2 2.0< +113.161167 [D4] read: ret 6 buf c1: 37 20 32 2e 30 >7 2.0< +113.173159 [D4] read: ret 6 buf 82: 2e 30 32 2e 30 >.02.0< +113.175157 [D4] read: ret 6 buf c3: 20 30 30 2e 30 > 00.0< +113.178158 [D4] read: ret 6 buf 81: 32 30 30 2e 30 >200.0< +113.190157 [D4] read: ret 6 buf c1: 20 30 30 2e 30 > 00.0< +113.202161 [D4] read: ret 6 buf 82: 30 30 30 2e 30 >000.0< +113.204154 [D4] read: ret 6 buf c3: 2e 30 20 2e 30 >.0 .0< +113.207150 [D4] read: ret 6 buf 81: 34 30 20 2e 30 >40 .0< +113.219174 [D4] read: ret 6 buf c1: 36 30 20 2e 30 >60 .0< +113.231165 [D4] read: ret 6 buf 82: 2e 38 20 2e 30 >.8 .0< +113.233157 [D4] read: ret 6 buf c3: 20 35 36 2e 30 > 56.0< +113.237149 [D4] read: ret 6 buf 81: 2e 35 36 2e 30 >.56.0< +113.249168 [D4] read: ret 6 buf c1: 30 35 36 2e 30 >056.0< +113.261155 [D4] read: ret 6 buf 83: 20 31 30 2e 30 > 10.0< +113.263151 [D4] read: ret 6 buf c2: 30 30 30 2e 30 >000.0< +113.266152 [D4] read: ret 6 buf 81: 31 30 30 2e 30 >100.0< +113.278161 [D4] read: ret 6 buf c1: 30 30 30 2e 30 >000.0< <- No Null bytes. +113.290155 [D4] read: ret 6 buf 82: 30 30 30 2e 30 >000.0< +113.292159 [D4] read: ret 6 buf c1: 0d 30 30 2e 30 > +113.292169 [D3] armac command Q1 response read: '(000.0 140.0 227.0 002 00.0 46.8 56.0 10001000' +---- + +Next query would return 0x80 control byte - 0 available bytes. This used to +terminate transmission, but some UPS don't work like that. + + +#### Armac R/3000I/PF1 + +---- +0.083301 [D4] armac command Q1 +0.164847 [D4] read: ret 6 buf a6: 28 32 34 31 2e >(241.< +0.184839 [D4] read: ret 6 buf 86: 35 20 30 30 30 >5 000< +0.205851 [D4] read: ret 6 buf a6: 2e 30 20 32 33 >.0 23< +0.226849 [D4] read: ret 6 buf 86: 30 2e 33 20 30 >0.3 0< +0.247859 [D4] read: ret 6 buf a6: 30 30 20 34 39 >00 49< +0.268862 [D4] read: ret 6 buf 86: 2e 39 20 32 2e >.9 2.< +0.289857 [D4] read: ret 6 buf a6: 32 35 20 34 38 >25 48< +0.309866 [D4] read: ret 6 buf 86: 2e 30 20 30 30 >.0 00< +0.330863 [D4] read: ret 6 buf a6: 30 30 30 30 30 >00000< +0.827913 [D4] read: ret 6 buf 83: 31 0d 30 30 30 >1 000< +0.827927 [D3] armac command Q1 response read: '(241.5 000.0 230.3 000 49.9 2.25 48.0 00000001' +0.827954 [D4] armac command ID +1.394985 [D4] read: ret 6 buf a5: 4e 41 4b 0d 30 >NAK < +1.395001 [D3] armac command ID response read: 'NAK' +---- + +This UPS sends higher nibble set to 6 often, which exceeds available bytes. +Maybe means that more are available. Its serial-USB bridge is probably faster. +We read 5 bytes in case 6 nibble is sent. End of transmission is marked by `\r`, +no 0 nibble is sent. + + Notes ~~~~~ From 566da82636501e8f1b4ad64b8980ff417455b32f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 17 Aug 2023 01:06:40 +0200 Subject: [PATCH 7/7] docs/nutdrv_qx-subdrivers.txt, docs/nut.dict: fix some typos and update the dictionary [#2005] Signed-off-by: Jim Klimov --- docs/nut.dict | 9 +++++---- docs/nutdrv_qx-subdrivers.txt | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/nut.dict b/docs/nut.dict index d712e5ba24..028feaaea8 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 3196 utf-8 +personal_ws-1.1 en 3198 utf-8 AAS ABI ACFAIL @@ -449,6 +449,7 @@ HFILE HIDIOCINITREPORT HIDRDD HITRANS +HL HMAC HNX HOMEBREW @@ -1365,6 +1366,7 @@ Viewsonic Viktor VirCIO Vout +Vultech Václav WALKMODE WARNFATAL @@ -1613,8 +1615,8 @@ bsd bsv bt bti -btnG btn +btnG btt buckboosthyst buckvolts @@ -2649,10 +2651,10 @@ qx's qxflags rD rackmount +raquo raritan ratedva ratedwatts -raquo rb rcctl readline @@ -3195,4 +3197,3 @@ zwfa zzz Åstrand Ørpetveit -Vultech diff --git a/docs/nutdrv_qx-subdrivers.txt b/docs/nutdrv_qx-subdrivers.txt index 31dba9964d..bc0dde9a61 100644 --- a/docs/nutdrv_qx-subdrivers.txt +++ b/docs/nutdrv_qx-subdrivers.txt @@ -964,7 +964,7 @@ Armac Subdriver ~~~~~~~~~~~~~~~ Armac subdriver is based on reverse engineering of Power Manager II software by -Richcomm Technologies writen in 2005 that is still (as of 2023) being +Richcomm Technologies written in 2005 that is still (as of 2023) being distributed as a valid software for freshly sold UPS of various manufacturers. It uses commands as defined for Megatec protocol - but has a different communication mechanism. @@ -974,7 +974,7 @@ It uses two types of USB interrupt transfers: - 6 byte chunk to read a reply (multiple transfers). Transfers are similar to those of the richcomm nut driver, but the transferred -data is not short binary commands. Instead, serial text data is overlayed in +data is not short binary commands. Instead, serial text data is overlaid in these transfers in a way that creates a badly made USB serial interface. UPS reply looks similar to this: