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

apc_modbus: Updates, command, writable variables and outlet group support #2184

Merged
merged 15 commits into from
Mar 2, 2024

Conversation

EchterAgo
Copy link
Contributor

@EchterAgo EchterAgo commented Nov 14, 2023

This adds support for commands, writable variables and outlet groups.

  • For commands there is a new table called apc_modbus_command_map which defines the supported commands as a tuple of command name, register offset and value to write. This also adds a new instcmd status called STAT_INSTCMD_CONVERSION_FAILED for when conversion of values fails. On startup all the commands are registered using dstate_addcmd. This also adds support for the upsdrv_shutdown function.
  • For writable variables we added a new flag called APC_VF_RW to the existing variables that indicates a writable variable. We added code to convert from a string to UINT/INT/STRING variables with output in APCs register format. There is a new _apc_modbus_setvar function that handles setting variables and rereading them from the device. This also adds a new setvar status called STAT_SET_CONVERSION_FAILED for when conversion of values fails. Variables are now correctly set as ST_FLAG_STRING and ST_FLAG_RW and we call dstate_setaux to give a maximum length for strings.
  • For outlet groups, we now have names, configurable delays and commands per outlet group. Devices have an outlet group called MOG (Main outlet group) that switches all the outputs of the UPS and 1-3 SOGs (Switched outlet groups) that can be controlled independently. Note that MOG is outlet.group.0 and the SOGs start at outlet.group.1. The outlet groups should have markings with the same index at the back of the unit.
  • This also reduces the length of some of the defines to make the variable maps more readable.
  • It also adds a comment to when the reopen matcher is created that clarifies why we create it.

fixes #2119

General points

  • Described the changes in the PR submission or a separate issue, e.g.
    known published or discovered protocols, applicable hardware (expected
    compatible and actually tested/developed against), limitations, etc.

  • There may be multiple commits in the PR, aligned and commented with
    a functional change. Notably, coding style changes better belong in a
    separate PR, but certainly in a dedicated commit to simplify reviews
    of "real" changes in the other commits. Similarly for typo fixes in
    comments or text documents.

Frequent "underwater rocks" for driver addition/update PRs

  • Revised existing driver families and added a sub-driver if applicable
    (nutdrv_qx, usbhid-ups...) or added a brand new driver in the other
    case.

  • Did not extend obsoleted drivers with new hardware support features
    (notably blazer and other single-device family drivers for Qx protocols,
    except the new nutdrv_qx which should cover them all).

  • For updated existing device drivers, bumped the DRIVER_VERSION macro
    or its equivalent.

  • For USB devices (HID or not), revised that the driver uses unique
    VID/PID combinations, or raised discussions when this is not the case
    (several vendors do use same interface chips for unrelated protocols).

  • For new USB devices, built and committed the changes for the
    scripts/upower/95-upower-hid.hwdb file

  • Proposed NUT data mapping is aligned with existing docs/nut-names.txt
    file. If the device exposes useful data points not listed in the file, the
    experimental.* namespace can be used as documented there, and discussion
    should be raised on the NUT Developers mailing list to standardize the new
    concept.

  • Updated data/driver.list.in if applicable (new tested device info)

Frequent "underwater rocks" for general C code PRs

  • Did not "blindly assume" default integer type sizes and value ranges,
    structure layout and alignment in memory, endianness (layout of bytes and
    bits in memory for multi-byte numeric types), or use of generic int where
    language or libraries dictate the use of size_t (or ssize_t sometimes).
  • Progress and errors are handled with upsdebugx(), upslogx(),
    fatalx() and related methods, not with direct printf() or exit().
    Similarly, NUT helpers are used for error-checked memory allocation and
    string operations (except where customized error handling is needed,
    such as unlocking device ports, etc.)

  • Coding style (including whitespace for indentations) follows precedent
    in the code of the file, and examples/guide in docs/developers.txt file.

  • For newly added files, the Makefile.am recipes were updated and the
    make distcheck target passes.

General documentation updates

  • Updated docs/acknowledgements.txt (for vendor-backed device support)

  • Added or updated manual page information in docs/man/*.txt files
    and corresponding recipe lists in docs/man/Makefile.am for new pages

  • Passed make spellcheck, updated spell-checking dictionary in the
    docs/nut.dict file if needed (did not remove any words -- the make
    rule printout in case of changes suggests how to maintain it).

Additional work may be needed after posting this PR

  • Propose a PR for NUT DDL with detailed device data dumps from tests
    against real hardware (the more models, the better).

  • Address NUT CI farm build failures for the PR: testing on numerous
    platforms and toolkits can expose issues not seen on just one system.

  • Revise suggestions from LGTM.COM analysis about "new issues" with
    the changed codebase.

@EchterAgo
Copy link
Contributor Author

Please give this some more testing. I did test a bit already but was unable to test controlling the load on the UPS.

@PrplHaz4

@EchterAgo
Copy link
Contributor Author

@jimklimov I'd still like to know what to do regarding outlet group commands, see #2119 (comment)

@EchterAgo
Copy link
Contributor Author

What I also need to know if the load.* and shutdown.* commands work or if we need to specify the MOG as a target.

@EchterAgo EchterAgo force-pushed the apc_modbus_updates branch 3 times, most recently from 0ab8aad to 8105c73 Compare November 15, 2023 21:26
@jimklimov jimklimov added this to the 2.8.2 milestone Nov 16, 2023
@EchterAgo
Copy link
Contributor Author

@jimklimov thanks for the header change, I forgot that.

@AppVeyorBot
Copy link

@jimklimov
Copy link
Member

@EchterAgo : sorry, I'm a lot on the road and in meetings over this week, could not give much thought to your questions :\

CC @aquette : any ideas regarding outlets (individual/groups) management here?

@EchterAgo
Copy link
Contributor Author

I noticed eaton-pdu-marlin-mib.c already uses outlet.group.* for commands.

@jimklimov
Copy link
Member

@EchterAgo : I think your force-push removed apc_modbus.h from the Makefile.am again?..

@EchterAgo
Copy link
Contributor Author

@jimklimov readded

@jimklimov
Copy link
Member

@EchterAgo : got a detailed testing report in the mailing list : https://alioth-lists.debian.net/pipermail/nut-upsuser/2023-November/013486.html

Seems there's some work still needed here and there... :)

@EchterAgo
Copy link
Contributor Author

EchterAgo commented Nov 22, 2023

@EchterAgo : got a detailed testing report in the mailing list : https://alioth-lists.debian.net/pipermail/nut-upsuser/2023-November/013486.html

Seems there's some work still needed here and there... :)

That is good to hear.

I'll look into the power switching commands, already have an idea what might be wrong. Sadly I can not test this here at the moment because I'm currently running a 200TB data migration and don't want to interrupt that.

As for the battery.date issue, I thought I tested that, will look again.

I did test the calibrate.start and calibrate.stop commands.

I'll implement ups.test.result.

@EchterAgo
Copy link
Contributor Author

Rebased and added ups.test.result

@jimklimov DCO is not happy because of a mismatch between your emails:

Commit sha: 6d08119, Author: Jim Klimov, Committer: Axel Gembe; Expected "Jim Klimov jimklimov@gmail.com", but got "Jim Klimov jimklimov+nut@gmail.com".

@EchterAgo
Copy link
Contributor Author

I think I found the battery.date issue, strptime produces a struct tm with tm_isdst, tm_gmtoff and tm_zone based on the current time zone.

_apc_modbus_date_from_nut works with local time while _apc_modbus_date_to_nut works with UTC. I'm going to make everything work with UTC.

@EchterAgo
Copy link
Contributor Author

Pushed new commits, setvar issue is fixed and the battery.date issue too.

@EchterAgo
Copy link
Contributor Author

I also added the target outlet group to the load.* and shutdown.* commands. I think this might be what is causing those commands not to work, not sure about the outlet.* commands, I don't know if those were specifically tested.

@EchterAgo
Copy link
Contributor Author

@jimklimov do you want me to make the author and signed-off-by in your commit use the same email address? If so, with or without the +nut suffix?

@AppVeyorBot
Copy link

@EchterAgo
Copy link
Contributor Author

mingw build:

apc_modbus.c: In function '_apc_modbus_date_from_nut':
apc_modbus.c:784:27: error: implicit declaration of function 'timegm'; did you mean 'time'? [-Werror=implicit-function-declaration]
  784 |         if ((epoch_time = timegm(&tm_struct)) == -1) {
      |                           ^~~~~~
      |                           time

looks like we need another way to fix this or implement a timegm alternative for Windows.

@EchterAgo
Copy link
Contributor Author

Or we work with local time, but then we have to also calculate apc_date_start_offset based on the current time zone.

EchterAgo and others added 4 commits November 24, 2023 14:23
…port

This adds support for commands, writable variables and outlet groups.

- For commands there is a new table called `apc_modbus_command_map`
  which defines the supported commands as a tuple of command name,
  register offset and value to write. This also adds a new instcmd
  status called `STAT_INSTCMD_CONVERSION_FAILED` for when conversion
  of values fails. On startup all the commands are registered using
  `dstate_addcmd`.
  This also adds support for the `upsdrv_shutdown` function.
- For writable variables we added a new flag called `APC_VF_RW` to the
  existing variables that indicates a writable variable. We added code
  to convert from a string to UINT/INT/STRING variables with output in
  APCs register format. There is a new `_apc_modbus_setvar` function
  that handles setting variables and rereading them from the device.
  This also adds a new setvar status called `STAT_SET_CONVERSION_FAILED`
  for when conversion of values fails. Variables are now correctly set
  as `ST_FLAG_STRING` and `ST_FLAG_RW` and we call `dstate_setaux` to
  give a maximum length for strings.
- For outlet groups, we now have names, configurable delays and commands
  per outlet group. Devices have an outlet group called MOG (Main outlet
  group) that switches all the outputs of the UPS and 1-3 SOGs (Switched
  outlet groups) that can be controlled independently. Note that MOG is
  `outlet.group.0` and the SOGs start at `outlet.group.1`. The outlet
  groups should have markings with the same index at the back of the
  unit.
- This also reduces the length of some of the defines to make the
  variable maps more readable.
- It also adds a comment to when the reopen matcher is created that
  clarifies why we create it.

Signed-off-by: Axel Gembe <axel@gembe.net>
Signed-off-by: Jim Klimov <jimklimov@gmail.com>
This outputs the test result, the source of the start of the test and
a result modifier.

Signed-off-by: Axel Gembe <axel@gembe.net>
The for loop searching for the correct register map kept on looping
after finding the value which caused the `apc_map` mariable to
potentially point to the wrong register map.

This can cause the re-read of the set value at the end of the function
to fail.

Signed-off-by: Axel Gembe <axel@gembe.net>
MINGW headers do not provide a `timegm` implementation but there is a
`_mkgmtime` which does the same:

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/mkgmtime-mkgmtime32-mkgmtime64

Signed-off-by: Axel Gembe <axel@gembe.net>
This changes `_apc_modbus_date_from_nut` to use `timegm` instead of
`mktime` which does not add the current time zone information. This
fixes dates that are off-by-one compared to what was set.

Signed-off-by: Axel Gembe <axel@gembe.net>
Maybe this is needed, needs to be confirmed.

Signed-off-by: Axel Gembe <axel@gembe.net>
@EchterAgo
Copy link
Contributor Author

FYI, if we want an actual fallback implementation for timegm, there are some here:

https://stackoverflow.com/questions/16647819/timegm-cross-platform

The one from boost should be license compatible and easy to port.

@AppVeyorBot
Copy link

@jimklimov
Copy link
Member

jimklimov commented Nov 27, 2023

@EchterAgo : more testing results coming in the mail thread, many things proven working :)

One point that got me concerned was about possibly (mis-)treating battery calibration as a "OB TEST" state. There are some places where we treat the "CAL" state specially (e.g. for requesting a shutdown or not when the battery charge goes low in upsmon). Now that I looked for it, I saw a few more cases of status_set("TEST") in older drivers, but did not right now revise what they were about (battery or some other tests?) - can you please revise what happens in apc_modbus, from search results I saw it also using CAL but did not read into the context...

FWIW, docs/new-drivers.txt does mention CAL but not a TEST...

@jimklimov
Copy link
Member

Cheers, how is it going here? Do you plan to post some updates shortly, or is (from your viewpoint) the change OK to merge as is and follow up on specific problems and improvements later?

@EchterAgo
Copy link
Contributor Author

EchterAgo commented Jan 12, 2024

Cheers, how is it going here? Do you plan to post some updates shortly, or is (from your viewpoint) the change OK to merge as is and follow up on specific problems and improvements later?

Sorry, it has been difficult for me to find time to work on this lately. I just was able to test the outlet commands and it seems that the outlet specific commands for outlet group 1, which is the only one I have, all work for me. What does not work are the outlet commands that specify the MOG (main outlet group). I'm not sure if that group is actually supposed to be switchable. I'll check the documentation some more.

@AppVeyorBot
Copy link

@AppVeyorBot
Copy link

@jimklimov
Copy link
Member

Cheers, I'm going to merge this PR as it stands today, posted an issue for follow-ups according to comments above.

I believe this change set would already benefit some users, and would expose the code for more practical experience and feedback for further steps. Thank you very much for bringing it this far, and I hope you would have time to get even more done :)

@jimklimov jimklimov merged commit 39b8b56 into networkupstools:master Mar 2, 2024
10 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

apc_modbus: Add support for commands
3 participants