UPS: apcupsd clean sources
[tomato.git] / release / src / router / apcupsd / src / drivers / apcsmart / smarteeprom.c
blob2e3830baf01171f4ab656d88af9d410c24dffa24
1 /*
2 * apceeprom.c
4 * Do APC EEPROM changes.
5 */
7 /*
8 * Copyright (C) 2000-2004 Kern Sibbald
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General
12 * Public License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this program; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * MA 02111-1307, USA.
25 #include "apc.h"
26 #include "apcsmart.h"
28 static void change_ups_battery_date(UPSINFO *ups, const char *newdate);
29 static void change_ups_name(UPSINFO *ups, const char *newname);
30 static void change_extended(UPSINFO *ups);
31 static int change_ups_eeprom_item(UPSINFO *ups, const char *title, const char cmd,
32 const char *setting);
35 /*********************************************************************/
36 int apcsmart_ups_program_eeprom(UPSINFO *ups, int command, const char *data)
38 char setting[20];
40 setup_device(ups);
41 apcsmart_ups_get_capabilities(ups);
43 switch (command) {
44 case CI_BATTDAT: /* change battery date */
45 if (ups->UPS_Cap[CI_BATTDAT]) {
46 printf("Attempting to update UPS battery date ...\n");
47 change_ups_battery_date(ups, data);
48 } else {
49 printf("UPS battery date configuration not supported by this UPS.\n");
50 return 0;
52 break;
54 case CI_IDEN:
55 if (ups->UPS_Cap[CI_IDEN]) {
56 printf("Attempting to rename UPS ...\n");
57 change_ups_name(ups, data);
58 } else {
59 printf("UPS name configuration not supported by this UPS.\n");
60 return 0;
62 break;
64 /* SENSITIVITY */
65 case CI_SENS:
66 if (ups->UPS_Cap[CI_SENS]) {
67 asnprintf(setting, sizeof(setting), "%.1s", data);
68 change_ups_eeprom_item(ups, "sensitivity", ups->UPS_Cmd[CI_SENS], setting);
69 } else {
70 printf("UPS sensitivity configuration not supported by this UPS.\n");
71 return 0;
73 break;
75 /* ALARM_STATUS */
76 case CI_DALARM:
77 if (ups->UPS_Cap[CI_DALARM]) {
78 asnprintf(setting, sizeof(setting), "%.1s", data);
79 change_ups_eeprom_item(ups, "alarm status", ups->UPS_Cmd[CI_DALARM],
80 setting);
81 } else {
82 printf("UPS alarm status configuration not supported by this UPS.\n");
83 return 0;
85 break;
87 /* LOWBATT_SHUTDOWN_LEVEL */
88 case CI_DLBATT:
89 if (ups->UPS_Cap[CI_DLBATT]) {
90 asnprintf(setting, sizeof(setting), "%02d", (int)atoi(data));
91 change_ups_eeprom_item(ups, "low battery warning delay",
92 ups->UPS_Cmd[CI_DLBATT], setting);
93 } else {
94 printf(
95 "UPS low battery warning configuration not supported by this UPS.\n");
96 return 0;
98 break;
100 /* WAKEUP_DELAY */
101 case CI_DWAKE:
102 if (ups->UPS_Cap[CI_DWAKE]) {
103 asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data));
104 change_ups_eeprom_item(ups, "wakeup delay", ups->UPS_Cmd[CI_DWAKE],
105 setting);
106 } else {
107 printf("UPS wakeup delay configuration not supported by this UPS.\n");
108 return 0;
110 break;
113 /* SLEEP_DELAY */
114 case CI_DSHUTD:
115 if (ups->UPS_Cap[CI_DSHUTD]) {
116 asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data));
117 change_ups_eeprom_item(ups, "shutdown delay", ups->UPS_Cmd[CI_DSHUTD],
118 setting);
119 } else {
120 printf("UPS shutdown delay configuration not supported by this UPS.\n");
121 return 0;
123 break;
125 /* LOW_TRANSFER_LEVEL */
126 case CI_LTRANS:
127 if (ups->UPS_Cap[CI_LTRANS]) {
128 asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data));
129 change_ups_eeprom_item(ups, "lower transfer voltage",
130 ups->UPS_Cmd[CI_LTRANS], setting);
131 } else {
132 printf(
133 "UPS low transfer voltage configuration not supported by this UPS.\n");
134 return 0;
136 break;
138 /* HIGH_TRANSFER_LEVEL */
139 case CI_HTRANS:
140 if (ups->UPS_Cap[CI_HTRANS]) {
141 asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data));
142 change_ups_eeprom_item(ups, "high transfer voltage",
143 ups->UPS_Cmd[CI_HTRANS], setting);
144 } else {
145 printf(
146 "UPS high transfer voltage configuration not supported by this UPS.\n");
147 return 0;
149 break;
151 /* UPS_BATT_CAP_RETURN */
152 case CI_RETPCT:
153 if (ups->UPS_Cap[CI_RETPCT]) {
154 asnprintf(setting, sizeof(setting), "%02d", (int)atoi(data));
155 change_ups_eeprom_item(ups, "return threshold percent",
156 ups->UPS_Cmd[CI_RETPCT], setting);
157 } else {
158 printf(
159 "UPS return threshold configuration not supported by this UPS.\n");
160 return 0;
162 break;
164 /* UPS_SELFTEST */
165 case CI_STESTI:
166 if (ups->UPS_Cap[CI_STESTI]) {
167 asnprintf(setting, sizeof(setting), "%.3s", data);
168 /* Make sure "ON" is 3 characters */
169 if (setting[2] == 0) {
170 setting[2] = ' ';
171 setting[3] = 0;
173 change_ups_eeprom_item(ups, "self test interval", ups->UPS_Cmd[CI_STESTI],
174 setting);
175 } else {
176 printf(
177 "UPS self test interval configuration not supported by this UPS.\n");
178 return 0;
180 break;
182 /* OUTPUT_VOLTAGE */
183 case CI_NOMOUTV:
184 if (ups->UPS_Cap[CI_NOMOUTV]) {
185 asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data));
186 change_ups_eeprom_item(ups, "output voltage on batteries",
187 ups->UPS_Cmd[CI_NOMOUTV], setting);
188 } else {
189 printf(
190 "UPS output voltage on batteries configuration not supported by this UPS.\n");
191 return 0;
193 break;
196 case -1: /* old style from .conf file */
198 printf("Attempting to configure UPS ...\n");
199 change_extended(ups); /* set new values in UPS */
201 printf("\nReading updated UPS configuration ...\n\n");
202 device_read_volatile_data(ups);
203 device_read_static_data(ups);
205 /* Print report of status */
206 output_status(ups, 0, stat_open, stat_print, stat_close);
207 break;
209 default:
210 printf("Ignoring unknown config request command=%d\n", command);
211 return 0;
212 break;
215 return 1;
218 /*********************************************************************/
219 static void change_ups_name(UPSINFO *ups, const char *newname)
221 char *n;
222 char response[32];
223 char name[10];
224 char a = ups->UPS_Cmd[CI_CYCLE_EPROM];
225 char c = ups->UPS_Cmd[CI_IDEN];
226 int i;
227 int j = strlen(newname);
229 name[0] = '\0';
231 if (j == 0) {
232 fprintf(stderr, "Error, new name of zero length.\n");
233 return;
234 } else if (j > 8) {
235 j = 8; /* maximum size */
238 strncpy(name, newname, 9);
240 /* blank fill to 8 chars */
241 while (j < 8) {
242 name[j] = ' ';
243 j++;
246 /* Ask for name */
247 write(ups->fd, &c, 1); /* c = 'c' */
248 getline(response, sizeof(response), ups);
249 fprintf(stderr, "The old UPS name is: %s\n", response);
251 /* Tell UPS we will change name */
252 write(ups->fd, &a, 1); /* a = '-' */
253 sleep(1);
255 n = name;
256 for (i = 0; i < 8; i++) {
257 write(ups->fd, n++, 1);
258 sleep(1);
261 /* Expect OK after successful name change */
262 *response = 0;
263 getline(response, sizeof(response), ups);
264 if (strcmp(response, "OK") != 0) {
265 fprintf(stderr, "\nError changing UPS name\n");
268 ups->upsname[0] = '\0';
269 smart_poll(ups->UPS_Cmd[CI_IDEN], ups);
270 astrncpy(ups->upsname, smart_poll(ups->UPS_Cmd[CI_IDEN], ups),
271 sizeof(ups->upsname));
273 fprintf(stderr, "The new UPS name is: %s\n", ups->upsname);
277 * Update date battery replaced
279 static void change_ups_battery_date(UPSINFO *ups, const char *newdate)
281 char *n;
282 char response[32];
283 char battdat[9];
284 char a = ups->UPS_Cmd[CI_CYCLE_EPROM];
285 char c = ups->UPS_Cmd[CI_BATTDAT];
286 int i;
287 int j = strlen(newdate);
289 battdat[0] = '\0';
291 if (j != 8) {
292 fprintf(stderr, "Error, new battery date must be 8 characters long.\n");
293 return;
296 astrncpy(battdat, newdate, sizeof(battdat));
298 /* Ask for battdat */
299 write(ups->fd, &c, 1); /* c = 'x' */
300 getline(response, sizeof(response), ups);
301 fprintf(stderr, "The old UPS battery date is: %s\n", response);
303 /* Tell UPS we will change battdat */
304 write(ups->fd, &a, 1); /* a = '-' */
305 sleep(1);
307 n = battdat;
308 for (i = 0; i < 8; i++) {
309 write(ups->fd, n++, 1);
310 sleep(1);
313 /* Expect OK after successful battdat change */
314 *response = 0;
315 getline(response, sizeof(response), ups);
316 if (strcmp(response, "OK") != 0) {
317 fprintf(stderr, "\nError changing UPS battery date\n");
320 ups->battdat[0] = '\0';
321 smart_poll(ups->UPS_Cmd[CI_BATTDAT], ups);
322 astrncpy(ups->battdat, smart_poll(ups->UPS_Cmd[CI_BATTDAT], ups),
323 sizeof(ups->battdat));
325 fprintf(stderr, "The new UPS battery date is: %s\n", ups->battdat);
328 /*********************************************************************/
329 static int change_ups_eeprom_item(UPSINFO *ups, const char *title, const char cmd,
330 const char *setting)
332 char response[32];
333 char response1[32];
334 char oldvalue[32];
335 char lastvalue[32];
336 char allvalues[256];
337 char a = ups->UPS_Cmd[CI_CYCLE_EPROM];
338 int i;
340 /* Ask for old value */
341 write(ups->fd, &cmd, 1);
342 if (getline(oldvalue, sizeof(oldvalue), ups) == FAILURE) {
343 fprintf(stderr, "Could not get old value of %s.\n", title);
344 return FAILURE;
347 if (strcmp(oldvalue, setting) == 0) {
348 fprintf(stderr, "The UPS %s remains unchanged as: %s\n", title, oldvalue);
349 return SUCCESS;
352 fprintf(stderr, "The old UPS %s is: %s\n", title, oldvalue);
353 astrncpy(allvalues, oldvalue, sizeof(allvalues));
354 astrncat(allvalues, " ", sizeof(allvalues));
355 astrncpy(lastvalue, oldvalue, sizeof(lastvalue));
357 /* Try a second time to ensure that it is a stable value */
358 write(ups->fd, &cmd, 1);
359 *response = 0;
360 getline(response, sizeof(response), ups);
361 if (strcmp(oldvalue, response) != 0) {
362 fprintf(stderr, "\nEEPROM value of %s is not stable\n", title);
363 return FAILURE;
367 * Just before entering this loop, the last command sent
368 * to the UPS MUST be to query the old value.
370 for (i = 0; i < 10; i++) {
371 write(ups->fd, &cmd, 1);
372 getline(response1, sizeof(response1), ups);
374 /* Tell UPS to cycle to next value */
375 write(ups->fd, &a, 1); /* a = '-' */
377 /* Expect OK after successful change */
378 *response = 0;
379 getline(response, sizeof(response), ups);
380 if (strcmp(response, "OK") != 0) {
381 fprintf(stderr, "\nError changing UPS %s\n", title);
382 fprintf(stderr, "Got %s instead of OK\n\n", response);
383 sleep(10);
384 return FAILURE;
387 /* get cycled value */
388 write(ups->fd, &cmd, 1);
389 getline(response1, sizeof(response1), ups);
391 /* get cycled value again */
392 write(ups->fd, &cmd, 1);
393 if (getline(response, sizeof(response), ups) == FAILURE ||
394 strcmp(response1, response) != 0) {
395 fprintf(stderr, "Error cycling values.\n");
396 getline(response, sizeof(response), ups); /* eat any garbage */
397 return FAILURE;
399 if (strcmp(setting, response) == 0) {
400 fprintf(stderr, "The new UPS %s is: %s\n", title, response);
401 sleep(10); /* allow things to settle down */
402 return SUCCESS;
406 * Check if we cycled back to the same value, but permit
407 * a duplicate because the L for sensitivy appears
408 * twice in a row, i.e. H M L L.
410 if (strcmp(oldvalue, response) == 0 && i > 0)
411 break;
412 if (strcmp(lastvalue, response) != 0) {
413 astrncat(allvalues, response, sizeof(allvalues));
414 astrncat(allvalues, " ", sizeof(allvalues));
415 astrncpy(lastvalue, response, sizeof(lastvalue));
417 sleep(5); /* don't cycle too fast */
420 fprintf(stderr, "Unable to change %s to: %s\n", title, setting);
421 fprintf(stderr, "Permitted values are: %s\n", allvalues);
422 getline(response, sizeof(response), ups); /* eat any garbage */
424 return FAILURE;
429 * Set new values in EEPROM memmory. Change the UPS EEPROM.
431 static void change_extended(UPSINFO *ups)
433 char setting[20];
435 apcsmart_ups_get_capabilities(ups);
438 * Note, a value of -1 in the variable at the beginning
439 * means that the user did not put a configuration directive
440 * in /etc/apcupsd/apcupsd.conf. Consequently, if no value
441 * was given, we won't attept to change it.
444 /* SENSITIVITY */
445 if (ups->UPS_Cap[CI_SENS] && strcmp(ups->sensitivity, "-1") != 0) {
446 asnprintf(setting, sizeof(setting), "%.1s", ups->sensitivity);
447 change_ups_eeprom_item(ups, "sensitivity", ups->UPS_Cmd[CI_SENS], setting);
450 /* WAKEUP_DELAY */
451 if (ups->UPS_Cap[CI_DWAKE] && ups->dwake != -1) {
452 asnprintf(setting, sizeof(setting), "%03d", (int)ups->dwake);
453 change_ups_eeprom_item(ups, "wakeup delay", ups->UPS_Cmd[CI_DWAKE], setting);
456 /* SLEEP_DELAY */
457 if (ups->UPS_Cap[CI_DSHUTD] && ups->dshutd != -1) {
458 asnprintf(setting, sizeof(setting), "%03d", (int)ups->dshutd);
459 change_ups_eeprom_item(ups, "shutdown delay", ups->UPS_Cmd[CI_DSHUTD],
460 setting);
463 /* LOW_TRANSFER_LEVEL */
464 if (ups->UPS_Cap[CI_LTRANS] && ups->lotrans != -1) {
465 asnprintf(setting, sizeof(setting), "%03d", (int)ups->lotrans);
466 change_ups_eeprom_item(ups, "lower transfer voltage",
467 ups->UPS_Cmd[CI_LTRANS], setting);
470 /* HIGH_TRANSFER_LEVEL */
471 if (ups->UPS_Cap[CI_HTRANS] && ups->hitrans != -1) {
472 asnprintf(setting, sizeof(setting), "%03d", (int)ups->hitrans);
473 change_ups_eeprom_item(ups, "upper transfer voltage",
474 ups->UPS_Cmd[CI_HTRANS], setting);
477 /* UPS_BATT_CAP_RETURN */
478 if (ups->UPS_Cap[CI_RETPCT] && ups->rtnpct != -1) {
479 asnprintf(setting, sizeof(setting), "%02d", (int)ups->rtnpct);
480 change_ups_eeprom_item(ups, "return threshold percent",
481 ups->UPS_Cmd[CI_RETPCT], setting);
484 /* ALARM_STATUS */
485 if (ups->UPS_Cap[CI_DALARM] && strcmp(ups->beepstate, "-1") != 0) {
486 asnprintf(setting, sizeof(setting), "%.1s", ups->beepstate);
487 change_ups_eeprom_item(ups, "alarm delay", ups->UPS_Cmd[CI_DALARM], setting);
490 /* LOWBATT_SHUTDOWN_LEVEL */
491 if (ups->UPS_Cap[CI_DLBATT] && ups->dlowbatt != -1) {
492 asnprintf(setting, sizeof(setting), "%02d", (int)ups->dlowbatt);
493 change_ups_eeprom_item(ups, "low battery warning delay",
494 ups->UPS_Cmd[CI_DLBATT], setting);
497 /* UPS_SELFTEST */
498 if (ups->UPS_Cap[CI_STESTI] && strcmp(ups->selftest, "-1") != 0) {
499 asnprintf(setting, sizeof(setting), "%.3s", ups->selftest);
500 /* Make sure "ON" is 3 characters */
501 if (setting[2] == 0) {
502 setting[2] = ' ';
503 setting[3] = 0;
505 change_ups_eeprom_item(
506 ups, "self test interval", ups->UPS_Cmd[CI_STESTI], setting);
509 /* OUTPUT_VOLTAGE */
510 if (ups->UPS_Cap[CI_NOMOUTV] && ups->NomOutputVoltage != -1) {
511 asnprintf(setting, sizeof(setting), "%03d", (int)ups->NomOutputVoltage);
512 change_ups_eeprom_item(ups, "output voltage on batteries",
513 ups->UPS_Cmd[CI_NOMOUTV], setting);