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

Updated Phoenix Contact modbus driver for newer models #2689

Merged
merged 17 commits into from
Dec 1, 2024

Conversation

RikyPlaza
Copy link
Contributor

Updated Phoenix Contact modbus driver for newer models which are using different modbus addresses. Choice is made basing on the UPS firmware version and the model information have been changed in order to have a quick feedback over the new/old model detection.

…es. Choice is made basing on firmware version.

Signed-off-by: RikyPlaza <[email protected]>
Copy link
Member

@jimklimov jimklimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for a solid-looking enhancement. A NEWS.adoc entry would be good, beside addressing the specific comments I mentioned during a look at code.

r = modbus_set_slave(modbus_ctx, MODBUS_SLAVE_ID); /* slave ID */
if (r < 0) {
modbus_free(modbus_ctx);
fatalx(EXIT_FAILURE, "Invalid modbus slave ID %d",MODBUS_SLAVE_ID);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and several times above - needless added whitespace

if (CHECK_BIT(tab_reg[0], 16))
alarm_set("Low Battery (Service)");

uint32_t alarms_word;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and above, variable definitions are added in the middle of scope. NUT coding style requires all definitions to be before code, so older systems can build current NUT too. Probably that is what CI failed about all over the place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undersoot!


mrir(modbus_ctx, 0x2000, 1, &actual_code_functions);

tab_reg[0] = CHECK_BIT(actual_code_functions, 2); //battery mode is the 2nd bit of the register 0x2000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use block comment style /* ... */

break;
case OLD_UPS:

mrir(modbus_ctx, 29697, 3, tab_reg); /* LB is actually called "shutdown event" on this ups */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea if these numbers make more sense in hex? Are they perhaps bit-masks of some command combos?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason why i kept the old addresses in dec and put the new ones in hex is the way they are reported in the UPSes datasheet. If you want to use a standard for coding i can change all addresses in the same way, but for maintenence in the furure it will be necessary to convery all numbers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, got no particular preference here. If maintenance would be easier with decimal numbers - so be it. Maybe worth a short comment at start of the file though.


#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
#define MODBUS_SLAVE_ID 192

#define OLD_UPS 0
#define NEW_UPS 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how soon "old" vs. "new" would become obsolete? Maybe more symbolic names would be better (just a thought)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, i've put the models. To be honest there would be another model (TRIO) but i don't have the hardware to test the communication. As soon as it will arrive i can test the driver and see if changes are needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another options can be an enum to also constrain the values accepted at compile-time (and get warnings like that a switch does not look at all newly defined options).


uint16_t FWVersion;

mrir(modbus_ctx, 0x0004, 1, &FWVersion);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to also populate ups.firmware

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, not sure if the variable should be defined somewhere else or i can just call the dstate_setinfo function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the global variable makes sense if this info would be used elsewhere (e.g. instead of those OLD_UPS/NEW_UPS defines?)

@RikyPlaza
Copy link
Contributor Author

@jimklimov Hello, regarding the NEWS.adoc, could you give me some references please? I've looked in other pull requests but i can't find any example. Thank you!

@AppVeyorBot
Copy link

…cted alarm trigger (wrong bit used)

Signed-off-by: RikyPlaza <[email protected]>
@jimklimov
Copy link
Member

@jimklimov Hello, regarding the NEWS.adoc, could you give me some references please? I've looked in other pull requests but i can't find any example. Thank you!

Probably just add a paragraph (bullet point) similar to ones that are already there.

@AppVeyorBot
Copy link

Copy link
Contributor Author

@RikyPlaza RikyPlaza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files reviewed.

@AppVeyorBot
Copy link

@RikyPlaza RikyPlaza requested a review from jimklimov November 26, 2024 05:36
@jimklimov
Copy link
Member

FYI: If the lack of default label would also prove a problem with some other compilers, check other drivers for use of pragmas around that. Typically we end up with a monster like:

#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) )
# pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT
# pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE
# pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunreachable-code"
# pragma clang diagnostic ignored "-Wcovered-switch-default"
#endif
                /* All enum cases defined as of the time of coding
                 * have been covered above. Handle later definitions,
                 * memory corruptions and buggy inputs below...
                 */
                default:
                        fatalx(EXIT_FAILURE, "no suitable definition found!");
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) )
# pragma GCC diagnostic pop
#endif

@jimklimov
Copy link
Member

Also remembered: a man page would be needed to describe the supported devices and the driver options (per addvar() in code) and maybe other nuances - known caveats, etc. Ideally this comes from a driver author, as they best know if there is anything special to know about the devices.

@RikyPlaza
Copy link
Contributor Author

RikyPlaza commented Nov 26, 2024

the lack of default label would also prove a problem with some other compilers, check other drivers for use of pragmas around that. Typically we end up with a monster like:

@jimklimov I'm not sure if the checks are running, for now i don't see any error so i would let the check finish. Do you know how much time do they ususally take?

@RikyPlaza
Copy link
Contributor Author

embered: a man page would be needed to describe the supported devices and the driver options (per addvar() in code) and maybe other nuances - known caveats, etc. Ideally this comes from a driver author, as they best know if there is anything special to know about the devices.

@jimklimov Ok, as soon as the checks are ok i'll take a look to the man page. Should i modify something already present or should i make a new man page?

@jimklimov
Copy link
Member

New driver - new man page :)

As for checks, it's about 3-5hrs for all scenarios to run; overall time depends on how maby other PR iterations are queued...

@RikyPlaza
Copy link
Contributor Author

@jimklimov Hi, now i see that the there are errors regarding the missing default label in switch statements, but i had to remove them in commit f19c8e0 since the checks were also failing. I really don't understand what it the issue...
In other drivers (blazer_usb.c, clone-outlet.c ecc) i see that the default label is preset.

@jimklimov
Copy link
Member

@RikyPlaza : did you try the construct with pragmas per #2689 (comment) ?

@RikyPlaza
Copy link
Contributor Author

@jimklimov Hello, if i consider the driver blazer_usb.c i don't see any pragma directive. I'm a little bit confused on how those drivers, without any pragma construct, pass the checks related to the default labels in switch statements...

@RikyPlaza
Copy link
Contributor Author

@jimklimov In any case now i try to insert that statemets and commit the driver. Let's see :)

…ault" label in switch statements.

Signed-off-by: RikyPlaza <[email protected]>
@jimklimov
Copy link
Member

jimklimov commented Nov 28, 2024

Different compilers and their different warning settings require different rules to be satisfied, and are sonetimes at odds:

  • a switch should definitively handle all cases, so must have a default label - works well for general numeric variables;
  • an enum's valid values are known at compile time, and each must be handled explicitly (even if implemented as many case value: labels preceding the same code block), so...
  • ...a default label is redundant (should never be reachable) in a switch that handles all enum values - this notion is head-on crash vs. the first rule above, hence the pragma's against warnings at this spot and the default label handled to be sure, as the least-worst solution.

Also note fall-through cases (lack of break/return/continue/... before next label) - these are considered a likely oversight by a programmer and in fact often are. Explicit goto superfluous_label to the next line defining this label solves the issue portably.

@RikyPlaza
Copy link
Contributor Author

@jimklimov no idea why the checks failed :)

Copy link
Contributor Author

@RikyPlaza RikyPlaza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea on the fails.

@jimklimov jimklimov merged commit 3984321 into networkupstools:master Dec 1, 2024
7 of 16 checks passed
@jimklimov
Copy link
Member

CI setup issue, mis-added new workers :\

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.

3 participants