Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow apc_modbus instances to monitor several USB devices on the same system #2790

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ https://github.com/networkupstools/nut/milestone/11
to have fixed a Segmentation Fault seen in earlier NUT releases with
some of the devices supported by this driver. [#2427]

- apc_modbus driver should now properly handle mismatches of criteria passed
to the regular expression matcher (e.g. serial number) allowing several USB
devices to be monitored without conflict. [#2609]

- phoenixcontact_modbus driver: Introduced Phoenix Contact QUINT4-UPS/24DC
management (only new modbus addresses). [#2689, #2716]

Expand Down
49 changes: 46 additions & 3 deletions drivers/apc_modbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,18 @@ static void _apc_modbus_create_reopen_matcher(void)
int r;

if (reopen_matcher != NULL) {
USBDeviceMatcher_t *curr, *prev = NULL;
for (curr = best_matcher; curr != NULL; curr = curr->next) {
if (curr == reopen_matcher) {
if (prev) {
prev->next = curr->next;
} else {
best_matcher = curr->next;
}
} else {
prev = curr;
}
}
USBFreeExactMatcher(reopen_matcher);
reopen_matcher = NULL;
}
Expand All @@ -951,8 +963,9 @@ static int _apc_modbus_reopen(void)

#if defined NUT_MODBUS_HAS_USB
/* We might have matched a new device in the modbus_connect callback.
* Because of this we want a new exact matcher. */
best_matcher = best_matcher->next;
* Because of this we want a new exact matcher. The method will drop
* the old reopen_matcher from our list starting at best_matcher, and
* from memory. */
_apc_modbus_create_reopen_matcher();
#endif /* defined NUT_MODBUS_HAS_USB */

Expand Down Expand Up @@ -1706,10 +1719,37 @@ static int _apc_modbus_usb_callback(const modbus_usb_device_t *device)

_apc_modbus_usb_lib_to_nut(device, &usbdevice);

upsdebugx(2, "- VendorID: %04x", usbdevice.VendorID);
upsdebugx(2, "- ProductID: %04x", usbdevice.ProductID);
upsdebugx(2, "- Manufacturer: %s", usbdevice.Vendor ? usbdevice.Vendor : "unknown");
upsdebugx(2, "- Product: %s", usbdevice.Product ? usbdevice.Product : "unknown");
upsdebugx(2, "- Serial Number: %s", usbdevice.Serial ? usbdevice.Serial : "unknown");
upsdebugx(2, "- Bus: %s", usbdevice.Bus ? usbdevice.Bus : "unknown");
#if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT)
upsdebugx(2, "- Bus Port: %s", usbdevice.BusPort ? usbdevice.BusPort : "unknown");
#endif
upsdebugx(2, "- Device: %s", usbdevice.Device ? usbdevice.Device : "unknown");
upsdebugx(2, "- Device release number: %04x", usbdevice.bcdDevice);

upsdebugx(2, "Trying to match device");
current_matcher = best_matcher;
upsdebugx(5, "%s: current_matcher=%p", __func__, (void*)current_matcher);
while (current_matcher != NULL) {
if (current_matcher->match_function(&usbdevice, current_matcher->privdata) == 1) {
int ret = current_matcher->match_function(&usbdevice, current_matcher->privdata);
upsdebugx(5, "%s: Tried matcher %p returned %d", __func__, (void*)current_matcher, ret);
if (ret == 1) {
/* known good hit */
break;
} else if (ret == 0) {
/* known active rejection */
upsdebugx(2, "%s: Device does not match - skipping", __func__);
/* go to next device that libmodbus would suggest and use this callback again */
return -1;
} else if (ret == -1) {
fatal_with_errno(EXIT_FAILURE, "%s: matcher", __func__);
} else if (ret == -2) {
upsdebugx(2, "%s: matcher: unspecified error", __func__);
return -1;
}

current_matcher = current_matcher->next;
Expand Down Expand Up @@ -1988,6 +2028,9 @@ void upsdrv_cleanup(void)

#if defined NUT_MODBUS_HAS_USB
USBFreeExactMatcher(reopen_matcher);
reopen_matcher = NULL;

USBFreeExactMatcher(regex_matcher);
regex_matcher = NULL;
#endif /* defined NUT_MODBUS_HAS_USB */
}