From 4cd226a55883dfc55a39f82f215dbb67e8c64cc3 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sun, 28 Jul 2024 17:22:12 +0200 Subject: [PATCH 1/8] drivers/mge-hid.c, NEWS.adoc: try to recognize Eaton 9E model and info [#1925] Also handle "unknown 2000" assuming it is a mis-read "Eaton 9E 2000(i?)" which refused to tell libusb its vendor/product/serial strings. This may be the answer to such issues as #1925, #2380 (re-opened), #2492 Signed-off-by: Jim Klimov --- NEWS.adoc | 2 +- data/driver.list.in | 1 + drivers/mge-hid.c | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/NEWS.adoc b/NEWS.adoc index adc0e84c5e..8fe70d6b41 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -108,7 +108,7 @@ https://github.com/networkupstools/nut/milestone/11 * General suggestion from `possibly_supported()` message method for devices with VendorID=`0x06da` (Phoenixtec), seen in some models supported by MGE HID or Liebert HID, updated to suggest trying `nutdrv_qx`. [#334] - * MGE HID list of `mge_model_names[]` was extended for Eaton 5PX and 5SC + * MGE HID list of `mge_model_names[]` was extended for Eaton 9E, 5PX and 5SC series (largely guessing, feedback and PRs for adaptation to actual string values reported by devices via USB are welcome), so these devices would now report `battery.voltage` and `battery.voltage.nominal`. [#2380] diff --git a/data/driver.list.in b/data/driver.list.in index 8fb11cb768..b8f33caf43 100644 --- a/data/driver.list.in +++ b/data/driver.list.in @@ -362,6 +362,7 @@ "Eaton" "ups" "5" "5S" "USB port" "usbhid-ups" "Eaton" "ups" "5" "5SC" "USB port" "usbhid-ups" "Eaton" "ups" "5" "5P" "USB port" "usbhid-ups" +"Eaton" "ups" "5" "9E" "USB port" "usbhid-ups" "Eaton" "ups" "5" "9SX" "USB port" "usbhid-ups" "Eaton" "ups" "5" "9PX" "USB port" "usbhid-ups" "Eaton" "ups" "5" "9PX Split Phase 6/8/10 kVA" "USB port" "usbhid-ups" diff --git a/drivers/mge-hid.c b/drivers/mge-hid.c index 920c19d3db..c7c5bd6e9f 100644 --- a/drivers/mge-hid.c +++ b/drivers/mge-hid.c @@ -50,7 +50,7 @@ # endif #endif -#define MGE_HID_VERSION "MGE HID 1.47" +#define MGE_HID_VERSION "MGE HID 1.48" /* (prev. MGE Office Protection Systems, prev. MGE UPS SYSTEMS) */ /* Eaton */ @@ -131,7 +131,8 @@ typedef enum { MGE_PULSAR_M_2200, MGE_PULSAR_M_3000, MGE_PULSAR_M_3000_XL, - EATON_5P = 0x500 /* Eaton 5P / 5PX / 5SC series */ + EATON_5P = 0x500, /* Eaton 5P / 5PX / 5SC series */ + EATON_9E = 0x900 /* Eaton 9E entry-level series */ } models_type_t; /* Default to line-interactive or online (ie, not offline). @@ -489,6 +490,7 @@ static const char *mge_battery_voltage_nominal_fun(double value) case MGE_PULSAR_M: case EATON_5P: + case EATON_9E: /* Presumably per https://github.com/networkupstools/nut/issues/1925#issuecomment-1562342854 */ break; default: @@ -514,6 +516,7 @@ static const char *mge_battery_voltage_fun(double value) case MGE_EVOLUTION: case MGE_PULSAR_M: case EATON_5P: + case EATON_9E: /* Presumably per https://github.com/networkupstools/nut/issues/1925#issuecomment-1562342854 */ break; default: @@ -1144,6 +1147,17 @@ static models_name_t mge_model_names [] = { "Eaton 5SC", "2200", EATON_5P, NULL }, { "Eaton 5SC", "3000", EATON_5P, NULL }, + /* Eaton 9E entry-level series per discussions in + * https://github.com/networkupstools/nut/issues/1925 + * https://github.com/networkupstools/nut/issues/2380 + * https://github.com/networkupstools/nut/issues/2492 + */ + { "unknown", "2000", EATON_9E, "9E2000 (presumed)" }, /* https://github.com/networkupstools/nut/issues/1925#issuecomment-1609262963 */ + { "Eaton 9E", "2000", EATON_9E, "9E2000" }, + { "Eaton 9E", "2000i", EATON_9E, "9E2000i" }, + { "Eaton 9E", "3000", EATON_9E, "9E3000" }, + { "Eaton 9E", "3000i", EATON_9E, "9E3000i" }, + /* Pulsar M models */ { "PULSAR M", "2200", MGE_PULSAR_M_2200, NULL }, { "PULSAR M", "3000", MGE_PULSAR_M_3000, NULL }, From 7130c98eb178dc073a109ee4fa2d72f6a5dc7e1f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 31 Jul 2024 18:13:04 +0200 Subject: [PATCH 2/8] drivers/mge-hid.c: rephrase the presumed 9E2000*i* model [#2562] I did not find any actual mentions of plain "9E2000" without an "i", only these: https://www.eaton.com/tr/en-gb/skuPage.9E2000I.html Also prepared for "9E3000i" models while here. Signed-off-by: Jim Klimov --- drivers/mge-hid.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mge-hid.c b/drivers/mge-hid.c index c7c5bd6e9f..e1f18f1995 100644 --- a/drivers/mge-hid.c +++ b/drivers/mge-hid.c @@ -1152,12 +1152,18 @@ static models_name_t mge_model_names [] = * https://github.com/networkupstools/nut/issues/2380 * https://github.com/networkupstools/nut/issues/2492 */ - { "unknown", "2000", EATON_9E, "9E2000 (presumed)" }, /* https://github.com/networkupstools/nut/issues/1925#issuecomment-1609262963 */ { "Eaton 9E", "2000", EATON_9E, "9E2000" }, { "Eaton 9E", "2000i", EATON_9E, "9E2000i" }, { "Eaton 9E", "3000", EATON_9E, "9E3000" }, { "Eaton 9E", "3000i", EATON_9E, "9E3000i" }, + /* https://github.com/networkupstools/nut/issues/1925#issuecomment-1609262963 + * if we failed to get iManufacturer, iProduct and iSerialNumber but saw + * the UPS.Flow.[4].ConfigApparentPower (the "2000" or "3000" part here) + */ + { "unknown", "2000", EATON_9E, "9E2000i (presumed)" }, + { "unknown", "3000", EATON_9E, "9E3000i (presumed)" }, + /* Pulsar M models */ { "PULSAR M", "2200", MGE_PULSAR_M_2200, NULL }, { "PULSAR M", "3000", MGE_PULSAR_M_3000, NULL }, From bd3a4b1304ae553f00cf80a5003f3f62d2670d7c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 31 Jul 2024 18:41:49 +0200 Subject: [PATCH 3/8] drivers/libusb1.c: nut_libusb_open(): comment about `if (!callback){...}` check Signed-off-by: Jim Klimov --- drivers/libusb1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/libusb1.c b/drivers/libusb1.c index 6f710cb95f..6669c178b1 100644 --- a/drivers/libusb1.c +++ b/drivers/libusb1.c @@ -601,6 +601,10 @@ static int nut_libusb_open(libusb_device_handle **udevp, nut_usb_set_altinterface(udev); + /* Did the driver provide a callback method for any further + * device acceptance checks (e.g. when same ID is supported + * by several sub-drivers, differing by vendor/model strings)? + */ if (!callback) { libusb_free_config_descriptor(conf_desc); libusb_free_device_list(devlist, 1); From ea99f96f87ea06cf5ff486ba7541bf8f74e2c33b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 31 Jul 2024 18:43:07 +0200 Subject: [PATCH 4/8] drivers/libusb1.c: nut_libusb_open(): try to re-fetch curDevice->Vendor, Product, Serial if NULL, after claiming it by other criteria [#2562] Signed-off-by: Jim Klimov --- drivers/libusb1.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/libusb1.c b/drivers/libusb1.c index 6669c178b1..2f325f30f1 100644 --- a/drivers/libusb1.c +++ b/drivers/libusb1.c @@ -33,7 +33,7 @@ #include "nut_stdint.h" #define USB_DRIVER_NAME "USB communication driver (libusb 1.0)" -#define USB_DRIVER_VERSION "0.48" +#define USB_DRIVER_VERSION "0.49" /* driver description structure */ upsdrv_info_t comm_upsdrv_info = { @@ -601,6 +601,70 @@ static int nut_libusb_open(libusb_device_handle **udevp, nut_usb_set_altinterface(udev); + /* If libusb failed to identify the device strings earlier, + * can we do that after claiming the interface? Just try... + * Note that we succeeded so far, meaning these strings were + * not among matching criteria. But they can be important for + * our drivers (e.g. per-model tweaks) and pretty reporting + * of certain `device.*` and/or `ups.*` data points. + */ + if (!curDevice->Vendor) { + retries = MAX_RETRY; + while (retries > 0) { + ret = libusb_get_string_descriptor_ascii(udev, dev_desc.iManufacturer, + (unsigned char*)string, sizeof(string)); + if (ret > 0) { + curDevice->Vendor = strdup(string); + if (curDevice->Vendor == NULL) { + libusb_free_device_list(devlist, 1); + fatal_with_errno(EXIT_FAILURE, "Out of memory"); + } + break; + } + retries--; + upsdebugx(1, "%s get iManufacturer failed, retrying...", __func__); + } + upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor ? curDevice->Vendor : "unknown"); + } + + if (!curDevice->Product) { + retries = MAX_RETRY; + while (retries > 0) { + ret = libusb_get_string_descriptor_ascii(udev, dev_desc.iProduct, + (unsigned char*)string, sizeof(string)); + if (ret > 0) { + curDevice->Product = strdup(string); + if (curDevice->Product == NULL) { + libusb_free_device_list(devlist, 1); + fatal_with_errno(EXIT_FAILURE, "Out of memory"); + } + break; + } + retries--; + upsdebugx(1, "%s get iProduct failed, retrying...", __func__); + } + upsdebugx(2, "- Product: %s", curDevice->Product ? curDevice->Product : "unknown"); + } + + if (!curDevice->Serial) { + retries = MAX_RETRY; + while (retries > 0) { + ret = libusb_get_string_descriptor_ascii(udev, dev_desc.iSerialNumber, + (unsigned char*)string, sizeof(string)); + if (ret > 0) { + curDevice->Serial = strdup(string); + if (curDevice->Serial == NULL) { + libusb_free_device_list(devlist, 1); + fatal_with_errno(EXIT_FAILURE, "Out of memory"); + } + break; + } + retries--; + upsdebugx(1, "%s get iSerialNumber failed, retrying...", __func__); + } + upsdebugx(2, "- Serial Number: %s", curDevice->Serial ? curDevice->Serial : "unknown"); + } + /* Did the driver provide a callback method for any further * device acceptance checks (e.g. when same ID is supported * by several sub-drivers, differing by vendor/model strings)? From 14dbd8c5ecc35209156382ea43be021abbdccd9b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 31 Jul 2024 18:49:17 +0200 Subject: [PATCH 5/8] drivers/libusb0.c: libusb_open(): comment about `if (!callback){...}` check Signed-off-by: Jim Klimov --- drivers/libusb0.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/libusb0.c b/drivers/libusb0.c index bc73eb2a99..64dc70c093 100644 --- a/drivers/libusb0.c +++ b/drivers/libusb0.c @@ -542,6 +542,10 @@ static int libusb_open(usb_dev_handle **udevp, nut_usb_set_altinterface(udev); + /* Did the driver provide a callback method for any further + * device acceptance checks (e.g. when same ID is supported + * by several sub-drivers, differing by vendor/model strings)? + */ if (!callback) { return 1; } From ad83b70bbd3a0f6eff64d6b8dbfc14621d3cba97 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 31 Jul 2024 18:49:45 +0200 Subject: [PATCH 6/8] drivers/libusb0.c: libusb_open(): try to re-fetch curDevice->Vendor, Product, Serial if NULL, after claiming it by other criteria [#2562] Signed-off-by: Jim Klimov --- drivers/libusb0.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/libusb0.c b/drivers/libusb0.c index 64dc70c093..c201d3d96f 100644 --- a/drivers/libusb0.c +++ b/drivers/libusb0.c @@ -542,6 +542,58 @@ static int libusb_open(usb_dev_handle **udevp, nut_usb_set_altinterface(udev); + /* If libusb failed to identify the device strings earlier, + * can we do that after claiming the interface? Just try... + * Note that we succeeded so far, meaning these strings were + * not among matching criteria. But they can be important for + * our drivers (e.g. per-model tweaks) and pretty reporting + * of certain `device.*` and/or `ups.*` data points. + */ + if (!curDevice->Vendor) { + retries = MAX_RETRY; + while (retries > 0) { + ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer, + string, sizeof(string)); + if (ret > 0) { + curDevice->Vendor = xstrdup(string); + break; + } + retries--; + upsdebugx(1, "%s get iManufacturer failed, retrying...", __func__); + } + upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor ? curDevice->Vendor : "unknown"); + } + + if (!curDevice->Product) { + retries = MAX_RETRY; + while (retries > 0) { + ret = usb_get_string_simple(udev, dev->descriptor.iProduct, + string, sizeof(string)); + if (ret > 0) { + curDevice->Product = xstrdup(string); + break; + } + retries--; + upsdebugx(1, "%s get iProduct failed, retrying...", __func__); + } + upsdebugx(2, "- Product: %s", curDevice->Product ? curDevice->Product : "unknown"); + } + + if (!curDevice->Serial) { + retries = MAX_RETRY; + while (retries > 0) { + ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, + string, sizeof(string)); + if (ret > 0) { + curDevice->Serial = xstrdup(string); + break; + } + retries--; + upsdebugx(1, "%s get iSerialNumber failed, retrying...", __func__); + } + upsdebugx(2, "- Serial Number: %s", curDevice->Serial ? curDevice->Serial : "unknown"); + } + /* Did the driver provide a callback method for any further * device acceptance checks (e.g. when same ID is supported * by several sub-drivers, differing by vendor/model strings)? From 0cb24fc07a0de4b33c2c5624a968227c2a581dbf Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 31 Jul 2024 22:33:41 +0200 Subject: [PATCH 7/8] drivers/mge-hid.c: add Eaton 9E1000* models, and "ir" suffix for rack [#2562] According to https://github.com/networkupstools/nut/pull/2571#issuecomment-2261337602 Signed-off-by: Jim Klimov --- drivers/mge-hid.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mge-hid.c b/drivers/mge-hid.c index e1f18f1995..ec1ef6db3e 100644 --- a/drivers/mge-hid.c +++ b/drivers/mge-hid.c @@ -1152,15 +1152,21 @@ static models_name_t mge_model_names [] = * https://github.com/networkupstools/nut/issues/2380 * https://github.com/networkupstools/nut/issues/2492 */ + { "Eaton 9E", "1000", EATON_9E, "9E1000" }, + { "Eaton 9E", "1000i", EATON_9E, "9E1000i" }, + { "Eaton 9E", "1000ir", EATON_9E, "9E1000ir" }, { "Eaton 9E", "2000", EATON_9E, "9E2000" }, { "Eaton 9E", "2000i", EATON_9E, "9E2000i" }, + { "Eaton 9E", "2000ir", EATON_9E, "9E2000ir" }, { "Eaton 9E", "3000", EATON_9E, "9E3000" }, { "Eaton 9E", "3000i", EATON_9E, "9E3000i" }, + { "Eaton 9E", "3000ir", EATON_9E, "9E3000ir" }, /* https://github.com/networkupstools/nut/issues/1925#issuecomment-1609262963 * if we failed to get iManufacturer, iProduct and iSerialNumber but saw * the UPS.Flow.[4].ConfigApparentPower (the "2000" or "3000" part here) */ + { "unknown", "1000", EATON_9E, "9E1000i (presumed)" }, { "unknown", "2000", EATON_9E, "9E2000i (presumed)" }, { "unknown", "3000", EATON_9E, "9E3000i (presumed)" }, From 649dac1703911e190a9da37cdb8e25a6936d9f1c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 1 Aug 2024 00:20:25 +0200 Subject: [PATCH 8/8] drivers/mge-hid.c: add Eaton 9En000 models "iau" suffix, and 9E3000 "ixl"/"ixlau" [#2562] Per https://github.com/networkupstools/nut/pull/2571#issuecomment-2261450468 Signed-off-by: Jim Klimov --- drivers/mge-hid.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mge-hid.c b/drivers/mge-hid.c index ec1ef6db3e..97ca23b1ba 100644 --- a/drivers/mge-hid.c +++ b/drivers/mge-hid.c @@ -1154,13 +1154,18 @@ static models_name_t mge_model_names [] = */ { "Eaton 9E", "1000", EATON_9E, "9E1000" }, { "Eaton 9E", "1000i", EATON_9E, "9E1000i" }, + { "Eaton 9E", "1000iau", EATON_9E, "9E1000iau" }, { "Eaton 9E", "1000ir", EATON_9E, "9E1000ir" }, { "Eaton 9E", "2000", EATON_9E, "9E2000" }, { "Eaton 9E", "2000i", EATON_9E, "9E2000i" }, + { "Eaton 9E", "2000iau", EATON_9E, "9E2000iau" }, { "Eaton 9E", "2000ir", EATON_9E, "9E2000ir" }, { "Eaton 9E", "3000", EATON_9E, "9E3000" }, { "Eaton 9E", "3000i", EATON_9E, "9E3000i" }, + { "Eaton 9E", "3000iau", EATON_9E, "9E3000iau" }, { "Eaton 9E", "3000ir", EATON_9E, "9E3000ir" }, + { "Eaton 9E", "3000ixl", EATON_9E, "9E3000ixl" }, + { "Eaton 9E", "3000ixlau", EATON_9E, "9E3000ixlau" }, /* https://github.com/networkupstools/nut/issues/1925#issuecomment-1609262963 * if we failed to get iManufacturer, iProduct and iSerialNumber but saw