22
25
#define ENDCHAR 13 /* replies end with CR */
26
#define DRV_VERSION "0.60"
28
static char *modelname, *va;
27
#define UPSDELAY 50000 /* 50 ms delay required for reliable operation */
29
#define SER_WAIT_SEC 3 /* allow 3.0 sec for ser_get calls */
30
#define SER_WAIT_USEC 0
32
#define DRV_VERSION "1.03"
29
34
static float lowvolt = 0, highvolt = 0, voltrange = 0;
30
static int linenorm = 0, poll_failures = 0;
35
static int linenorm = 0;
31
36
static int inverted_bypass_bit = 0;
33
static void setmodel(const char *abbr, const char *va)
38
static void model_set(const char *abbr, const char *rating)
35
40
if (!strcmp(abbr, "FOR")) {
36
41
dstate_setinfo("ups.mfr", "%s", "Best Power");
37
dstate_setinfo("ups.model", "Fortress %s", va);
42
dstate_setinfo("ups.model", "Fortress %s", rating);
41
46
if (!strcmp(abbr, "FTC")) {
42
47
dstate_setinfo("ups.mfr", "%s", "Best Power");
43
dstate_setinfo("ups.model", "Fortress Telecom %s", va);
48
dstate_setinfo("ups.model", "Fortress Telecom %s", rating);
47
52
if (!strcmp(abbr, "PRO")) {
48
53
dstate_setinfo("ups.mfr", "%s", "Best Power");
49
dstate_setinfo("ups.model", "Patriot Pro %s", va);
54
dstate_setinfo("ups.model", "Patriot Pro %s", rating);
50
55
inverted_bypass_bit = 1;
54
59
if (!strcmp(abbr, "PR2")) {
55
60
dstate_setinfo("ups.mfr", "%s", "Best Power");
56
dstate_setinfo("ups.model", "Patriot Pro II %s", va);
61
dstate_setinfo("ups.model", "Patriot Pro II %s", rating);
57
62
inverted_bypass_bit = 1;
61
66
if (!strcmp(abbr, "325")) {
62
67
dstate_setinfo("ups.mfr", "%s", "Sola Australia");
63
dstate_setinfo("ups.model", "Sola 325 %s", va);
68
dstate_setinfo("ups.model", "Sola 325 %s", rating);
67
72
if (!strcmp(abbr, "520")) {
68
73
dstate_setinfo("ups.mfr", "%s", "Sola Australia");
69
dstate_setinfo("ups.model", "Sola 520 %s", va);
74
dstate_setinfo("ups.model", "Sola 520 %s", rating);
78
if (!strcmp(abbr, "610")) {
79
dstate_setinfo("ups.mfr", "%s", "Best Power");
80
dstate_setinfo("ups.model", "610 %s", rating);
73
84
if (!strcmp(abbr, "620")) {
74
85
dstate_setinfo("ups.mfr", "%s", "Sola Australia");
75
dstate_setinfo("ups.model", "Sola 620 %s", va);
86
dstate_setinfo("ups.model", "Sola 620 %s", rating);
79
90
if (!strcmp(abbr, "AX1")) {
80
91
dstate_setinfo("ups.mfr", "%s", "Best Power");
81
dstate_setinfo("ups.model", "Axxium Rackmount %s", va);
92
dstate_setinfo("ups.model", "Axxium Rackmount %s", rating);
85
96
dstate_setinfo("ups.mfr", "%s", "Unknown");
86
dstate_setinfo("ups.model", "Unknown %s (%s)", abbr, va);
97
dstate_setinfo("ups.model", "Unknown %s (%s)", abbr, rating);
88
99
printf("Unknown model detected - please report this ID: '%s'\n", abbr);
91
int instcmd(const char *cmdname, const char *extra)
102
static int instcmd(const char *cmdname, const char *extra)
93
104
if (!strcasecmp(cmdname, "test.battery.stop")) {
105
ser_send_pace(upsfd, UPSDELAY, "CT\r");
98
106
return STAT_INSTCMD_HANDLED;
101
109
if (!strcasecmp(cmdname, "test.battery.start")) {
110
ser_send_pace(upsfd, UPSDELAY, "T\r");
105
111
return STAT_INSTCMD_HANDLED;
109
115
return STAT_INSTCMD_UNKNOWN;
112
void upsdrv_initinfo(void)
114
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
115
dstate_addcmd("test.battery.start");
116
dstate_addcmd("test.battery.stop");
118
setmodel(modelname, va);
119
printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"),
120
dstate_getinfo("ups.model"), device_path);
122
upsh.new_instcmd = instcmd;
124
/* paranoia - cancel any shutdown that might already be running */
129
static void setup_serial(void)
133
if (tcgetattr(upsfd, &tio) == -1)
136
tio.c_iflag = IXON | IXOFF;
138
tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
143
#ifdef HAVE_CFSETISPEED
144
cfsetispeed(&tio, B2400);
145
cfsetospeed(&tio, B2400);
147
#error This system lacks cfsetispeed() and has no other means to set the speed
150
if (tcsetattr(upsfd, TCSANOW, &tio) == -1)
154
static void ups_sync(void)
159
printf("Syncing with UPS: ");
162
for (i = 0; i < MAXTRIES; i++) {
165
upssend("%s", "\rQ1\r");
172
ret = upsrecv(buf, sizeof(buf), ENDCHAR, "");
174
/* return once we get something that looks usable */
175
if ((ret > 0) && (buf[0] == '(')) {
181
fatalx("\nFailed - giving up...");
184
static int ups_on_line(void)
187
char temp[256], stat[32];
189
printf("Checking line status: ");
192
for (i = 0; i < MAXTRIES; i++) {
200
ret = upsrecv(temp, sizeof(temp), ENDCHAR, "");
202
/* Q1 must return 46 bytes starting with a ( */
203
if ((ret > 0) && (temp[0] == '(') && (strlen(temp) == 46)) {
205
sscanf(temp, "%*s %*s %*s %*s %*s %*s %*s %s", stat);
208
return 1; /* on line */
210
return 0; /* on battery */
214
upslogx(LOG_ERR, "Status read failed: assuming on battery");
216
return 0; /* on battery */
219
void upsdrv_shutdown(void)
221
printf("The UPS will shut down in approximately one minute.\n");
224
printf("The UPS will restart in about one minute.\n");
226
printf("The UPS will restart when power returns.\n");
228
upssend("%s", "S01R0001\r");
231
118
static int get_ident(char *buf, size_t bufsize)
235
printf("Identifying UPS: ");
123
ID = getval("ID"); /* user-supplied override from ups.conf */
126
upsdebugx(2, "NOTE: using user-supplied ID response");
127
snprintf(buf, bufsize, "%s", ID);
238
131
for (i = 0; i < MAXTRIES; i++) {
242
upssend("%s", "\r\rID\r");
250
ret = upsrecv(buf, bufsize, ENDCHAR, "");
132
ser_send_pace(upsfd, UPSDELAY, "\rID\r");
134
ret = ser_get_line(upsfd, buf, bufsize, ENDCHAR, "",
135
SER_WAIT_SEC, SER_WAIT_USEC);
138
upsdebugx(2, "get_ident: got [%s]", buf);
252
140
/* buf must start with ( and be in the range [25-27] */
253
141
if ((ret > 0) && (buf[0] != '(') && (strlen(buf) >= 25) &&
254
(strlen(buf) <= 27)) {
261
148
upslogx(LOG_INFO, "Giving up on hardware detection after %d tries",
307
static void pollfail(char *why)
311
/* ignore the first few since these UPSes tend to drop characters */
312
if (poll_failures == 3)
313
upslogx(LOG_ERR, why);
192
if ((!model) || (!rating))
193
fatalx("Didn't get a valid ident string");
195
bvs = getval("nombattvolt");
200
nomvolt = strtod(bvs, (char **) NULL);
206
dstate_setinfo("battery.voltage.nominal", "%2.1f", highvolt);
208
voltrange = highvolt - lowvolt;
210
model_set(model, rating);
213
static void ups_sync(void)
218
for (i = 0; i < MAXTRIES; i++) {
219
ser_send_pace(upsfd, UPSDELAY, "\rQ1\r");
221
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
222
SER_WAIT_SEC, SER_WAIT_USEC);
224
/* return once we get something that looks usable */
225
if ((ret > 0) && (buf[0] == '('))
231
fatalx("Unable to detect a Best/SOLA or Phoenix protocol UPS");
234
void upsdrv_initinfo(void)
239
printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"),
240
dstate_getinfo("ups.model"), device_path);
242
/* paranoia - cancel any shutdown that might already be running */
243
ser_send_pace(upsfd, UPSDELAY, "C\r");
245
upsh.instcmd = instcmd;
247
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
248
dstate_addcmd("test.battery.start");
249
dstate_addcmd("test.battery.stop");
252
static int ups_on_line(void)
255
char temp[256], pstat[32];
257
for (i = 0; i < MAXTRIES; i++) {
258
ser_send_pace(upsfd, UPSDELAY, "\rQ1\r");
260
ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, "",
261
SER_WAIT_SEC, SER_WAIT_USEC);
263
/* Q1 must return 46 bytes starting with a ( */
264
if ((ret > 0) && (temp[0] == '(') && (strlen(temp) == 46)) {
266
sscanf(temp, "%*s %*s %*s %*s %*s %*s %*s %s", pstat);
269
return 1; /* on line */
271
return 0; /* on battery */
277
upslogx(LOG_ERR, "Status read failed: assuming on battery");
279
return 0; /* on battery */
282
void upsdrv_shutdown(void)
284
printf("The UPS will shut down in approximately one minute.\n");
287
printf("The UPS will restart in about one minute.\n");
289
printf("The UPS will restart when power returns.\n");
291
ser_send_pace(upsfd, UPSDELAY, "S01R0001\r");
318
294
void upsdrv_updateinfo(void)
320
296
char involt[16], outvolt[16], loadpct[16], acfreq[16],
321
battvolt[16], upstemp[16], stat[16], buf[256];
297
battvolt[16], upstemp[16], pstat[16], buf[256];
326
/* this UPS needs a huge delay on queries, so chop up the updates */
328
/* half the time, send the Q1, the other half, read it */
331
upssend("%s", "\rQ1\r");
338
ret = upsrecv(buf, sizeof(buf), ENDCHAR, "");
340
if (strlen(buf) < 46) {
341
pollfail("Poll failed: short read from UPS");
346
if (strlen(buf) > 46) {
347
pollfail("Poll failed: oversized read from UPS");
301
ret = ser_send_pace(upsfd, UPSDELAY, "\rQ1\r");
304
ser_comm_fail("ser_send_pace failed");
309
/* these things need a long time to respond completely */
312
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
313
SER_WAIT_SEC, SER_WAIT_USEC);
322
ser_comm_fail("Poll failed: short read (got %d bytes)", ret);
328
ser_comm_fail("Poll failed: response too long (got %d bytes)",
348
330
dstate_datastale();
352
334
if (buf[0] != '(') {
353
pollfail("Poll failed: invalid start character");
335
ser_comm_fail("Poll failed: invalid start character (got %02x)",
354
337
dstate_datastale();
358
/* only say this if it got high enough to log a failure note */
359
if (poll_failures >= 3)
360
upslogx(LOG_NOTICE, "UPS poll succeeded");
364
343
sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", involt, outvolt,
365
loadpct, acfreq, battvolt, upstemp, stat);
344
loadpct, acfreq, battvolt, upstemp, pstat);
367
346
bvoltp = ((atof (battvolt) - lowvolt) / voltrange) * 100.0;