UPS: apcupsd clean sources
[tomato.git] / release / src / router / apcupsd / src / apctest.c
blob8434ccde2f2804362e1af5e438699f1c7eeabfb6
1 /*
2 * apctest.c
4 * A cable tester program for apcupsd.
6 * Hacked from apcupsd.c by Kern Sibbald, Sept 2000
7 */
9 /*
10 * Copyright (C) 2000-2004 Kern Sibbald
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of version 2 of the GNU General
14 * Public License as published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public
22 * License along with this program; if not, write to the Free
23 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 * MA 02111-1307, USA.
27 #include "apc.h"
28 #include <termios.h>
30 UPSINFO *core_ups;
31 UPSINFO *ups;
33 int le_bit = TIOCM_LE;
34 int st_bit = TIOCM_ST;
35 int sr_bit = TIOCM_SR;
36 int dtr_bit = TIOCM_DTR;
37 int rts_bit = TIOCM_RTS;
38 int cts_bit = TIOCM_CTS;
39 int cd_bit = TIOCM_CD;
40 int rng_bit = TIOCM_RNG;
41 int dsr_bit = TIOCM_DSR;
43 struct termios oldtio;
44 struct termios newtio;
46 /* Forward referenced functions */
47 static void do_dumb_testing(void);
48 static void test1(void);
49 static void test2(void);
50 static void test3(void);
51 static void test4(void);
52 static void test5(void);
53 static void test6(void);
54 static void guess(void);
56 static void do_smart_testing(void);
58 #ifdef HAVE_APCSMART_DRIVER
59 static void smart_test1(void);
60 static void smart_calibration(void);
61 static void monitor_calibration_progress(int monitor);
62 static void terminate_calibration(int ask);
63 static void program_smart_eeprom(void);
64 static void print_eeprom_values(UPSINFO *ups);
65 static void smart_ttymode(void);
66 static void parse_eeprom_cmds(char *eprom, char locale);
67 int apcsmart_ups_program_eeprom(UPSINFO *ups, int command, const char *data);
68 static void print_valid_eeprom_values(UPSINFO *ups);
69 #endif
71 static void do_usb_testing(void);
73 #ifdef HAVE_USB_DRIVER
75 /* USB driver functions */
76 #include "drivers/usb/usb.h"
78 /* Our own test functions */
79 static void usb_kill_power_test(void);
80 static void usb_get_self_test_result(void);
81 static void usb_run_self_test(void);
82 static int usb_get_battery_date(void);
83 static void usb_set_battery_date(void);
84 static void usb_get_manf_date(void);
85 static void usb_set_alarm(void);
86 static void usb_set_sens(void);
87 static void usb_set_xferv(int lowhigh);
88 static void usb_calibration();
89 static void usb_test_alarm(void);
90 static int usb_get_self_test_interval(void);
91 static void usb_set_self_test_interval(void);
92 #endif
94 static void strip_trailing_junk(char *cmd);
95 static char *get_cmd(const char *prompt);
96 static int write_file(char *buf);
99 /* Static variables */
100 static int normal, no_cable, no_power, low_batt;
101 static int test1_done = 0;
102 static int test2_done = 0;
103 static int test3_done = 0;
104 static int test4_done = 0;
105 static int test5_done = 0;
108 /* Print a message, and also write it to an output file */
109 static void pmsg(const char *fmt, ...)
111 char buf[3000];
112 va_list arg_ptr;
114 va_start(arg_ptr, fmt);
115 avsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
116 va_end(arg_ptr);
117 printf("%s", buf);
118 fflush(stdout);
119 write_file(buf);
122 /* Write output into "log" file */
123 static int write_file(char *buf)
125 static int out_fd = -1;
127 if (out_fd == -1) {
128 out_fd = open("apctest.output", O_WRONLY | O_CREAT | O_APPEND, 0644);
129 if (out_fd < 0) {
130 printf("Could not create apctest.output: %s\n", strerror(errno));
131 return -1;
134 return write(out_fd, buf, strlen(buf));
137 /* Print out current time */
138 static void ptime(void)
140 char dt[MAXSTRING];
141 time_t now = time(NULL);
143 strftime(dt, MAXSTRING, "%Y-%m-%d %T ", localtime(&now));
144 pmsg(dt);
149 * The terminate function; trapping signals allows apctest
150 * to exit and cleanly close logfiles, and reset the tty back
151 * to its original settings. You may want to add this
152 * to all configurations. Of course, the file descriptors
153 * must be global for this to work, I also set them to
154 * NULL initially to allow terminate to determine whether
155 * it should close them.
157 void apctest_terminate(int sig)
159 if (sig != 0) {
160 ptime();
161 pmsg("apctest exiting, signal %u\n", sig);
164 clear_files();
166 device_close(ups);
168 delete_lockfile(ups);
170 clean_threads();
172 closelog();
173 destroy_ups(ups);
174 _exit(0);
177 void apctest_error_cleanup(UPSINFO *ups)
179 device_close(ups);
180 delete_lockfile(ups);
181 clean_threads();
182 pmsg("apctest error termination completed\n");
183 closelog();
184 destroy_ups(ups);
185 exit(1);
189 * Subroutine error_out prints FATAL ERROR with file,
190 * line number, and the error message then cleans up
191 * and exits. It is normally called from the Error_abort
192 * define, which inserts the file and line number.
194 void apctest_error_out(const char *file, int line, const char *fmt, ...)
196 char buf[256];
197 va_list arg_ptr;
198 int i;
200 asnprintf(buf, sizeof(buf),
201 "apctest FATAL ERROR in %s at line %d\n", file, line);
202 i = strlen(buf);
204 va_start(arg_ptr, fmt);
205 avsnprintf((char *)&buf[i], sizeof(buf) - i, (char *)fmt, arg_ptr);
206 va_end(arg_ptr);
208 pmsg(buf);
210 apctest_error_cleanup(core_ups); /* finish the work */
214 * Subroutine error_exit simply prints the supplied error
215 * message, cleans up, and exits.
217 void apctest_error_exit(const char *fmt, ...)
219 char buf[256];
220 va_list arg_ptr;
222 va_start(arg_ptr, fmt);
223 avsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
224 va_end(arg_ptr);
226 pmsg(buf);
228 apctest_error_cleanup(core_ups); /* finish the work */
232 /* Main program */
234 /* This application must be linked as console app. */
236 int main(int argc, char *argv[])
238 /* Set specific error_* handlers. */
239 error_out = apctest_error_out;
240 error_exit = apctest_error_exit;
243 * Default config file. If we set a config file in startup switches, it
244 * will be re-filled by parse_options()
246 cfgfile = APCCONF;
248 ups = new_ups(); /* get new ups */
249 if (!ups)
250 Error_abort1("%s: init_ipc failed.\n", argv[0]);
252 init_ups_struct(ups);
253 core_ups = ups; /* this is our core ups structure */
255 /* parse_options is self messaging on errors, so we need only to exit() */
256 if (parse_options(argc, argv))
257 exit(1);
259 pmsg("\n\n");
260 ptime();
261 pmsg("apctest " APCUPSD_RELEASE " (" ADATE ") " APCUPSD_HOST "\n");
263 pmsg("Checking configuration ...\n");
264 check_for_config(ups, cfgfile);
266 attach_driver(ups);
267 if (ups->driver == NULL)
268 Error_abort0("apctest cannot continue without a valid driver.\n");
270 pmsg("Attached to driver: %s\n", ups->driver->driver_name);
272 ups->start_time = time(NULL);
274 /* Print configuration */
275 pmsg("sharenet.type = %s\n", ups->sharenet.long_name);
276 pmsg("cable.type = %s\n", ups->cable.long_name);
277 pmsg("mode.type = %s\n", ups->mode.long_name);
279 delete_lockfile(ups);
281 pmsg("Setting up the port ...\n");
282 setup_device(ups);
284 if (hibernate_ups) {
285 pmsg("apctest: bad option, I cannot do a killpower\n");
286 apctest_terminate(0);
289 init_signals(apctest_terminate);
291 pmsg("Doing prep_device() ...\n");
292 prep_device(ups);
295 * This isn't a documented option but can be used
296 * for testing dumb mode on a SmartUPS if you have
297 * the proper cable.
299 if (dumb_mode_test) {
300 #ifdef HAVE_APCSMART_DRIVER
301 char ans[20];
303 write(ups->fd, "R", 1); /* enter dumb mode */
304 *ans = 0;
305 getline(ans, sizeof(ans), ups);
306 pmsg("Going dumb: %s\n", ans);
307 #else
308 pmsg("apcsmart not compiled: dumb mode test unavailable\n");
309 #endif
312 switch (ups->mode.type)
314 case USB_UPS:
315 pmsg("\nYou are using a USB cable type, so I'm entering USB test mode\n");
316 do_usb_testing();
317 break;
318 case APCSMART_UPS:
319 pmsg("\nYou are using a SMART cable type, so I'm entering SMART test mode\n");
320 do_smart_testing();
321 break;
322 case DUMB_UPS:
323 pmsg("\nYou are using a DUMB cable type, so I'm entering DUMB test mode\n");
324 do_dumb_testing();
325 break;
326 default:
327 pmsg("Testing not yet implemented for this UPSTYPE.\n");
329 apctest_terminate(0);
330 return -1; /* to keep compiler happy */
333 static void print_bits(int bits)
335 char buf[200];
337 asnprintf(buf, sizeof(buf), "IOCTL GET: %x ", bits);
339 if (bits & le_bit)
340 astrncat(buf, "LE ", sizeof(buf));
341 if (bits & st_bit)
342 astrncat(buf, "ST ", sizeof(buf));
343 if (bits & sr_bit)
344 astrncat(buf, "SR ", sizeof(buf));
345 if (bits & dtr_bit)
346 astrncat(buf, "DTR ", sizeof(buf));
347 if (bits & rts_bit)
348 astrncat(buf, "RTS ", sizeof(buf));
349 if (bits & cts_bit)
350 astrncat(buf, "CTS ", sizeof(buf));
351 if (bits & cd_bit)
352 astrncat(buf, "CD ", sizeof(buf));
353 if (bits & rng_bit)
354 astrncat(buf, "RNG ", sizeof(buf));
355 if (bits & dsr_bit)
356 astrncat(buf, "DSR ", sizeof(buf));
358 astrncat(buf, "\n", sizeof(buf));
360 pmsg(buf);
363 static void do_dumb_testing(void)
365 int quit = FALSE;
366 char *cmd;
368 pmsg("Hello, this is the apcupsd Cable Test program.\n\n"
369 "We are beginning testing for dumb UPSes, which\n"
370 "use signaling rather than commands.\n"
371 "Most tests enter a loop polling every second for 10 seconds.\n");
373 while (!quit) {
374 pmsg("\n"
375 "1) Test 1 - normal mode\n"
376 "2) Test 2 - no cable\n"
377 "3) Test 3 - no power\n"
378 "4) Test 4 - low battery (requires test 3 first)\n"
379 "5) Test 5 - battery exhausted\n"
380 "6) Test 6 - kill UPS power\n"
381 "7) Test 7 - run tests 1 through 5\n"
382 "8) Guess which is the appropriate cable\n"
383 "Q) Quit\n\n");
385 cmd = get_cmd("Select test number: ");
387 if (cmd) {
388 int item = atoi(cmd);
390 switch (item) {
391 case 1:
392 test1();
393 break;
394 case 2:
395 test2();
396 break;
397 case 3:
398 test3();
399 break;
400 case 4:
401 test4();
402 break;
403 case 5:
404 test5();
405 break;
406 case 6:
407 test6();
408 break;
409 case 7:
410 test1();
411 test2();
412 test3();
413 test4();
414 test5();
415 break;
416 case 8:
417 guess();
418 break;
419 default:
420 if (tolower(*cmd) == 'q')
421 quit = TRUE;
422 else
423 pmsg("Illegal response. Please enter 1-8,Q\n");
424 break;
426 } else {
427 pmsg("Illegal response. Please enter 1-8,Q\n");
431 ptime();
432 pmsg("End apctest.\n");
436 * Poll 10 times once per second and report any
437 * change in serial port bits.
439 static int test_bits(int inbits)
441 int i, nbits;
442 int bits = inbits;
444 for (i = 0; i < 10; i++) {
445 if (ioctl(ups->fd, TIOCMGET, &nbits) < 0) {
446 pmsg("ioctl error, big problem: %s\n", strerror(errno));
447 return 0;
450 if (i == 0 || nbits != bits) {
451 ptime();
452 print_bits(nbits);
453 bits = nbits;
456 sleep(1);
459 return bits;
462 static void test1(void)
464 pmsg("\nFor the first test, everything should be normal.\n"
465 "The UPS should be plugged in to the power, and the serial cable\n"
466 "should be connected to the computer.\n\n"
467 "Please enter any character when ready to continue: ");
468 fgetc(stdin);
469 pmsg("\n");
471 normal = test_bits(0);
473 ptime();
474 pmsg("Test 1: normal condition, completed.\n");
475 test1_done = TRUE;
478 static void test2(void)
480 pmsg("\nFor the second test, the UPS should be plugged in to the power, \n"
481 "but the serial port should be DISCONNECTED from the computer.\n\n"
482 "Please enter any character when ready to continue: ");
483 fgetc(stdin);
484 pmsg("\n");
486 no_cable = test_bits(0);
488 ptime();
489 pmsg("Test 2: no cable, completed. \n");
490 test2_done = TRUE;
493 static void test3(void)
495 pmsg("\nFor the third test, the serial cable should be plugged\n"
496 "back into the UPS, but the AC power plug to the UPS should be DISCONNECTED.\n\n"
497 "Please enter any character when ready to continue: ");
498 fgetc(stdin);
499 pmsg("\n");
501 no_power = test_bits(0);
503 ptime();
504 pmsg("Test 3: no power, completed.\n");
505 test3_done = TRUE;
508 static void test4(void)
510 int i, bits;
512 if (!test3_done) {
513 pmsg("We need the output of test 3 to run this test.\n"
514 "Please run test 3 first then this test.\n");
515 return;
518 pmsg("\nThe fourth test is the same as the third test:\n"
519 "the serial cable should be plugged in to the UPS, but the AC power\n"
520 "plug to the UPS should be DISCONNECTED. In addition, you should\n"
521 "continue this test until the batteries are exhausted.\n"
522 "If apctest detects a state change, it will stop\n"
523 "the test. If not, hit control-C to stop the program\n\n"
524 "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n"
525 "Please enter any character when ready to continue: ");
526 fgetc(stdin);
527 pmsg("\n");
529 low_batt = no_power;
531 ptime();
532 pmsg("Start test 4: ");
533 pmsg("\n");
535 /* Spin until we get a state change */
536 for (i = 0;; i++) {
537 if (ioctl(ups->fd, TIOCMGET, &bits) < 0) {
538 pmsg("ioctl error, big problem: %s\n", strerror(errno));
539 return;
542 if (bits != low_batt) {
543 ptime();
544 print_bits(bits);
545 low_batt = bits;
546 break;
547 } else if (i == 0) {
548 ptime();
549 print_bits(bits);
552 sleep(1);
555 ptime();
556 pmsg("Test 4: low battery, completed.\n");
557 test4_done = TRUE;
560 static void test5(void)
562 int i, bits, last_bits = 0;
564 pmsg("\nThe fifth test is the same as the third test:\n"
565 "the serial cable should be plugged in to the UPS, but the AC power\n"
566 "plug to the UPS should be DISCONNECTED. In addition, you should\n"
567 "continue this test until the batteries are exhausted.\n"
568 "If apctest detects a state change, contrary to test 4, it\n"
569 "will not stop. The idea is to see ANY changed bits just up to\n"
570 "the very moment that the UPS powers down.\n\n"
571 "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n"
572 "Please enter any character when ready to continue: ");
573 fgetc(stdin);
574 pmsg("\n");
576 pmsg("Start test 5:\n");
578 /* Spin until we get a state change */
579 for (i = 0;; i++) {
580 if (ioctl(ups->fd, TIOCMGET, &bits) < 0) {
581 pmsg("ioctl error, big problem: %s\n", strerror(errno));
582 return;
585 if (i == 60)
586 i = 0; /* force print once a minute */
588 if (i == 0 || bits != last_bits) {
589 ptime();
590 print_bits(bits);
591 last_bits = bits;
594 sleep(1);
597 /* Should never get here */
598 /* NOTREACHED */
599 ptime();
600 pmsg("Test 5: battery exhausted, completed.\n");
601 test5_done = TRUE;
604 static void test6(void)
606 int bits;
608 pmsg("\nThis test will attempt to power down the UPS.\n"
609 "The serial cable should be plugged in to the UPS, but the\n"
610 "AC power plug to the UPS should be DISCONNECTED.\n\n"
611 "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n"
612 "Please enter any character when ready to continue: ");
613 fgetc(stdin);
614 pmsg("\n");
616 if (ioctl(ups->fd, TIOCMGET, &bits) < 0) {
617 pmsg("ioctl error, big problem: %s\n", strerror(errno));
618 return;
621 ptime();
622 print_bits(bits);
623 make_file(ups, ups->pwrfailpath);
624 initiate_hibernate(ups);
625 unlink(ups->pwrfailpath);
626 ptime();
628 pmsg("returned from kill_power function.\n");
630 if (ioctl(ups->fd, TIOCMGET, &bits) < 0) {
631 pmsg("ioctl error, big problem: %s\n", strerror(errno));
632 return;
635 ptime();
636 print_bits(bits);
640 * Make a wild guess at the cable type
642 * If I had more data on each of the cable types, this could
643 * be much improved.
645 static void guess(void)
647 int found = 0;
649 if (!(test1_done && test3_done)) {
650 pmsg("Test 1 and test 3 must be performed before I can make a guess.\n");
651 return;
653 if (!(normal & (cd_bit | cts_bit)) && (no_power & cd_bit) && (low_batt & cts_bit)) {
654 pmsg("This looks like a CUSTOM_SIMPLE cable\n");
655 found = 1;
658 if (!(normal & (cd_bit | cts_bit)) && (no_power & cts_bit) && (low_batt & cd_bit)) {
659 pmsg("This looks like a 940-0020A\n");
660 found = 1;
663 if (!(normal & (cd_bit | sr_bit)) && (no_power & cd_bit) && (low_batt & sr_bit)) {
664 pmsg("This looks like a 940-0023A cable\n");
665 found = 1;
668 if (!(normal & (rng_bit | cd_bit)) && (no_power & rng_bit) && (low_batt & cd_bit)) {
669 pmsg("This looks like a 940-0095A cable\n");
670 found = 1;
673 if (!found) {
674 pmsg("Hmmm. I don't quite know what you have. Sorry.\n");
678 static void do_smart_testing(void)
680 #ifdef HAVE_APCSMART_DRIVER
681 char *cmd;
682 int quit = FALSE;
684 pmsg("Hello, this is the apcupsd Cable Test program.\n"
685 "This part of apctest is for testing Smart UPSes.\n"
686 "Please select the function you want to perform.\n");
688 while (!quit) {
689 pmsg("\n"
690 "1) Query the UPS for all known values\n"
691 "2) Perform a Battery Runtime Calibration\n"
692 "3) Abort Battery Calibration\n"
693 "4) Monitor Battery Calibration progress\n"
694 "5) Program EEPROM\n"
695 "6) Enter TTY mode communicating with UPS\n"
696 "Q) Quit\n\n");
698 cmd = get_cmd("Select function number: ");
699 if (cmd) {
700 int item = atoi(cmd);
702 switch (item) {
703 case 1:
704 smart_test1();
705 break;
706 case 2:
707 smart_calibration();
708 break;
709 case 3:
710 terminate_calibration(1);
711 break;
712 case 4:
713 monitor_calibration_progress(0);
714 break;
715 case 5:
716 program_smart_eeprom();
717 break;
718 case 6:
719 smart_ttymode();
720 break;
721 default:
722 if (tolower(*cmd) == 'q')
723 quit = TRUE;
724 else
725 pmsg("Illegal response. Please enter 1-6,Q\n");
726 break;
727 break;
729 } else {
730 pmsg("Illegal response. Please enter 1-6,Q\n");
733 ptime();
734 pmsg("End apctest.\n");
735 #else
736 pmsg("APC Smart Driver not configured.\n");
737 #endif
740 #ifdef HAVE_APCSMART_DRIVER
741 static void smart_ttymode(void)
743 #ifdef HAVE_MINGW
744 // This is crap. Windows has no sane way (that I can find) to watch two
745 // fds for activity from a single thread without involving the overly
746 // complex "overlapped" io junk. So we will resort to polling.
748 // Save any existing timeouts on the UPS fd
749 HANDLE hnd = (HANDLE)_get_osfhandle(ups->fd);
750 COMMTIMEOUTS orig_ups_ct;
751 GetCommTimeouts(hnd, &orig_ups_ct);
753 // Reset UPS fd timeout to 50 msec
754 COMMTIMEOUTS ct;
755 ct.ReadIntervalTimeout = MAXDWORD;
756 ct.ReadTotalTimeoutMultiplier = 0;
757 ct.ReadTotalTimeoutConstant = 50;
758 ct.WriteTotalTimeoutMultiplier = 0;
759 ct.WriteTotalTimeoutConstant = 0;
760 SetCommTimeouts(hnd, &ct);
762 pmsg("Enter an ESC character (or ctl-[) to exit.\n\n");
764 char ch;
765 while (1)
767 // Waits up to 50 msec for a char from the UPS
768 if (read(ups->fd, &ch, 1) == 1)
769 putch(ch);
771 // Check if keyboard key was hit and read it (only Windows would
772 // have a function dedicated to checking if a key has been pressed!)
773 if (kbhit())
775 ch = getch();
776 if (ch == 0x1b)
777 break;
778 else
779 write(ups->fd, &ch, 1);
783 // Restore original timeouts on UPS fd
784 SetCommTimeouts(hnd, &orig_ups_ct);
785 #else
786 char ch;
787 struct termios t, old_term_params;
788 fd_set rfds;
789 int stat;
791 if (tcgetattr(0, &old_term_params) != 0) {
792 pmsg("Cannot tcgetattr()\n");
793 return;
796 t = old_term_params;
797 t.c_cc[VMIN] = 1; /* satisfy read after 1 char */
798 t.c_cc[VTIME] = 0;
799 t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK |
800 ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR);
801 t.c_iflag |= IGNBRK;
802 t.c_lflag &= ~(ICANON | ISIG | NOFLSH | TOSTOP);
803 tcflush(0, TCIFLUSH);
805 if (tcsetattr(0, TCSANOW, &t) == -1) {
806 pmsg("Cannot tcsetattr()\n");
807 return;
810 pmsg("Enter an ESC character (or ctl-[) to exit.\n\n");
812 tcflush(ups->fd, TCIOFLUSH);
813 for (;;) {
814 FD_ZERO(&rfds);
815 FD_SET(0, &rfds);
816 FD_SET(ups->fd, &rfds);
817 stat = select((ups->fd) + 1, &rfds, NULL, NULL, NULL);
818 if (stat == -1) {
819 pmsg("select() failed.\n");
820 break;
822 if (FD_ISSET(0, &rfds)) {
823 if (read(0, &ch, 1) != 1)
824 break;
826 if (ch == 0x1B)
827 break;
829 write(ups->fd, &ch, 1);
831 if (FD_ISSET(ups->fd, &rfds)) {
832 if (read(ups->fd, &ch, 1) != 1)
833 break;
835 write(1, &ch, 1);
839 tcsetattr(0, TCSANOW, &old_term_params);
840 #endif
844 /* Do runtime battery calibration */
845 static void smart_calibration(void)
847 char *ans, cmd;
848 char answer[2000];
849 int stat, monitor, elapse;
850 time_t start_time;
852 pmsg("First ensure that we have a good link and \n"
853 "that the UPS is functionning normally.\n");
854 pmsg("Simulating UPSlinkCheck ...\n");
856 tcflush(ups->fd, TCIOFLUSH);
858 /* Start really simply */
859 cmd = 'Y';
860 stat = write(ups->fd, &cmd, 1);
861 if (stat < 0)
862 pmsg("Bad status from write: %s\n", strerror(errno));
864 stat = getline(answer, sizeof(answer), ups);
865 pmsg("Wrote: Y Got: %s\n", answer);
866 if (stat == FAILURE) {
867 pmsg("getline failed. Apparently the link is not up.\n"
868 "Giving up.\n");
869 return;
872 pmsg("Attempting to use smart_poll() ...\n");
873 ans = smart_poll('Y', ups);
874 pmsg("Sent: Y Got: %s ", ans);
875 if (strcmp(ans, "SM") == 0) {
876 pmsg("Good -- smart_poll() works!.\n\n");
877 } else {
878 pmsg("Not good.\nGiving up.\n");
879 return;
882 pmsg("Checking estimated runtime ...\n");
883 ans = smart_poll('j', ups);
884 if (*ans >= '0' && *ans <= '9') {
885 int rt = atoi(ans);
887 pmsg("Current runtime is %d minutes\n", rt);
888 } else {
889 pmsg("Unexpected response from UPS: %s\n", ans);
890 return;
893 pmsg("Checking for battery level ...\n");
894 ans = smart_poll('f', ups);
895 if (strncmp(ans, "100.0", 5) == 0) {
896 pmsg("Battery level is 100.0 -- OK\n");
897 } else {
898 pmsg("Battery level %s insufficient to run test.\n", ans);
899 return;
902 pmsg("\nThe battery calibration should automatically end\n"
903 "when the battery level drops below about 25, depending\n"
904 "on your UPS.\n\n"
905 "I can also optionally monitor the progress\n"
906 "and stop the calibration if it goes below 10. However,\n"
907 "in the case of a new battery this may prematurely end the\n"
908 "calibration loosing the effect.\n\n");
910 ans = get_cmd("Do you want me to stop the calibration\n"
911 "if the battery level goes too low? (y/n): ");
913 if (*ans == 'Y' || *ans == 'y')
914 monitor = 1;
915 else
916 monitor = 0;
918 pmsg("\nSending Battery Calibration command. ...\n");
920 ans = smart_poll('D', ups);
921 if (*ans == '!' || strcmp(ans, "OK") == 0) {
922 pmsg("UPS has initiated battery calibration.\n");
923 } else {
924 pmsg("Unexpected response from UPS: %s\n", ans);
925 return;
928 start_time = time(NULL);
929 monitor_calibration_progress(monitor);
930 elapse = time(NULL) - start_time;
931 pmsg("On battery %d sec or %dm%ds.\n", elapse, elapse / 60, elapse % 60);
934 static void terminate_calibration(int ask)
936 char *ans, *cmd;
938 if (ask) {
939 pmsg("\nCAUTION! Don't use this command unless the UPS\n"
940 "is already doing a calibration.\n");
941 cmd = get_cmd("Are you sure? (yes/no): ");
942 if (strcmp(cmd, "yes") != 0)
943 return;
946 pmsg("\nAttempting to abort calibration ...\n");
947 ans = smart_poll('D', ups); /* abort calibration */
948 if (*ans == '$' || strcmp(ans, "NO") == 0) {
949 pmsg("Battery Runtime Calibration terminated.\n");
950 pmsg("Checking estimated runtime ...\n");
951 ans = smart_poll('j', ups);
952 if (*ans >= '0' && *ans <= '9') {
953 int rt = atoi(ans);
955 pmsg("Updated runtime is %d\n", rt);
956 } else {
957 pmsg("Unexpected response from UPS: %s\n", ans);
959 } else {
960 pmsg("Response to abort request: %s\n", ans);
965 static void monitor_calibration_progress(int monitor)
967 char *ans;
968 int count = 6;
969 int max_count = 6;
970 char period = '.';
972 pmsg("Monitoring the calibration progress ...\n"
973 "To stop the calibration, enter a return.\n");
975 for (;;) {
976 fd_set rfds;
977 struct timeval tv;
978 int retval, percent;
979 char cmd;
981 FD_ZERO(&rfds);
982 FD_SET(ups->fd, &rfds);
983 FD_SET(STDIN_FILENO, &rfds);
984 tv.tv_sec = 10;
985 tv.tv_usec = 0;
986 errno = 0;
988 retval = select((ups->fd) + 1, &rfds, NULL, NULL, &tv);
990 switch (retval) {
991 case 0:
992 if (++count >= max_count) {
993 ans = smart_poll('f', ups); /* Get battery charge */
994 percent = (int)strtod(ans, NULL);
995 pmsg("\nBattery charge %d\n", percent);
997 if (percent > 0) {
998 if (monitor && percent <= 10) {
999 pmsg("Battery charge less than 10% terminating calibration ...\n");
1000 terminate_calibration(0);
1001 return;
1003 if (percent < 30)
1004 max_count = 2; /* report faster */
1007 ans = smart_poll('j', ups); /* Get runtime */
1008 if (*ans >= '0' && *ans <= '9') {
1009 int rt = atoi(ans);
1011 pmsg("Remaining runtime is %d minutes\n", rt);
1012 if (monitor && rt < 2) {
1013 pmsg("Runtime less than 2 minutes terminating calibration ...\n");
1014 terminate_calibration(0);
1015 return;
1018 count = 0;
1019 } else {
1020 write(STDOUT_FILENO, &period, 1);
1022 continue;
1024 case -1:
1025 if (errno == EINTR || errno == EAGAIN)
1026 continue;
1028 pmsg("\nSelect error. ERR=%s\n", strerror(errno));
1029 return;
1031 default:
1032 break;
1035 /* *ANY* user input aborts the calibration */
1036 if (FD_ISSET(STDIN_FILENO, &rfds)) {
1037 read(STDIN_FILENO, &cmd, 1);
1038 pmsg("\nUser input. Terminating calibration ...\n");
1039 terminate_calibration(0);
1040 return;
1043 if (FD_ISSET(ups->fd, &rfds)) {
1044 read(ups->fd, &cmd, 1);
1045 if (cmd == '$') {
1046 pmsg("\nBattery Runtime Calibration terminated by UPS.\n");
1047 pmsg("Checking estimated runtime ...\n");
1048 ans = smart_poll('j', ups);
1049 if (*ans >= '0' && *ans <= '9') {
1050 int rt = atoi(ans);
1052 pmsg("Remaining runtime is %d minutes\n", rt);
1053 } else {
1054 pmsg("Unexpected response from UPS: %s\n", ans);
1056 return;
1057 /* ignore normal characters */
1058 } else if (cmd == '!' || cmd == '+' || cmd == ' ' ||
1059 cmd == '\n' || cmd == '\r') {
1060 continue;
1061 } else {
1062 pmsg("\nUPS sent: %c\n", cmd);
1068 static void program_smart_eeprom(void)
1070 char *cmd;
1071 int quit = FALSE;
1073 pmsg("This is the EEPROM programming section of apctest.\n"
1074 "Please select the function you want to perform.\n");
1076 while (!quit) {
1077 pmsg("\n"
1078 " 1) Print EEPROM values\n"
1079 " 2) Change Battery date\n"
1080 " 3) Change UPS name\n"
1081 " 4) Change sensitivity\n"
1082 " 5) Change alarm delay\n"
1083 " 6) Change low battery warning delay\n"
1084 " 7) Change wakeup delay\n"
1085 " 8) Change shutdown delay\n"
1086 " 9) Change low transfer voltage\n"
1087 "10) Change high transfer voltage\n"
1088 "11) Change battery return threshold percent\n"
1089 "12) Change output voltage when on batteries\n"
1090 "13) Change the self test interval\n"
1091 "14) Set EEPROM with conf file values\n"
1092 " Q) Quit\n\n");
1094 cmd = get_cmd("Select function number: ");
1095 if (cmd) {
1096 int item = atoi(cmd);
1098 switch (item) {
1099 case 1:
1100 print_eeprom_values(ups);
1101 break;
1103 case 2:
1104 cmd = get_cmd("Enter new battery date -- DD/MM/YY: ");
1105 if (strlen(cmd) != 8 || cmd[2] != '/' || cmd[5] != '/') {
1106 pmsg("Date must be exactly DD/MM/YY\n");
1107 break;
1109 apcsmart_ups_program_eeprom(ups, CI_BATTDAT, cmd);
1110 break;
1112 case 3:
1113 cmd = get_cmd("Enter new UPS name -- max 8 chars: ");
1114 if (strlen(cmd) == 0 || strlen(cmd) > 8) {
1115 pmsg("Name must be between 1 and 8 characters long.\n");
1116 break;
1118 apcsmart_ups_program_eeprom(ups, CI_IDEN, cmd);
1119 break;
1121 case 4:
1122 cmd = get_cmd("Enter new sensitivity: ");
1123 apcsmart_ups_program_eeprom(ups, CI_SENS, cmd);
1124 break;
1126 case 5:
1127 cmd = get_cmd("Enter new alarm delay: ");
1128 apcsmart_ups_program_eeprom(ups, CI_DALARM, cmd);
1129 break;
1131 case 6:
1132 cmd = get_cmd("Enter new low battery delay: ");
1133 apcsmart_ups_program_eeprom(ups, CI_DLBATT, cmd);
1134 break;
1136 case 7:
1137 cmd = get_cmd("Enter new wakeup delay: ");
1138 apcsmart_ups_program_eeprom(ups, CI_DWAKE, cmd);
1139 break;
1141 case 8:
1142 cmd = get_cmd("Enter new shutdown delay: ");
1143 apcsmart_ups_program_eeprom(ups, CI_DSHUTD, cmd);
1144 break;
1146 case 9:
1147 cmd = get_cmd("Enter new low transfer voltage: ");
1148 apcsmart_ups_program_eeprom(ups, CI_LTRANS, cmd);
1149 break;
1151 case 10:
1152 cmd = get_cmd("Enter new high transfer voltage: ");
1153 apcsmart_ups_program_eeprom(ups, CI_HTRANS, cmd);
1154 break;
1156 case 11:
1157 cmd = get_cmd("Enter new battery return level: ");
1158 apcsmart_ups_program_eeprom(ups, CI_RETPCT, cmd);
1159 break;
1161 case 12:
1162 cmd = get_cmd("Enter new output voltage on batteries: ");
1163 apcsmart_ups_program_eeprom(ups, CI_NOMOUTV, cmd);
1164 break;
1166 case 13:
1167 cmd = get_cmd("Enter new self test interval: ");
1168 apcsmart_ups_program_eeprom(ups, CI_STESTI, cmd);
1169 break;
1171 case 14:
1172 pmsg("The EEPROM values to be changed will be taken from\n"
1173 "the configuration directives in your apcupsd.conf file.\n");
1174 cmd = get_cmd("Do you want to continue? (Y/N): ");
1175 if (*cmd != 'y' && *cmd != 'Y') {
1176 pmsg("EEPROM changes NOT made.\n");
1177 break;
1179 apcsmart_ups_program_eeprom(ups, -1, NULL);
1180 break;
1182 default:
1183 if (tolower(*cmd) == 'q')
1184 quit = TRUE;
1185 else
1186 pmsg("Illegal response. Please enter 1-14,Q\n");
1187 break;
1189 } else {
1190 pmsg("Illegal response. Please enter 1-14,Q\n");
1193 ptime();
1194 pmsg("End EEPROM programming.\n");
1197 static void smart_test1(void)
1199 char *ans, *p, *o, cmd;
1200 char answer[2000];
1201 char parts[2000];
1202 int stat;
1204 #ifdef working
1205 char locale, locale1, locale2;
1206 #endif
1208 pmsg("I am going to run through the series of queries of the UPS\n"
1209 "that are used in initializing apcupsd.\n\n");
1211 pmsg("Simulating UPSlinkCheck ...\n");
1212 tcflush(ups->fd, TCIOFLUSH);
1214 /* Start really simply */
1215 cmd = 'Y';
1216 stat = write(ups->fd, &cmd, 1);
1217 if (stat < 0)
1218 pmsg("Bad status from write: %s\n", strerror(errno));
1220 stat = getline(answer, sizeof(answer), ups);
1221 pmsg("Wrote: Y Got: %s\n", answer);
1222 if (stat == FAILURE) {
1223 pmsg("getline failed. Apparently the link is not up.\n"
1224 "Giving up.\n");
1225 return;
1228 pmsg("Attempting to use smart_poll() ...\n");
1229 ans = smart_poll('Y', ups);
1230 pmsg("Sent: Y Got: %s ", ans);
1231 if (strcmp(ans, "SM") == 0) {
1232 pmsg("Good -- smart_poll() works!.\n\n");
1233 } else {
1234 pmsg("Not good.\nGiving up.\n");
1235 return;
1238 pmsg("Going to ask for valid commands...\n");
1239 cmd = 'a';
1240 stat = write(ups->fd, &cmd, 1);
1241 if (stat != 1)
1242 pmsg("Bad response from write: %d %s\n", stat, strerror(errno));
1244 *answer = 0;
1245 stat = getline(answer, sizeof(answer), ups);
1246 pmsg("Wrote: a Got: %s\n", answer);
1247 if (stat == FAILURE) {
1248 pmsg("Cannot get the list of valid commands (a very old ups perhaps ?).\n");
1251 /* Get protocol version */
1252 for (p = answer, o = parts; *p && *p != '.'; p++)
1253 *o++ = *p;
1255 *o = 0;
1256 pmsg("Protocol version is: %s\n", parts);
1257 if (*p == '.')
1258 p++;
1260 /* Get alert characters */
1261 for (o = parts; *p && *p != '.'; p++) {
1262 if (*p < 0x20) {
1263 *o++ = '^';
1264 *o++ = *p + 'A' - 1;
1265 } else {
1266 *o++ = *p;
1269 *o = 0;
1271 pmsg("Alert characters are: %s\n", parts);
1272 if (*p == '.')
1273 p++;
1275 /* Get command characters */
1276 for (o = parts; *p; p++) {
1277 if (*p < 0x20) {
1278 *o++ = '^';
1279 *o++ = *p + 'A' - 1;
1280 } else {
1281 *o++ = *p;
1284 *o = 0;
1286 pmsg("Command characters are: %s\n", parts);
1287 pmsg("\nNow running through apcupsd get_UPS capabilities().\n"
1288 "NA indicates that the feature is Not Available\n\n");
1290 pmsg("UPS Status: %s\n", smart_poll(ups->UPS_Cmd[CI_STATUS], ups));
1292 pmsg("Line quality: %s\n", smart_poll(ups->UPS_Cmd[CI_LQUAL], ups));
1294 pmsg("Reason for last transfer to batteries: %s\n",
1295 smart_poll(ups->UPS_Cmd[CI_WHY_BATT], ups));
1297 pmsg("Self-Test Status: %s\n", smart_poll(ups->UPS_Cmd[CI_ST_STAT], ups));
1299 pmsg("Line Voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_VLINE], ups));
1301 pmsg("Line Voltage Max: %s\n", smart_poll(ups->UPS_Cmd[CI_VMAX], ups));
1303 pmsg("Line Voltage Min: %s\n", smart_poll(ups->UPS_Cmd[CI_VMIN], ups));
1305 pmsg("Output Voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_VOUT], ups));
1307 pmsg("Batt level percent: %s\n", smart_poll(ups->UPS_Cmd[CI_BATTLEV], ups));
1309 pmsg("Batt voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_VBATT], ups));
1311 pmsg("UPS Load: %s\n", smart_poll(ups->UPS_Cmd[CI_LOAD], ups));
1313 pmsg("Line freq: %s\n", smart_poll(ups->UPS_Cmd[CI_FREQ], ups));
1315 pmsg("Runtime left: %s\n", smart_poll(ups->UPS_Cmd[CI_RUNTIM], ups));
1317 pmsg("UPS Internal temp: %s\n", smart_poll(ups->UPS_Cmd[CI_ITEMP], ups));
1319 pmsg("Dip switch settings: %s\n", smart_poll(ups->UPS_Cmd[CI_DIPSW], ups));
1321 pmsg("Register 1: %s\n", smart_poll(ups->UPS_Cmd[CI_REG1], ups));
1323 pmsg("Register 2: %s\n", smart_poll(ups->UPS_Cmd[CI_REG2], ups));
1325 pmsg("Register 3: %s\n", smart_poll('8', ups));
1327 pmsg("Sensitivity: %s\n", smart_poll(ups->UPS_Cmd[CI_SENS], ups));
1329 pmsg("Wakeup delay: %s\n", smart_poll(ups->UPS_Cmd[CI_DWAKE], ups));
1331 pmsg("Sleep delay: %s\n", smart_poll(ups->UPS_Cmd[CI_DSHUTD], ups));
1333 pmsg("Low transfer voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_LTRANS], ups));
1335 pmsg("High transfer voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_HTRANS], ups));
1337 pmsg("Batt charge for return: %s\n", smart_poll(ups->UPS_Cmd[CI_RETPCT], ups));
1339 pmsg("Alarm status: %s\n", smart_poll(ups->UPS_Cmd[CI_DALARM], ups));
1341 pmsg("Low battery shutdown level: %s\n", smart_poll(ups->UPS_Cmd[CI_DLBATT],
1342 ups));
1344 pmsg("UPS Name: %s\n", smart_poll(ups->UPS_Cmd[CI_IDEN], ups));
1346 pmsg("UPS Self test interval: %s\n", smart_poll(ups->UPS_Cmd[CI_STESTI], ups));
1348 pmsg("UPS manufacture date: %s\n", smart_poll(ups->UPS_Cmd[CI_MANDAT], ups));
1350 pmsg("UPS serial number: %s\n", smart_poll(ups->UPS_Cmd[CI_SERNO], ups));
1352 pmsg("Date battery replaced: %s\n", smart_poll(ups->UPS_Cmd[CI_BATTDAT], ups));
1354 pmsg("Output voltage when on batteries: %s\n",
1355 smart_poll(ups->UPS_Cmd[CI_NOMOUTV], ups));
1357 pmsg("Nominal battery voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_NOMBATTV], ups));
1359 pmsg("Percent humidity: %s\n", smart_poll(ups->UPS_Cmd[CI_HUMID], ups));
1361 pmsg("Ambient temperature: %s\n", smart_poll(ups->UPS_Cmd[CI_ATEMP], ups));
1363 pmsg("Firmware revision: %s\n", smart_poll(ups->UPS_Cmd[CI_REVNO], ups));
1365 pmsg("Number of external batteries installed: %s\n",
1366 smart_poll(ups->UPS_Cmd[CI_EXTBATTS], ups));
1368 pmsg("Number of bad batteries installed: %s\n",
1369 smart_poll(ups->UPS_Cmd[CI_BADBATTS], ups));
1371 pmsg("UPS model as defined by UPS: %s\n", smart_poll(ups->UPS_Cmd[CI_UPSMODEL],
1372 ups));
1374 pmsg("UPS EPROM capabilities string: %s\n", (ans =
1375 smart_poll(ups->UPS_Cmd[CI_EPROM], ups)));
1376 pmsg("The EPROM string is %d characters long!\n", strlen(ans));
1378 pmsg("Hours since last self test: %s\n", smart_poll(ups->UPS_Cmd[CI_ST_TIME],
1379 ups));
1381 pmsg("\nThat is all for now.\n");
1382 return;
1384 #endif
1386 static void do_usb_testing(void)
1388 #ifdef HAVE_USB_DRIVER
1389 char *cmd;
1390 int quit = FALSE;
1392 pmsg("Hello, this is the apcupsd Cable Test program.\n"
1393 "This part of apctest is for testing USB UPSes.\n");
1395 pmsg("\nGetting UPS capabilities...");
1396 if (!usb_ups_get_capabilities(ups))
1397 pmsg("FAILED\nSome or all tests may not work!\n");
1398 else
1399 pmsg("SUCCESS\n");
1401 pmsg("\nPlease select the function you want to perform.\n");
1403 while (!quit) {
1404 pmsg("\n"
1405 "1) Test kill UPS power\n"
1406 "2) Perform self-test\n"
1407 "3) Read last self-test result\n"
1408 "4) View/Change battery date\n"
1409 "5) View manufacturing date\n"
1410 "6) View/Change alarm behavior\n"
1411 "7) View/Change sensitivity\n"
1412 "8) View/Change low transfer voltage\n"
1413 "9) View/Change high transfer voltage\n"
1414 "10) Perform battery calibration\n"
1415 "11) Test alarm\n"
1416 "12) View/Change self-test interval\n"
1417 " Q) Quit\n\n");
1419 cmd = get_cmd("Select function number: ");
1420 if (cmd) {
1421 int item = atoi(cmd);
1423 switch (item) {
1424 case 1:
1425 usb_kill_power_test();
1426 break;
1427 case 2:
1428 usb_run_self_test();
1429 break;
1430 case 3:
1431 usb_get_self_test_result();
1432 break;
1433 case 4:
1434 usb_set_battery_date();
1435 break;
1436 case 5:
1437 usb_get_manf_date();
1438 break;
1439 case 6:
1440 usb_set_alarm();
1441 break;
1442 case 7:
1443 usb_set_sens();
1444 break;
1445 case 8:
1446 usb_set_xferv(0);
1447 break;
1448 case 9:
1449 usb_set_xferv(1);
1450 break;
1451 case 10:
1452 usb_calibration();
1453 break;
1454 case 11:
1455 usb_test_alarm();
1456 break;
1457 case 12:
1458 usb_set_self_test_interval();
1459 break;
1460 default:
1461 if (tolower(*cmd) == 'q')
1462 quit = TRUE;
1463 else
1464 pmsg("Illegal response. Please enter 1-12,Q\n");
1465 break;
1467 } else {
1468 pmsg("Illegal response. Please enter 1-12,Q\n");
1471 ptime();
1472 pmsg("End apctest.\n");
1473 #else
1474 pmsg("USB Driver not configured.\n");
1475 #endif
1478 #ifdef HAVE_USB_DRIVER
1480 static void usb_set_xferv(int lowhigh)
1482 int result;
1483 char* cmd;
1484 const char *text;
1485 int ci;
1487 if (lowhigh) {
1488 text = "HIGH";
1489 ci = CI_HTRANS;
1490 } else {
1491 text = "LOW";
1492 ci = CI_LTRANS;
1495 if (!usb_read_int_from_ups(ups, ci, &result)) {
1496 pmsg("\nI don't know how to control the %s transfer voltage "
1497 " settings on your UPS.\n", text);
1498 return;
1501 int newval;
1502 do {
1503 pmsg("Current %s transfer voltage setting: %d Volts\n", text, result);
1505 pmsg("Enter new %s transfer voltage (0 to cancel): ", text);
1506 cmd = get_cmd("");
1507 newval = atoi(cmd);
1509 // Check for exit
1510 if (newval == 0)
1511 return;
1513 // Write new value
1514 usb_write_int_to_ups(ups, ci, newval, text);
1516 // Give write a chance to work, then read new value
1517 sleep(1);
1518 result = 0;
1519 usb_read_int_from_ups(ups, ci, &result);
1521 if (result != newval) {
1522 pmsg("FAILED to set new %s transfer voltage.\n\n"
1523 "This is probably because you entered a value that is out-of-range\n"
1524 "for your UPS. The acceptable range of values varies based on UPS\n"
1525 "model. The UPS has probably set the value as close as possible to\n"
1526 "what you requested.\n\n", text);
1529 while (result != newval);
1531 pmsg("New %s transfer voltage setting: %d Volts\n", text, result);
1534 static void usb_set_sens(void)
1536 int result;
1537 char* cmd;
1539 if (!usb_read_int_from_ups(ups, CI_SENS, &result)) {
1540 pmsg("\nI don't know how to control the alarm settings on your UPS.\n");
1541 return;
1544 pmsg("Current sensitivity setting: ");
1545 switch(result) {
1546 case 0:
1547 pmsg("LOW\n");
1548 break;
1549 case 1:
1550 pmsg("MEDIUM\n");
1551 break;
1552 case 2:
1553 pmsg("HIGH\n");
1554 break;
1555 default:
1556 pmsg("UNKNOWN\n");
1557 break;
1560 while(1) {
1561 pmsg("Press...\n"
1562 " L for Low sensitivity\n"
1563 " M for Medium sensitivity\n"
1564 " H for High sensitivity\n"
1565 " Q to Quit with no changes\n"
1566 "Your choice: ");
1567 cmd = get_cmd("Select function: ");
1568 if (cmd) {
1569 switch(tolower(*cmd)) {
1570 case 'l':
1571 usb_write_int_to_ups(ups, CI_SENS, 0, "CI_SENS");
1572 break;
1573 case 'm':
1574 usb_write_int_to_ups(ups, CI_SENS, 1, "CI_SENS");
1575 break;
1576 case 'h':
1577 usb_write_int_to_ups(ups, CI_SENS, 2, "CI_SENS");
1578 break;
1579 case 'q':
1580 return;
1581 default:
1582 pmsg("Illegal response.\n");
1583 continue;
1585 } else {
1586 pmsg("Illegal response.\n");
1587 continue;
1590 break;
1593 /* Delay needed for readback to work */
1594 sleep(1);
1596 usb_read_int_from_ups(ups, CI_SENS, &result);
1597 pmsg("New sensitivity setting: ");
1598 switch(result) {
1599 case 0:
1600 pmsg("LOW\n");
1601 break;
1602 case 1:
1603 pmsg("MEDIUM\n");
1604 break;
1605 case 2:
1606 pmsg("HIGH\n");
1607 break;
1608 default:
1609 pmsg("UNKNOWN\n");
1610 break;
1614 static void usb_set_alarm(void)
1616 int result;
1617 char* cmd;
1619 if (!usb_read_int_from_ups(ups, CI_DALARM, &result)) {
1620 pmsg("\nI don't know how to control the alarm settings on your UPS.\n");
1621 return;
1624 pmsg("Current alarm setting: ");
1625 switch(result) {
1626 case 1:
1627 pmsg("DISABLED\n");
1628 break;
1629 case 2:
1630 pmsg("ENABLED\n");
1631 break;
1632 default:
1633 pmsg("UNKNOWN\n");
1634 break;
1637 while(1) {
1638 pmsg("Press...\n"
1639 " E to Enable alarms\n"
1640 " D to Disable alarms\n"
1641 " Q to Quit with no changes\n"
1642 "Your choice: ");
1643 cmd = get_cmd("Select function: ");
1644 if (cmd) {
1645 switch(tolower(*cmd)) {
1646 case 'e':
1647 usb_write_int_to_ups(ups, CI_DALARM, 2, "CI_DALARM");
1648 break;
1649 case 'd':
1650 usb_write_int_to_ups(ups, CI_DALARM, 1, "CI_DALARM");
1651 break;
1652 case 'q':
1653 return;
1654 default:
1655 pmsg("Illegal response.\n");
1656 continue;
1658 } else {
1659 pmsg("Illegal response.\n");
1660 continue;
1663 break;
1666 /* Delay needed for readback to work */
1667 sleep(1);
1669 usb_read_int_from_ups(ups, CI_DALARM, &result);
1670 pmsg("New alarm setting: ");
1671 switch(result) {
1672 case 1:
1673 pmsg("DISABLED\n");
1674 break;
1675 case 2:
1676 pmsg("ENABLED\n");
1677 break;
1678 default:
1679 pmsg("UNKNOWN\n");
1680 break;
1684 static void usb_kill_power_test(void)
1686 pmsg("\nThis test will attempt to power down the UPS.\n"
1687 "The USB cable should be plugged in to the UPS, but the\n"
1688 "AC power plug to the UPS should be DISCONNECTED.\n\n"
1689 "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n"
1690 "Please enter any character when ready to continue: ");
1692 fgetc(stdin);
1693 pmsg("\n");
1695 ptime();
1696 pmsg("calling kill_power function.\n");
1698 make_file(ups, ups->pwrfailpath);
1699 initiate_hibernate(ups);
1700 unlink(ups->pwrfailpath);
1702 ptime();
1703 pmsg("returned from kill_power function.\n");
1706 static void usb_get_self_test_result(void)
1708 int result;
1710 if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) {
1711 pmsg("\nI don't know how to run a self test on your UPS\n"
1712 "or your UPS does not support self test.\n");
1713 return;
1716 pmsg("Result of last self test: ");
1717 switch (result) {
1718 case 1:
1719 pmsg("PASSED\n");
1720 break;
1721 case 2:
1722 pmsg("WARNING\n");
1723 break;
1724 case 3:
1725 pmsg("ERROR\n");
1726 break;
1727 case 4:
1728 pmsg("ABORTED\n");
1729 break;
1730 case 5:
1731 pmsg("IN PROGRESS\n");
1732 break;
1733 case 6:
1734 pmsg("NO TEST PERFORMED\n");
1735 break;
1736 default:
1737 pmsg("UNKNOWN (%02x)\n", result);
1738 break;
1742 static bool usb_clear_test_result()
1744 int timeout, result;
1746 pmsg("Clearing previous self test result...");
1748 // abort battery calibration in case it's in progress
1749 usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus");
1751 if (!usb_write_int_to_ups(ups, CI_ST_STAT, 0, "SelftestStatus")) {
1752 pmsg("FAILED\n");
1753 return false;
1756 for (timeout = 0; timeout < 10; timeout++) {
1757 if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) {
1758 pmsg("FAILED\n");
1759 return false;
1762 if (result == 6) {
1763 pmsg("CLEARED\n");
1764 break;
1767 sleep(1);
1770 if (timeout == 10) {
1771 pmsg("FAILED\n");
1772 return false;
1775 return true;
1778 static void usb_run_self_test(void)
1780 int result;
1781 int timeout;
1783 pmsg("\nThis test instructs the UPS to perform a self-test\n"
1784 "operation and reports the result when the test completes.\n\n");
1786 if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) {
1787 pmsg("I don't know how to run a self test on your UPS\n"
1788 "or your UPS does not support self test.\n");
1789 return;
1792 if (!usb_clear_test_result())
1793 return;
1795 pmsg("Initiating self test...");
1796 if (!usb_write_int_to_ups(ups, CI_ST_STAT, 1, "SelftestStatus")) {
1797 pmsg("FAILED\n");
1798 return;
1801 pmsg("INITIATED\n");
1803 pmsg("Waiting for test to complete...");
1805 for (timeout = 0; timeout < 40; timeout++) {
1806 if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) {
1807 pmsg("ERROR READING STATUS\n");
1808 usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus");
1809 return;
1812 if (result != 6) {
1813 pmsg("COMPLETED\n");
1814 break;
1817 sleep(1);
1820 if (timeout == 40) {
1821 pmsg("TEST DID NOT COMPLETE\n");
1822 usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus");
1823 return;
1826 usb_get_self_test_result();
1829 static int usb_get_battery_date(void)
1831 int result;
1833 if (!usb_read_int_from_ups(ups, CI_BATTDAT, &result)) {
1834 pmsg("\nI don't know how to access the battery date on your UPS\n"
1835 "or your UPS does not support the battery date feature.\n");
1836 return 0;
1840 * Date format is:
1841 * YYYY|YYYM|MMMD|DDDD
1842 * bit 0-4: Day
1843 * 5-8: Month
1844 * 9-15: Year-1980
1846 pmsg("Current battery date: %02u/%02u/%04u\n",
1847 (result & 0x1e0) >> 5, result & 0x1f, 1980 + ((result & 0xfe00) >> 9));
1849 return result;
1852 static void usb_set_battery_date(void)
1854 char *cmd;
1855 int result, day, month, year, temp, max;
1857 if (!(result = usb_get_battery_date()))
1858 return;
1860 cmd = get_cmd("Enter new battery date (MM/DD/YYYY), blank to quit: ");
1861 if (!isdigit(cmd[0]) || !isdigit(cmd[1]) || cmd[2] != '/' ||
1862 !isdigit(cmd[3]) || !isdigit(cmd[4]) || cmd[5] != '/' ||
1863 !isdigit(cmd[6]) || !isdigit(cmd[7]) || !isdigit(cmd[8]) ||
1864 !isdigit(cmd[9]) || cmd[10] != '\0' ||
1865 ((month = strtoul(cmd, NULL, 10)) > 12) || (month < 1) ||
1866 ((day = strtoul(cmd + 3, NULL, 10)) > 31) || (day < 1) ||
1867 ((year = strtoul(cmd + 6, NULL, 10)) < 1980)) {
1868 pmsg("Invalid format.\n");
1869 return;
1872 result = ((year - 1980) << 9) | (month << 5) | day;
1874 pmsg("Writing new date...");
1875 if (!usb_write_int_to_ups(ups, CI_BATTDAT, result, "ManufactureDate")) {
1876 pmsg("FAILED\n");
1877 return;
1880 pmsg("SUCCESS\n");
1882 pmsg("Waiting for change to take effect...");
1883 for (max = 0; max < 10; max++) {
1884 if (!usb_read_int_from_ups(ups, CI_BATTDAT, &temp)) {
1885 pmsg("ERROR\n");
1886 return;
1889 if (temp == result)
1890 break;
1892 sleep(1);
1895 if (max == 10)
1896 pmsg("TIMEOUT\n");
1897 else
1898 pmsg("SUCCESS\n");
1900 usb_get_battery_date();
1903 static void usb_get_manf_date(void)
1905 int result;
1907 if (!usb_read_int_from_ups(ups, CI_MANDAT, &result)) {
1908 pmsg("\nI don't know how to access the manufacturing date on your UPS\n"
1909 "or your UPS does not support the manufacturing date feature.\n");
1910 return;
1914 * Date format is:
1915 * YYYY|YYYM|MMMD|DDDD
1916 * bit 0-4: Day
1917 * 5-8: Month
1918 * 9-15: Year-1980
1920 pmsg("Manufacturing date: %02u/%02u/%04u\n",
1921 (result & 0x1e0) >> 5, result & 0x1f, 1980 + ((result & 0xfe00) >> 9));
1924 static void usb_calibration()
1926 int result;
1927 int aborted;
1928 int ilastbl;
1930 if (!ups->UPS_Cap[CI_ST_STAT] ||
1931 !ups->UPS_Cap[CI_BATTLEV] ||
1932 !ups->UPS_Cap[CI_LOAD]) {
1933 pmsg("\nI don't know how to run a battery calibration on your UPS\n"
1934 "or your UPS does not support battery calibration\n");
1935 return;
1938 pmsg("This test instructs the UPS to perform a battery calibration\n"
1939 "operation and reports the result when the process completes.\n"
1940 "The battery level must be at 100%% and the load must be at least\n"
1941 "10%% to begin this test.\n\n");
1943 if (!usb_read_int_from_ups(ups, CI_BATTLEV, &result)) {
1944 pmsg("Failed to read current battery level\n");
1945 return;
1948 if (result == 100) {
1949 pmsg("Battery level is %d%% -- OK\n", result);
1951 else {
1952 pmsg("Battery level %d%% is insufficient to run test.\n", result);
1953 return;
1956 if (!usb_read_int_from_ups(ups, CI_LOAD, &result)) {
1957 pmsg("Failed to read current load level\n");
1958 return;
1961 if (result >= 10) {
1962 pmsg("Load level is %d%% -- OK\n", result);
1964 else {
1965 pmsg("Load level %d%% is insufficient to run test.\n", result);
1966 return;
1969 if (!usb_clear_test_result())
1970 return;
1972 pmsg("\nThe battery calibration should automatically end\n"
1973 "when the battery level drops below about 25%%.\n"
1974 "This process can take minutes or hours, depending on\n"
1975 "the size of your UPS and the load attached.\n\n");
1977 pmsg("Initiating battery calibration...");
1978 if (!usb_write_int_to_ups(ups, CI_ST_STAT, 2, "SelftestStatus")) {
1979 pmsg("FAILED\n");
1980 return;
1983 pmsg("INITIATED\n\n");
1985 pmsg("Waiting for calibration to complete...\n"
1986 "To abort the calibration, press ENTER.\n");
1988 ilastbl = 0;
1989 while (1) {
1990 #ifndef HAVE_MINGW
1991 fd_set rfds;
1992 struct timeval tv;
1993 FD_ZERO(&rfds);
1994 FD_SET(STDIN_FILENO, &rfds);
1995 tv.tv_sec = 10;
1996 tv.tv_usec = 0;
1998 aborted = select(STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 1;
1999 if (aborted) {
2000 while (fgetc(stdin) != '\n')
2003 #else
2004 aborted = false;
2005 for (int i = 0; i < 100 && !aborted; i++) {
2006 while (kbhit() && !aborted)
2007 aborted = getch() == '\r';
2008 if (!aborted)
2010 struct timespec ts;
2011 ts.tv_sec = 0;
2012 ts.tv_nsec = 100000000;
2013 nanosleep(&ts, NULL);
2016 #endif
2018 if (aborted) {
2019 pmsg("\n\nUser input detected; aborting calibration...");
2020 if (!usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus")) {
2021 pmsg("FAILED\n");
2023 else {
2024 pmsg("ABORTED\n");
2026 return;
2029 if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) {
2030 pmsg("\n\nError reading status; aborting calibration...");
2031 if (!usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus")) {
2032 pmsg("FAILED\n");
2034 else {
2035 pmsg("ABORTED\n");
2037 return;
2040 if (result != 5) {
2041 pmsg("\nCALIBRATION COMPLETED\n");
2042 break;
2045 // Output the battery level
2046 if (usb_read_int_from_ups(ups, CI_BATTLEV, &result)) {
2047 if (ilastbl == result)
2048 pmsg(".");
2049 else
2050 pmsg("\nBattery level: %d%%", result);
2051 ilastbl = result;
2053 else
2054 pmsg(".");
2057 usb_get_self_test_result();
2060 static void usb_test_alarm(void)
2062 int result;
2064 if (!usb_read_int_from_ups(ups, CI_TESTALARM, &result))
2066 pmsg("\nI don't know how to test the alarm on your UPS.\n");
2067 return;
2070 // Write to UPS
2071 pmsg("Testing alarm...");
2072 usb_write_int_to_ups(ups, CI_TESTALARM, 1, "CI_TESTALARM");
2073 sleep(1);
2075 pmsg("COMPLETE\n");
2078 static int usb_get_self_test_interval(void)
2080 int result;
2082 if (!usb_read_int_from_ups(ups, CI_STESTI, &result))
2084 pmsg("\nI don't know how to access the self-test interval on your UPS\n"
2085 "or your UPS does not support the self-test interval feature.\n");
2086 return -1;
2089 pmsg("Current Self-test interval: ");
2090 switch (result)
2092 case 0:
2093 pmsg("None\n");
2094 break;
2095 case 1:
2096 pmsg("Power On\n");
2097 break;
2098 case 2:
2099 pmsg("7 days\n");
2100 break;
2101 case 3:
2102 pmsg("14 days\n");
2103 break;
2104 default:
2105 pmsg("UNKNOWN (%02x)\n", result);
2106 break;
2109 return result;
2112 static void usb_set_self_test_interval(void)
2114 if (usb_get_self_test_interval() == -1)
2115 return;
2117 while(1)
2119 pmsg("Press...\n"
2120 " 0 for None\n"
2121 " 1 for On Power\n"
2122 " 2 for 7 Days\n"
2123 " 3 for 14 Days\n"
2124 " Q to Quit with no changes\n"
2125 "Your choice: ");
2126 char *cmd = get_cmd("Select function: ");
2127 if (cmd)
2129 if (*cmd >= '0' && *cmd <= '3')
2131 usb_write_int_to_ups(ups, CI_STESTI, *cmd-'0', "CI_STESTI");
2132 break;
2134 else if (tolower(*cmd) == 'q')
2135 return;
2136 else
2137 pmsg("Illegal response.\n");
2139 else
2141 pmsg("Illegal response.\n");
2145 /* Delay needed for readback to work */
2146 sleep(1);
2147 usb_get_self_test_interval();
2150 #endif
2152 /* Get next input command from the terminal */
2153 static char *get_cmd(const char *prompt)
2155 static char cmd[1000];
2157 pmsg(prompt);
2159 if (fgets(cmd, sizeof(cmd), stdin) == NULL)
2160 return NULL;
2162 write_file(cmd);
2164 pmsg("\n");
2165 strip_trailing_junk(cmd);
2167 return cmd;
2170 /* Strip any trailing junk from the command */
2171 static void strip_trailing_junk(char *cmd)
2173 char *p;
2175 p = cmd + strlen(cmd) - 1;
2177 /* strip trailing junk from command */
2178 while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
2179 *p-- = 0;
2182 #ifdef HAVE_APCSMART_DRIVER
2185 * EPROM commands and their values as parsed from the
2186 * ^Z eprom string returned by the UPS.
2188 static struct {
2189 char cmd;
2190 char size;
2191 char num;
2192 char cmdvals[50];
2193 } cmd[15];
2195 /* Total number of EPROM commands */
2196 static int ncmd = 0;
2198 static UPSINFO eeprom_ups;
2201 * Table of the UPS command, the apcupsd configuration directive,
2202 * and an explanation of what the command sets in the EPROM.
2204 static struct {
2205 char cmd;
2206 const char *config_directive;
2207 const char *descript;
2208 char type;
2209 int *data;
2210 } cmd_table[] = {
2211 {'u', "HITRANSFER", "Upper transfer voltage", 'i', &eeprom_ups.hitrans},
2212 {'l', "LOTRANSFER", "Lower transfer voltage", 'i', &eeprom_ups.lotrans},
2213 {'e', "RETURNCHARGE", "Return threshold", 'i', &eeprom_ups.rtnpct},
2214 {'o', "OUTPUTVOLTS", "Output voltage on batts", 'i', &eeprom_ups.NomOutputVoltage},
2215 {'s', "SENSITIVITY", "Sensitivity", 'c', (int *)eeprom_ups.sensitivity},
2216 {'q', "LOWBATT", "Low battery warning", 'i', &eeprom_ups.dlowbatt},
2217 {'p', "SLEEP", "Shutdown grace delay", 'i', &eeprom_ups.dshutd},
2218 {'k', "BEEPSTATE", "Alarm delay", 'c', (int *)eeprom_ups.beepstate},
2219 {'r', "WAKEUP", "Wakeup delay", 'i', &eeprom_ups.dwake},
2220 {'E', "SELFTEST", "Self test interval", 'c', (int *)eeprom_ups.selftest},
2221 {0, NULL, NULL} /* Last entry */
2225 static void print_valid_eeprom_values(UPSINFO *ups)
2227 int i, j, k, l;
2228 char *p;
2229 char val[100];;
2231 pmsg("\nValid EEPROM values for the %s\n\n", ups->mode.long_name);
2233 memcpy(&eeprom_ups, ups, sizeof(UPSINFO));
2235 pmsg("%-24s %-12s %-6s %s\n", " ", "Config", "Current", "Permitted");
2236 pmsg("%-24s %-12s %-6s %s\n", "Description", "Directive", "Value ", "Values");
2237 pmsg("===================================================================\n");
2239 for (i = 0; i < ncmd; i++) {
2240 for (j = 0; cmd_table[j].cmd; j++) {
2241 if (cmd[i].cmd == cmd_table[j].cmd) {
2242 if (cmd_table[j].type == 'c')
2243 asnprintf(val, sizeof(val), "%s", (char *)cmd_table[j].data);
2244 else
2245 asnprintf(val, sizeof(val), "%d", *cmd_table[j].data);
2247 pmsg("%-24s %-12s %-6s ", cmd_table[j].descript,
2248 cmd_table[j].config_directive, val);
2250 p = cmd[i].cmdvals;
2251 for (k = cmd[i].num; k; k--) {
2252 for (l = cmd[i].size; l; l--)
2253 pmsg("%c", *p++);
2255 pmsg(" ");
2258 pmsg("\n");
2259 break;
2264 pmsg("===================================================================\n");
2266 tcflush(ups->fd, TCIOFLUSH);
2267 smart_poll('Y', ups);
2268 smart_poll('Y', ups);
2270 pmsg("Battery date: %s\n", smart_poll(ups->UPS_Cmd[CI_BATTDAT], ups));
2271 pmsg("UPS Name : %s\n", smart_poll(ups->UPS_Cmd[CI_IDEN], ups));
2272 pmsg("\n");
2276 * Parse EPROM command string returned by a ^Z command. We
2277 * pull out only entries that correspond to our UPS (locale).
2279 static void parse_eeprom_cmds(char *eprom, char locale)
2281 char *p = eprom;
2282 char c, l, n, s;
2283 #ifdef debuggggggg
2284 int i;
2285 #endif
2287 ncmd = 0;
2288 for (;;) {
2289 c = *p++;
2290 if (c == 0)
2291 break;
2293 if (c == '#')
2294 continue;
2296 l = *p++; /* get locale */
2297 n = *p++ - '0'; /* get number of commands */
2298 s = *p++ - '0'; /* get character size */
2300 if (l != '4' && l != locale) { /* skip this locale */
2301 p += n * s;
2302 continue;
2305 cmd[ncmd].cmd = c; /* store command */
2306 cmd[ncmd].size = s; /* chare length of each value */
2307 cmd[ncmd].num = n; /* number of values */
2309 strncpy(cmd[ncmd].cmdvals, p, n * s); /* save values */
2310 p += n * s;
2311 ncmd++;
2313 #ifdef debuggggggg
2314 printf("\n");
2315 for (i = 0; i < ncmd; i++) {
2316 printf("cmd=%c len=%d nvals=%d vals=%s\n", cmd[i].cmd,
2317 cmd[i].size, cmd[i].num, cmd[i].cmdvals);
2319 #endif
2322 /*********************************************************************/
2323 static void print_eeprom_values(UPSINFO *ups)
2325 char locale, locale1, locale2;
2327 pmsg("Doing prep_device() ...\n");
2328 prep_device(ups);
2329 if (!ups->UPS_Cap[CI_EPROM])
2330 Error_abort0("Your model does not support EPROM programming.\n");
2332 if (ups->UPS_Cap[CI_REVNO])
2333 locale1 = *(ups->firmrev + strlen(ups->firmrev) - 1);
2334 else
2335 locale1 = 0;
2337 if (ups->UPS_Cap[CI_UPSMODEL])
2338 locale2 = *(ups->upsmodel + strlen(ups->upsmodel) - 1);
2339 else
2340 locale2 = 0;
2342 if (locale1 == locale2 && locale1 == 0)
2343 Error_abort0("Your model does not support EPROM programming.\n");
2345 if (locale1 == locale2)
2346 locale = locale1;
2348 if (locale1 == 0)
2349 locale = locale2;
2350 else
2351 locale = locale1;
2353 parse_eeprom_cmds(ups->eprom, locale);
2354 print_valid_eeprom_values(ups);
2356 #endif