1
/* nutdrv_qx_blazer-common.c - Common functions/settings for nutdrv_qx_{mecer,megatec,megatec-old,mustek,q1,voltronic-qs,zinto}.{c,h}
4
* 2013 Daniele Pezzini <hyouko@gmail.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#include "nutdrv_qx.h"
24
#include "nutdrv_qx_blazer-common.h"
28
/* Range for ups.delay.start */
29
info_rw_t blazer_r_ondelay[] = {
35
/* Range for ups.delay.shutdown */
36
info_rw_t blazer_r_offdelay[] = {
42
/* == Support functions == */
44
/* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */
45
int blazer_claim(void) {
47
/* To tell whether the UPS is supported or not, we'll check both status (Q1/QS/D) and vendor (I/FW?) - provided that we were not told not to do it with the ups.conf flag 'novendor'. */
49
item_t *item = find_nut_info("input.voltage", 0, 0);
51
/* Don't know what happened */
55
/* No reply/Unable to get value */
56
if (qx_process(item, NULL))
59
/* Unable to process value */
60
if (ups_infoval_set(item) != 1)
63
if (testvar("novendor"))
67
item = find_nut_info("ups.firmware", 0, 0);
69
/* Don't know what happened */
71
dstate_delinfo("input.voltage");
75
/* No reply/Unable to get value */
76
if (qx_process(item, NULL)) {
77
dstate_delinfo("input.voltage");
81
/* Unable to process value */
82
if (ups_infoval_set(item) != 1) {
83
dstate_delinfo("input.voltage");
91
/* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0.
92
* NOTE: this 'light' version only checks for status (Q1/QS/D/..) */
93
int blazer_claim_light(void) {
95
/* To tell whether the UPS is supported or not, we'll check just status (Q1/QS/D/..). */
97
item_t *item = find_nut_info("input.voltage", 0, 0);
99
/* Don't know what happened */
103
/* No reply/Unable to get value */
104
if (qx_process(item, NULL))
107
/* Unable to process value */
108
if (ups_infoval_set(item) != 1)
115
/* Subdriver-specific flags/vars */
116
void blazer_makevartable(void)
118
addvar(VAR_FLAG, "norating", "Skip reading rating information from UPS");
119
addvar(VAR_FLAG, "novendor", "Skip reading vendor information from UPS");
122
/* Subdriver-specific initups */
123
void blazer_initups(item_t *qx2nut)
128
nr = testvar("norating");
129
nv = testvar("novendor");
134
for (item = qx2nut; item->info_type != NULL; item++) {
140
if (nr && !strcasecmp(item->command, "F\r")) {
141
upsdebugx(2, "%s: skipping %s", __func__, item->info_type);
142
item->qxflags |= QX_FLAG_SKIP;
146
if (nv && (!strcasecmp(item->command, "I\r") || !strcasecmp(item->command, "FW?\r"))) {
147
upsdebugx(2, "%s: skipping %s", __func__, item->info_type);
148
item->qxflags |= QX_FLAG_SKIP;
154
/* == Preprocess functions == */
156
/* Preprocess setvars */
157
int blazer_process_setvar(item_t *item, char *value, size_t valuelen)
159
if (!strlen(value)) {
160
upsdebugx(2, "%s: value not given for %s", __func__, item->info_type);
164
if (!strcasecmp(item->info_type, "ups.delay.start")) {
166
int ondelay = strtol(value, NULL, 10);
168
/* Truncate to minute */
169
ondelay -= (ondelay % 60);
171
snprintf(value, valuelen, "%d", ondelay);
173
} else if (!strcasecmp(item->info_type, "ups.delay.shutdown")) {
175
int offdelay = strtol(value, NULL, 10);
177
/* Truncate to nearest settable value */
179
offdelay -= (offdelay % 6);
181
offdelay -= (offdelay % 60);
184
snprintf(value, valuelen, "%d", offdelay);
188
/* Don't know what happened */
196
/* Preprocess instant commands */
197
int blazer_process_command(item_t *item, char *value, size_t valuelen)
199
if (!strcasecmp(item->info_type, "shutdown.return")) {
201
/* Sn: Shutdown after n minutes and then turn on when mains is back
202
* SnRm: Shutdown after n minutes and then turn on after m minutes
203
* Accepted values for n: .2 -> .9 , 01 -> 10
204
* Accepted values for m: 0001 -> 9999
205
* Note: "S01R0001" and "S01R0002" may not work on early (GE) firmware versions.
206
* The failure mode is that the UPS turns off and never returns.
207
* The fix is to push the return value up by 2, i.e. S01R0003, and it will return online properly.
208
* (thus the default of ondelay=3 mins) */
210
int offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10),
211
ondelay = strtol(dstate_getinfo("ups.delay.start"), NULL, 10) / 60;
212
char buf[SMALLBUF] = "";
217
snprintf(buf, sizeof(buf), ".%d", offdelay / 6);
219
snprintf(buf, sizeof(buf), "%02d", offdelay / 60);
222
} else if (offdelay < 60) {
224
snprintf(buf, sizeof(buf), ".%dR%04d", offdelay / 6, ondelay);
228
snprintf(buf, sizeof(buf), "%02dR%04d", offdelay / 60, ondelay);
232
snprintf(value, valuelen, item->command, buf);
234
} else if (!strcasecmp(item->info_type, "shutdown.stayoff")) {
237
* Shutdown after n minutes and stay off
238
* Accepted values for n: .2 -> .9 , 01 -> 10 */
240
int offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10);
241
char buf[SMALLBUF] = "";
244
snprintf(buf, sizeof(buf), ".%d", offdelay / 6);
246
snprintf(buf, sizeof(buf), "%02d", offdelay / 60);
249
snprintf(value, valuelen, item->command, buf);
251
} else if (!strcasecmp(item->info_type, "test.battery.start")) {
253
int delay = strlen(value) > 0 ? strtol(value, NULL, 10) : 600;
255
if ((delay < 60) || (delay > 5940)) {
256
upslogx(LOG_ERR, "%s: battery test time '%d' out of range [60..5940] seconds", item->info_type, delay);
262
snprintf(value, valuelen, item->command, delay);
266
/* Don't know what happened */
274
/* Process status bits */
275
int blazer_process_status_bits(item_t *item, char *value, size_t valuelen)
279
if (strspn(item->value, "01") != 1) {
280
upsdebugx(3, "%s: unexpected value %s@%d->%s", __func__, item->value, item->from, item->value);
286
case 38: /* Utility Fail (Immediate) */
288
if (item->value[0] == '1')
294
case 39: /* Battery Low */
296
if (item->value[0] == '1')
302
case 40: /* Bypass/Boost or Buck Active */
304
if (item->value[0] == '1') {
308
vi = strtod(dstate_getinfo("input.voltage"), NULL);
309
vo = strtod(dstate_getinfo("output.voltage"), NULL);
312
upsdebugx(2, "%s: output voltage too low", __func__);
314
} else if (vo < 0.95 * vi) {
316
} else if (vo < 1.05 * vi) {
318
} else if (vo < 1.5 * vi) {
321
upsdebugx(2, "%s: output voltage too high", __func__);
329
case 41: /* UPS Failed - ups.alarm */
331
if (item->value[0] == '1')
332
val = "UPS selftest failed!";
335
case 42: /* UPS Type - ups.type */
337
if (item->value[0] == '1')
338
val = "offline / line interactive";
343
case 43: /* Test in Progress */
345
if (item->value[0] == '1')
351
case 44: /* Shutdown Active */
353
if (item->value[0] == '1') {
354
if (!strcasecmp(item->info_type, "ups.status"))
357
val = "Shutdown imminent!";
358
} else if (!strcasecmp(item->info_type, "ups.status")) {
363
case 45: /* Beeper status - ups.beeper.status */
365
if (item->value[0] == '1')
372
/* Don't know what happened */
376
snprintf(value, valuelen, "%s", val);