Skip to content

Commit 414b340

Browse files
authored
Merge 263be99 into eb08bd4
2 parents eb08bd4 + 263be99 commit 414b340

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

NEWS.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ https://github.com/networkupstools/nut/milestone/13
4545
- Second-level bullet points listed in this file will now use 4 spaces
4646
(not 3 like before) for easier initial indentation of new entries.
4747

48+
- `apc_modbus` driver updates:
49+
* Fixed string join not doing zero termination. [PR #3413]
50+
4851
- NUT client libraries:
4952
* Complete support for actions documented in `docs/net-protocol.txt`
5053
was implemented in C++, Python and PERL bindings in-tree, and for Java
@@ -211,6 +214,7 @@ but the `nutshutdown` script would bail out quickly and quietly. [PR #3008]
211214
exposed for outlet groups actually present on the UPS. Global `load.*` and
212215
`shutdown.*` commands now correctly target all available outlet groups.
213216
[PR #3395]
217+
* Fixed string join not doing zero termination. [PR #3413]
214218
215219
- Introduced a new NUT driver named `meanwell_ntu` which provides support for
216220
the Mean Well NTU series hybrid inverter and UPS units. [PR #3206]

drivers/apc_modbus.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ static int _apc_modbus_string_join(const char *values[], size_t values_len, cons
695695
}
696696

697697
output_idx = 0;
698+
output[0] = 0; /* Always zero terminate */
698699

699700
for (i = 0; i < values_len && output_idx < output_len; i++) {
700701
if (values[i] == NULL)
@@ -771,6 +772,69 @@ static int _apc_modbus_battery_test_status_to_nut(const apc_modbus_value_t *valu
771772

772773
static apc_modbus_converter_t _apc_modbus_battery_test_status_conversion = { _apc_modbus_battery_test_status_to_nut, NULL };
773774

775+
static int _apc_modbus_runtime_calibration_status_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len)
776+
{
777+
const char *result, *source, *modifier;
778+
const char *values[3];
779+
780+
if (value == NULL || output == NULL || output_len == 0) {
781+
/* Invalid parameters */
782+
return 0;
783+
}
784+
785+
if (value->type != APC_VT_UINT) {
786+
return 0;
787+
}
788+
789+
result = NULL;
790+
if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_PENDING)) {
791+
result = "Pending";
792+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_INPROGRESS)) {
793+
result = "InProgress";
794+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_PASSED)) {
795+
result = "Passed";
796+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_FAILED)) {
797+
result = "Failed";
798+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_REFUSED)) {
799+
result = "Refused";
800+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_ABORTED)) {
801+
result = "Aborted";
802+
}
803+
804+
source = NULL;
805+
if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_SOURCE_PROTOCOL)) {
806+
source = "Source: Protocol";
807+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_SOURCE_LOCALUI)) {
808+
source = "Source: LocalUI";
809+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_SOURCE_INTERNAL)) {
810+
source = "Source: Internal";
811+
}
812+
813+
modifier = NULL;
814+
if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_INVALIDSTATE)) {
815+
modifier = "Modifier: InvalidState";
816+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_INTERNALFAULT)) {
817+
modifier = "Modifier: InternalFault";
818+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_STATEOFCHARGENOTACCEPTABLE)) {
819+
modifier = "Modifier: StateOfChargeNotAcceptable";
820+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_LOADCHANGE)) {
821+
modifier = "Modifier: LoadChange";
822+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_ACINPUTNOTACCEPTABLE)) {
823+
modifier = "Modifier: ACInputNotAcceptable";
824+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_LOADTOOLOW)) {
825+
modifier = "Modifier: LoadTooLow";
826+
} else if ((value->data.uint_value & APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_OVERCHARGEINPROGRESS)) {
827+
modifier = "Modifier: OverChargeInProgress";
828+
}
829+
830+
values[0] = result;
831+
values[1] = source;
832+
values[2] = modifier;
833+
return _apc_modbus_string_join(values, SIZEOF_ARRAY(values), ", ", output, output_len);
834+
}
835+
836+
static apc_modbus_converter_t _apc_modbus_runtime_calibration_status_conversion = { _apc_modbus_runtime_calibration_status_to_nut, NULL };
837+
774838
static const time_t apc_date_start_offset = 946684800; /* 2000-01-01 00:00 */
775839

776840
static int _apc_modbus_date_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len)
@@ -889,6 +953,7 @@ static apc_modbus_register_t apc_modbus_register_map_inventory[] = {
889953
static apc_modbus_register_t apc_modbus_register_map_status[] = {
890954
{ "input.transfer.reason", 2, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_status_change_cause_conversion, NULL, 0, NULL },
891955
{ "ups.test.result", 23, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_battery_test_status_conversion, NULL, 0, NULL },
956+
{ "experimental.ups.calibration.result", 24, 1, APC_VT_UINT, APC_VF_NONE, &_apc_modbus_runtime_calibration_status_conversion, NULL, 0, NULL },
892957
{ NULL, 0, 0, APC_VT_INT, APC_VF_NONE, NULL, NULL, 0.0f, NULL }
893958
};
894959

drivers/apc_modbus.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@
4848
#define APC_MODBUS_REPLACEBATTERYTESTSTATUS_BF_MOD_INTERNALFAULT (1 << 10)
4949
#define APC_MODBUS_REPLACEBATTERYTESTSTATUS_BF_MOD_STATEOFCHARGENOTACCEPTABLE (1 << 11)
5050

51+
/* RunTimeCalibrationStatus_BF register bits (register 24 in status block)
52+
* See MPAO-98KJ7F_R1_EN Appendix B */
53+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_PENDING (1 << 0)
54+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_INPROGRESS (1 << 1)
55+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_PASSED (1 << 2)
56+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_FAILED (1 << 3)
57+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_REFUSED (1 << 4)
58+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_ABORTED (1 << 5)
59+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_SOURCE_PROTOCOL (1 << 6)
60+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_SOURCE_LOCALUI (1 << 7)
61+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_SOURCE_INTERNAL (1 << 8)
62+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_INVALIDSTATE (1 << 9)
63+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_INTERNALFAULT (1 << 10)
64+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_STATEOFCHARGENOTACCEPTABLE (1 << 11)
65+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_LOADCHANGE (1 << 12)
66+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_ACINPUTNOTACCEPTABLE (1 << 13)
67+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_LOADTOOLOW (1 << 14)
68+
#define APC_MODBUS_RUNTIMECALIBRATIONSTATUS_BF_MOD_OVERCHARGEINPROGRESS (1 << 15)
69+
5170
#define APC_MODBUS_SOGRELAYCONFIGSETTING_BF_REG 590
5271
#define APC_MODBUS_SOGRELAYCONFIGSETTING_BF_MOG_PRESENT (1 << 0)
5372
#define APC_MODBUS_SOGRELAYCONFIGSETTING_BF_SOG_0_PRESENT (1 << 1)

0 commit comments

Comments
 (0)