26
26
#include "powercom-hid.h"
27
27
#include "usb-common.h"
28
28
29
- #define POWERCOM_HID_VERSION "PowerCOM HID 0.71 "
29
+ #define POWERCOM_HID_VERSION "PowerCOM HID 0.72 "
30
30
/* FIXME: experimental flag to be put in upsdrv_info */
31
31
32
32
/* PowerCOM */
@@ -62,10 +62,30 @@ static char powercom_scratch_buf[32];
62
62
*/
63
63
static char powercom_sdcmd_byte_order_fallback = 0 ;
64
64
65
+ /* Some devices (Raptor and Smart KING Pro series) follow the protocol
66
+ * where we can not set arbitrary value of shutdown delay in seconds
67
+ * (like in other powercom UPSes), but the shutdown delay can be set
68
+ * only from table "Table of possible delays for Shutdown commands"
69
+ * specified at page 17 of the protocol document:
70
+ * https://networkupstools.org/protocols/powercom/Software_USB_communication_controller_SKP_series.doc
71
+ *
72
+ * "Table of possible delays for Shutdown commands" (mentioned for
73
+ * `DelayBeforeShutdown` and `DelayBeforeStartup` HID Usages):
74
+ * Index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
75
+ * Value 12s 18s 24s 30s 36s 42s 48s 54s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m
76
+ * Sent to UPS .2 .3 .4 .5 .6 .7 .8 .9 01 02 03 04 05 06 07 08 09 10
77
+ *
78
+ */
79
+ static char powercom_sdcmd_discrete_delay = 0 ;
80
+
65
81
static const char * powercom_startup_fun (double value )
66
82
{
67
83
uint16_t i = value ;
68
84
85
+ /* For powercom_sdcmd_discrete_delay we also read minutes
86
+ * from DelayBeforeStartup (same as for older dialects).
87
+ * FIXME: ...but theoretically they can be 32-bit (1..99999)
88
+ */
69
89
snprintf (powercom_scratch_buf , sizeof (powercom_scratch_buf ), "%d" , 60 * (((i & 0x00FF ) << 8 ) + (i >> 8 )));
70
90
upsdebugx (3 , "%s: value = %.0f, buf = %s" , __func__ , value , powercom_scratch_buf );
71
91
@@ -75,20 +95,40 @@ static const char *powercom_startup_fun(double value)
75
95
static double powercom_startup_nuf (const char * value )
76
96
{
77
97
const char * s = dstate_getinfo ("ups.delay.start" );
78
- uint16_t val , command ;
98
+ uint32_t val , command ;
79
99
int iv ;
80
100
81
- iv = atoi (value ? value : s ) / 60 ;
82
- if (iv < 0 || (intmax_t )iv > (intmax_t )UINT16_MAX ) {
83
- upsdebugx (0 , "%s: value = %d is not in uint16_t range" , __func__ , iv );
101
+ /* Start with seconds "as is" - convert into whole minutes */
102
+ iv = atoi (value ? value : s ) / 60 ; /* minutes */
103
+ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP ) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS ) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE ) )
104
+ # pragma GCC diagnostic push
105
+ #endif
106
+ #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS
107
+ # pragma GCC diagnostic ignored "-Wtype-limits"
108
+ #endif
109
+ #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE
110
+ # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"
111
+ #endif
112
+ if (iv < 0 || (intmax_t )iv > (intmax_t )UINT32_MAX ) {
113
+ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP ) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS ) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE ) )
114
+ # pragma GCC diagnostic pop
115
+ #endif
116
+ upsdebugx (0 , "%s: value = %d is not in uint32_t range" , __func__ , iv );
84
117
return 0 ;
85
118
}
86
119
87
- /* COMMENTME: What are we doing here, a byte-swap in the word? */
88
- val = (uint16_t )iv ;
89
- command = (uint16_t )(val << 8 );
90
- command += (uint16_t )(val >> 8 );
91
- upsdebugx (3 , "%s: value = %s, command = %04X" , __func__ , value , command );
120
+ if (powercom_sdcmd_discrete_delay ) {
121
+ /* Per spec, DelayBeforeStartup reads and writes
122
+ * 4-byte "mmmm" values in minutes (1..99999) */
123
+ command = (uint32_t )iv ;
124
+ } else {
125
+ /* COMMENTME: What are we doing here, a byte-swap in the word? */
126
+ val = (uint16_t )iv ;
127
+ command = (uint16_t )(val << 8 );
128
+ command += (uint16_t )(val >> 8 );
129
+ }
130
+
131
+ upsdebugx (3 , "%s: value = %s, command = 0x%08X" , __func__ , value , command );
92
132
93
133
return command ;
94
134
}
@@ -101,6 +141,12 @@ static const char *powercom_shutdown_fun(double value)
101
141
{
102
142
uint16_t i = value ;
103
143
144
+ /* NOTE: for powercom_sdcmd_discrete_delay mode it seems we
145
+ * do not read DelayBeforeShutdown at all (not for time),
146
+ * the value is stored and retrieved as DelayBeforeStartup.
147
+ * FIXME: Should anything be changed here?
148
+ */
149
+
104
150
if (powercom_sdcmd_byte_order_fallback ) {
105
151
/* Legacy behavior */
106
152
snprintf (powercom_scratch_buf , sizeof (powercom_scratch_buf ), "%d" , 60 * (i & 0x00FF ) + (i >> 8 ));
@@ -120,25 +166,46 @@ static double powercom_shutdown_nuf(const char *value)
120
166
uint16_t val , command ;
121
167
int iv ;
122
168
123
- iv = atoi (value ? value : s );
169
+ iv = atoi (value ? value : s ); /* seconds */
124
170
if (iv < 0 || (intmax_t )iv > (intmax_t )UINT16_MAX ) {
125
171
upsdebugx (0 , "%s: value = %d is not in uint16_t range" , __func__ , iv );
126
172
return 0 ;
127
173
}
128
174
129
- val = (uint16_t )iv ;
130
- val = val ? val : 1 ; /* 0 sets the maximum delay */
131
- if (powercom_sdcmd_byte_order_fallback ) {
132
- /* Legacy behavior */
133
- command = ((uint16_t )((val % 60 ) << 8 )) + (uint16_t )(val / 60 );
134
- command |= 0x4000 ; /* AC RESTART NORMAL ENABLE */
175
+ if (powercom_sdcmd_discrete_delay ) {
176
+ if (iv <= 12 ) command = 1 ;
177
+ else if (iv <= 18 ) command = 2 ;
178
+ else if (iv <= 24 ) command = 3 ;
179
+ else if (iv <= 30 ) command = 4 ;
180
+ else if (iv <= 36 ) command = 5 ;
181
+ else if (iv <= 42 ) command = 6 ;
182
+ else if (iv <= 48 ) command = 7 ;
183
+ else if (iv <= 54 ) command = 8 ;
184
+ else if (iv <= 60 ) command = 9 ;
185
+ else if (iv <= 120 ) command = 10 ;
186
+ else if (iv <= 180 ) command = 11 ;
187
+ else if (iv <= 240 ) command = 12 ;
188
+ else if (iv <= 300 ) command = 13 ;
189
+ else if (iv <= 360 ) command = 14 ;
190
+ else if (iv <= 420 ) command = 15 ;
191
+ else if (iv <= 480 ) command = 16 ;
192
+ else if (iv <= 540 ) command = 17 ;
193
+ else command = 18 ;
135
194
} else {
136
- /* New default */
137
- command = ((uint16_t )((val / 60 ) << 8 )) + (uint16_t )(val % 60 );
138
- command |= 0x0040 ; /* AC RESTART NORMAL ENABLE */
195
+ val = (uint16_t )iv ;
196
+ val = val ? val : 1 ; /* 0 sets the maximum delay */
197
+ if (powercom_sdcmd_byte_order_fallback ) {
198
+ /* Legacy behavior */
199
+ command = ((uint16_t )((val % 60 ) << 8 )) + (uint16_t )(val / 60 );
200
+ command |= 0x4000 ; /* AC RESTART NORMAL ENABLE */
201
+ } else {
202
+ /* New default */
203
+ command = ((uint16_t )((val / 60 ) << 8 )) + (uint16_t )(val % 60 );
204
+ command |= 0x0040 ; /* AC RESTART NORMAL ENABLE */
205
+ }
139
206
}
140
207
141
- upsdebugx (3 , "%s: value = %s, command = %04X" , __func__ , value , command );
208
+ upsdebugx (3 , "%s: value = %s, command = 0x %04X" , __func__ , value , command );
142
209
143
210
return command ;
144
211
}
@@ -153,6 +220,7 @@ static double powercom_stayoff_nuf(const char *value)
153
220
uint16_t val , command ;
154
221
int iv ;
155
222
223
+ /* FIXME: Anything for powercom_sdcmd_discrete_delay? */
156
224
iv = atoi (value ? value : s );
157
225
if (iv < 0 || (intmax_t )iv > (intmax_t )UINT16_MAX ) {
158
226
upsdebugx (0 , "%s: value = %d is not in uint16_t range" , __func__ , iv );
@@ -171,7 +239,7 @@ static double powercom_stayoff_nuf(const char *value)
171
239
command |= 0x0080 ; /* AC RESTART NORMAL DISABLE */
172
240
}
173
241
174
- upsdebugx (3 , "%s: value = %s, command = %04X" , __func__ , value , command );
242
+ upsdebugx (3 , "%s: value = %s, command = 0x %04X" , __func__ , value , command );
175
243
176
244
return command ;
177
245
}
@@ -592,6 +660,7 @@ static int powercom_claim(HIDDevice_t *hd)
592
660
593
661
accept :
594
662
powercom_sdcmd_byte_order_fallback = testvar ("powercom_sdcmd_byte_order_fallback" );
663
+ powercom_sdcmd_discrete_delay = testvar ("powercom_sdcmd_discrete_delay" );
595
664
596
665
return 1 ;
597
666
}
0 commit comments