2 * wattsup - Program for controlling the Watts Up? Pro Device
5 * Copyright (c) 2005 Patrick Mochel
7 * This program is released under the GPLv2
12 * gcc -O2 -Wall -o wattsup wattsup.c
32 static const char * wu_version
= "0.02";
35 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
37 static const char * prog_name
= "wattsup";
39 static const char * sysfs_path_start
= "/sys/class/tty";
41 static char * wu_device
= "ttyUSB0";
43 static int wu_count
= 0;
44 static int wu_debug
= 0;
45 static char *wu_delim
= ", ";
46 static int wu_final
= 0;
47 static int wu_interval
= 1;
48 static int wu_label
= 0;
49 static int wu_newline
= 0;
50 static int wu_suppress
= 0;
52 static int wu_localtime
= 0;
53 static int wu_gmtime
= 0;
55 static int wu_info_all
= 0;
56 static int wu_no_data
= 0;
57 static int wu_set_only
= 0;
60 #define wu_num_fields 18
61 #define wu_param_len 16
69 char * field
[wu_num_fields
];
70 char * label
[wu_num_fields
];
78 unsigned int watt_hours
;
83 unsigned int max_watts
;
85 unsigned int max_volts
;
86 unsigned int max_amps
;
87 unsigned int min_watts
;
88 unsigned int min_volts
;
90 unsigned int min_amps
;
91 unsigned int power_factor
;
92 unsigned int duty_cycle
;
93 unsigned int power_cycle
;
107 int (*show
)(int dev_fd
);
108 int (*store
)(int dev_fd
);
141 static char * wu_option_value(unsigned int index
);
162 wu_field_power_factor
,
164 wu_field_power_cycle
,
173 static struct wu_field wu_fields
[wu_num_fields
] = {
176 .descr
= "Watt Consumption",
179 [wu_field_min_watts
] = {
181 .descr
= "Minimum Watts Consumed",
184 [wu_field_max_watts
] = {
186 .descr
= "Maxium Watts Consumed",
191 .descr
= "Volts Consumption",
194 [wu_field_min_volts
] = {
196 .descr
= "Minimum Volts Consumed",
199 [wu_field_max_volts
] = {
201 .descr
= "Maximum Volts Consumed",
206 .descr
= "Amp Consumption",
209 [wu_field_min_amps
] = {
211 .descr
= "Minimum Amps Consumed",
214 [wu_field_max_amps
] = {
216 .descr
= "Maximum Amps Consumed",
219 [wu_field_watt_hours
] = {
221 .descr
= "Average KWH",
224 [wu_field_mo_kwh
] = {
226 .descr
= "Average monthly KWH",
231 .descr
= "Cost per watt",
234 [wu_field_mo_cost
] = {
236 .descr
= "Monthly Cost",
239 [wu_field_power_factor
] = {
240 .name
= "power-factor",
241 .descr
= "Ratio of Watts vs. Volt Amps",
244 [wu_field_duty_cycle
] = {
245 .name
= "duty-cycle",
246 .descr
= "Percent of the Time On vs. Time Off",
249 [wu_field_power_cycle
] = {
250 .name
= "power-cycle",
251 .descr
= "Indication of power cycle",
258 static void msg_start(const char * fmt
, ...)
266 static void msg_end(void)
271 static void msg(const char * fmt
, ...)
280 static void dbg(const char * fmt
, ...)
286 msg_start("%s: [debug] ", prog_name
);
293 static void err(const char * fmt
, ...)
298 fprintf(stderr
, "%s: [error] ", prog_name
);
299 vfprintf(stderr
, fmt
, ap
);
300 fprintf(stderr
, "\n");
304 static void perr(const char * fmt
, ...)
311 n
= sprintf(buf
, "%s: [error] ", prog_name
);
312 vsnprintf(buf
+ n
, sizeof(buf
) - n
, fmt
, ap
);
317 static int ret_err(int err
)
324 static void print_packet(struct wu_packet
* p
, char * str
)
329 msg_start("Watts Up? %s\n", str
);
330 for (i
= 0; i
< p
->count
; i
++) {
332 msg("%s", wu_newline
? "\n" : wu_delim
);
334 msg("[%s] ", p
->label
[i
]);
341 static void print_time(void)
346 if (wu_localtime
|| wu_gmtime
) {
354 msg("[%02d:%02d:%02d] ",
355 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
359 static void print_packet_filter(struct wu_packet
* p
,
360 int (*filter_ok
)(struct wu_packet
* p
, int i
, char * str
))
367 for (i
= 0, printed
= 0; i
< p
->count
; i
++) {
368 if (!filter_ok(p
, i
, buf
))
372 msg("%s", wu_newline
? "\n" : wu_delim
);
374 msg("[%s] ", p
->label
[i
]);
382 * Device should be something like "ttyS0"
385 static int open_device(char * device_name
, int * dev_fd
)
391 cur_fd
= open(".", O_RDONLY
);
393 perr("Could not open current directory.");
397 ret
= chdir(sysfs_path_start
);
399 perr(sysfs_path_start
);
404 * First, check if /sys/class/tty/<name>/ exists.
407 dbg("Checking sysfs path: %s/%s", sysfs_path_start
, device_name
);
409 ret
= stat(device_name
,&s
);
415 if (!S_ISDIR(s
.st_mode
)) {
417 err("%s is not a TTY device.", device_name
);
421 dbg("%s is a registered TTY device", device_name
);
427 * Check if device node exists and is writable
431 ret
= stat(device_name
,&s
);
433 perr("/dev/%s (device node)", device_name
);
437 if (!S_ISCHR(s
.st_mode
)) {
440 err("%s is not a TTY character device.", device_name
);
444 dbg("%s has a device node", device_name
);
446 ret
= access(device_name
, R_OK
| W_OK
);
448 perr("%s: Not writable?", device_name
);
452 ret
= open(device_name
, O_RDWR
| O_NONBLOCK
);
454 perr("Could not open %s");
466 static int setup_serial_device(int dev_fd
)
471 ret
= tcgetattr(dev_fd
,&t
);
476 cfsetispeed(&t
, B115200
);
477 cfsetospeed(&t
, B115200
);
478 tcflush(dev_fd
, TCIFLUSH
);
482 ret
= tcsetattr(dev_fd
, TCSANOW
,&t
);
485 perr("setting terminal attributes");
493 static int wu_write(int fd
, struct wu_packet
* p
)
500 memset(p
->buf
, 0, sizeof(p
->buf
));
501 n
= sprintf(p
->buf
, "#%c,%c,%d", p
->cmd
, p
->sub_cmd
, p
->count
);
505 for (i
= 0; i
< p
->count
; i
++) {
506 if ((p
->len
+ strlen(p
->field
[i
]) + 4)>= sizeof(p
->buf
)) {
507 err("Overflowed command string");
508 return ret_err(EOVERFLOW
);
510 n
= sprintf(s
, ",%s", p
->field
[i
]);
514 p
->buf
[p
->len
++] = ';';
516 dbg("Writing '%s' (strlen = %d) (len = %d) to device",
517 p
->buf
, strlen(p
->buf
), p
->len
);
518 ret
= write(fd
, p
->buf
, p
->len
);
520 perr("Writing to device");
522 return ret
>= 0 ? 0 : ret
;
526 static void dump_packet(struct wu_packet
* p
)
530 dbg("Packet - Command '%c' %d parameters", p
->cmd
, p
->count
);
532 for (i
= 0; i
< p
->count
; i
++)
533 dbg("[%2d] [%20s] = \"%s\"", i
, p
->label
[i
], p
->field
[i
]);
537 static int parse_packet(struct wu_packet
* p
)
542 p
->buf
[p
->len
] = '\0';
544 dbg("Parsing Packet, Raw buffer is (%d bytes) [%s]",
550 * First character should be '#'
557 dbg("Invalid packet");
558 return ret_err(EFAULT
);
561 dbg("Invalid packet");
562 return ret_err(EFAULT
);
566 * Command character is first
568 next
= strchr(s
, ',');
573 dbg("Invalid Command field [%s]", s
);
574 return ret_err(EFAULT
);
578 * Next character is the subcommand, and should be '-'
579 * Though, it doesn't matter, because we just
582 next
= strchr(s
, ',');
587 dbg("Invalid 2nd field");
588 return ret_err(EFAULT
);
592 * Next is the number of parameters,
593 * which should always be> 0.
595 next
= strchr(s
, ',');
601 dbg("Couldn't determine number of parameters");
602 return ret_err(EFAULT
);
605 dbg("Have %d parameter%s (cmd = '%c')",
606 p
->count
, p
->count
> 1 ? "s" : "", p
->cmd
);
609 * Now, we loop over the rest of the string,
610 * storing a pointer to each in p->field[].
612 * The last character was originally a ';', but may have been
613 * overwritten with a '\0', so we make sure to catch
614 * that when converting the last parameter.
616 for (i
= 0; i
< p
->count
; i
++) {
617 next
= strpbrk(s
, ",;");
621 if (i
< (p
->count
- 1)) {
622 dbg("Malformed parameter string [%s]", s
);
623 return ret_err(EFAULT
);
628 * Skip leading white space in fields
640 static int wu_read(int fd
, struct wu_packet
* p
)
652 ret
= select(fd
+ 1,&read_fd
, NULL
, NULL
,&tv
);
654 perr("select on terminal device");
658 ret
= read(fd
, p
->buf
, wu_strlen
);
660 perr("Reading from device");
665 dbg("Device timed out while reading");
666 return ret_err(ETIME
);
668 return parse_packet(p
);
672 static int wu_show_header(int fd
)
674 struct wu_packet p
= {
679 [0] = "watts header",
680 [1] = "volts header",
684 [5] = "mo. kWh header",
685 [6] = "mo. cost header",
686 [7] = "max watts header",
687 [8] = "max volts header",
688 [9] = "max amps header",
689 [10] = "min watts header",
690 [11] = "min volts header",
691 [12] = "min amps header",
692 [13] = "power factor header",
693 [14] = "duty cycle header",
694 [15] = "power cycle header",
699 ret
= wu_write(fd
,&p
);
701 perr("Requesting header strings");
706 ret
= wu_read(fd
,&p
);
708 perr("Reading header strings");
712 print_packet(&p
, "Header Record");
718 static int wu_show_cal(int fd
)
720 struct wu_packet p
= {
726 [1] = "sample count",
732 [7] = "low amps gain",
733 [8] = "low amps bias",
734 [9] = "low amps offset",
736 [11] = "watts offset",
737 [12] = "low watts gain",
738 [13] = "low watts offset",
743 ret
= wu_write(fd
,&p
);
745 perr("Requesting calibration parameters");
750 ret
= wu_read(fd
,&p
);
752 perr("Reading header strings");
755 print_packet(&p
, "Calibration Settings");
760 static int wu_start_log(void)
762 struct wu_packet p
= {
777 ret
= wu_write(wu_fd
,&p
);
781 perr("Starting External Logging");
787 static int wu_stop_log(void)
789 struct wu_packet p
= {
801 * Stop logging and read time stamp.
803 ret
= wu_write(wu_fd
,&p
);
805 perr("Stopping External Logging");
810 ret
= wu_read(wu_fd
,&p
);
812 perr("Reading final time stamp");
816 print_packet(&p
, "Final Time Stamp and Interval");
820 static int filter_data(struct wu_packet
* p
, int i
, char * buf
)
822 if (i
< wu_num_fields
) {
823 if (wu_fields
[i
].enable
) {
824 double val
= strtod(p
->field
[i
], NULL
);
825 snprintf(buf
, 256, "%.1f", val
/ 10.0);
832 static int wu_clear(int fd
)
834 struct wu_packet p
= {
844 ret
= wu_write(fd
,&p
);
846 perr("Clearing memory");
858 static int wu_read_data(int fd
)
860 struct wu_packet p
= {
875 [13] = "power factor",
877 [15] = "power cycle",
885 static const int wu_max_retry
= 2;
890 ret
= wu_read(fd
,&p
);
892 if (++retry
< wu_max_retry
) {
893 dbg("Bad record back, retrying\n");
896 } else if (retry
== wu_max_retry
) {
897 dbg("Still couldn't get a good record, resetting\n");
905 perr("Blech. Giving up on read");
910 dbg("[%d] ", num_read
);
912 print_packet_filter(&p
, filter_data
);
914 if (wu_count
&& (++i
== wu_count
))
924 static int wu_show_interval(int fd
)
926 struct wu_packet p
= {
937 ret
= wu_write(fd
,&p
);
939 perr("Requesting interval");
944 ret
= wu_read(fd
,&p
);
946 perr("Reading interval");
949 print_packet(&p
, "Interval Settings");
954 static int wu_write_interval(int fd
, unsigned int seconds
,
955 unsigned int interval
)
957 char str_seconds
[wu_param_len
];
958 char str_interval
[wu_param_len
];
959 struct wu_packet p
= {
970 snprintf(str_seconds
, wu_param_len
, "%ud", seconds
);
971 snprintf(str_interval
, wu_param_len
, "%ud", interval
);
973 ret
= wu_write(fd
,&p
);
975 perr("Setting Sampling Interval");
982 static int wu_store_interval(int fd
)
984 char * s
= wu_option_value(wu_option_interval
);
987 wu_interval
= strtol(s
,&end
, 0);
989 err("Invalid interval: %s", s
);
990 return ret_err(EINVAL
);
992 return wu_write_interval(fd
, 1, wu_interval
);
995 static int wu_show_mode(int fd
)
997 struct wu_packet p
= {
1002 [0] = "display mode",
1007 ret
= wu_write(fd
,&p
);
1009 perr("Requesting device display mode");
1013 ret
= wu_read(fd
,&p
);
1015 perr("Reaing device display mode");
1022 static int wu_write_mode(int fd
, int mode
)
1024 char str_mode
[wu_param_len
];
1025 struct wu_packet p
= {
1035 snprintf(str_mode
, wu_param_len
, "%ud", mode
);
1036 ret
= wu_write(fd
,&p
);
1038 perr("Setting device display mode");
1044 static int wu_store_mode(int fd
)
1046 char * s
= wu_option_value(wu_option_mode
);
1050 mode
= strtol(s
,&end
, 0);
1052 err("Invalid mode: %s", s
);
1053 return ret_err(EINVAL
);
1055 return wu_write_mode(fd
, mode
);
1060 static int wu_show_user(int fd
)
1062 struct wu_packet p
= {
1067 [0] = "cost per kWh",
1068 [1] = "2nd tier cost",
1069 [2] = "2nd tier threshold",
1070 [3] = "duty cycle threshold",
1075 ret
= wu_write(fd
,&p
);
1077 perr("Requesting user parameters");
1082 ret
= wu_read(fd
,&p
);
1084 perr("Reading user parameters");
1087 print_packet(&p
, "User Settings");
1092 static int wu_write_user(int fd
, unsigned int kwh_cost
,
1093 unsigned int second_tier_cost
,
1094 unsigned int second_tier_threshold
,
1095 unsigned int duty_cycle_threshold
)
1097 char str_kwh_cost
[wu_param_len
];
1098 char str_2nd_tier_cost
[wu_param_len
];
1099 char str_2nd_tier_threshold
[wu_param_len
];
1100 char str_duty_cycle_threshold
[wu_param_len
];
1102 struct wu_packet p
= {
1108 [1] = str_2nd_tier_cost
,
1109 [2] = str_2nd_tier_threshold
,
1110 [3] = str_duty_cycle_threshold
,
1115 snprintf(str_kwh_cost
, wu_param_len
, "%ud", kwh_cost
);
1116 snprintf(str_2nd_tier_cost
, wu_param_len
, "%ud",
1118 snprintf(str_2nd_tier_threshold
, wu_param_len
, "%ud",
1119 second_tier_threshold
);
1120 snprintf(str_duty_cycle_threshold
, wu_param_len
, "%ud",
1121 duty_cycle_threshold
);
1123 ret
= wu_write(fd
,&p
);
1125 perr("Writing user parameters");
1131 static int wu_store_user(int fd
)
1133 unsigned int kwh_cost
;
1134 unsigned int second_tier_cost
;
1135 unsigned int second_tier_threshold
;
1136 unsigned int duty_cycle_threshold
;
1137 char * buf
= wu_option_value(wu_option_user
);
1142 err("No user parameters?");
1143 return ret_err(EINVAL
);
1146 kwh_cost
= strtoul(s
,&next
, 0);
1148 err("Incomplete user parameters");
1149 return ret_err(EINVAL
);
1153 while (s
&& !isdigit(*s
))
1156 err("Incomplete user parameters");
1157 return ret_err(EINVAL
);
1161 second_tier_cost
= strtoul(s
,&next
, 0);
1163 err("Incomplete user parameters");
1164 return ret_err(EINVAL
);
1168 while (s
&& !isdigit(*s
))
1171 err("Incomplete user parameters");
1172 return ret_err(EINVAL
);
1176 second_tier_threshold
= strtoul(s
,&next
, 0);
1178 err("Incomplete user parameters");
1179 return ret_err(EINVAL
);
1183 while (s
&& !isdigit(*s
))
1186 err("Incomplete user parameters");
1187 return ret_err(EINVAL
);
1191 duty_cycle_threshold
= strtoul(s
,&next
, 0);
1193 err("Incomplete user parameters");
1194 return ret_err(EINVAL
);
1198 while (s
&& !isdigit(*s
))
1201 err("Incomplete user parameters");
1202 return ret_err(EINVAL
);
1205 return wu_write_user(fd
, kwh_cost
, second_tier_cost
,
1206 second_tier_threshold
, duty_cycle_threshold
);
1210 static void enable_field(char * name
)
1214 for (i
= 0; i
< wu_num_fields
; i
++) {
1215 if (!strcasecmp(wu_fields
[i
].name
, name
)) {
1216 wu_fields
[i
].enable
= 1;
1222 static void enable_all_fields(void)
1226 for (i
= 0; i
< wu_num_fields
; i
++)
1227 wu_fields
[i
].enable
= 1;
1232 static int wu_show_help(int);
1233 static int wu_show_version(int);
1237 static int wu_store_count(int unused
)
1239 char * s
= wu_option_value(wu_option_count
);
1243 wu_count
= strtol(s
,&end
, 0);
1245 err("Bad count field");
1246 return ret_err(EINVAL
);
1252 static int wu_store_debug(int unused
)
1258 static int wu_store_delim(int unused
)
1260 char * s
= wu_option_value(wu_option_delim
);
1267 static int wu_store_final(int unused
)
1273 static int wu_store_label(int unused
)
1279 static int wu_store_newline(int unused
)
1285 static int wu_store_suppress(int unused
)
1291 static int wu_store_localtime(int unused
)
1297 static int wu_store_gmtime(int unused
)
1303 static int wu_store_info_all(int unused
)
1309 static int wu_store_no_data(int unused
)
1315 static int wu_store_set_only(int unused
)
1323 * wu_options - command line options and their associated flags
1326 static struct wu_options wu_options
[] = {
1331 [wu_option_help
] = {
1335 .descr
= "Display help text and exit",
1336 .show
= wu_show_help
,
1339 [wu_option_version
] = {
1340 .longopt
= "version",
1343 .descr
= "Display version information and exit",
1344 .show
= wu_show_version
,
1348 * Modifies the output for all other options
1350 [wu_option_debug
] = {
1354 .descr
= "Print out debugging messages",
1355 .store
= wu_store_debug
,
1359 * For data reading..
1361 [wu_option_count
] = {
1365 .descr
= "Specify number of data samples",
1367 .store
= wu_store_count
,
1370 [wu_option_final
] = {
1374 .descr
= "Print final interval information",
1375 .store
= wu_store_final
,
1379 * Modifies output for each option (most relevant for data)
1381 [wu_option_delim
] = {
1385 .descr
= "Set field delimiter (default \", \")",
1387 .store
= wu_store_delim
,
1390 [wu_option_newline
] = {
1391 .longopt
= "newline",
1394 .descr
= "Use '\\n' as delimter instead",
1395 .store
= wu_store_newline
,
1398 [wu_option_localtime
] = {
1399 .longopt
= "localtime",
1402 .descr
= "Print localtime with each data reading",
1403 .store
= wu_store_localtime
,
1406 [wu_option_gmtime
] = {
1407 .longopt
= "gmtime",
1410 .descr
= "Print GMT time with each data reading",
1411 .store
= wu_store_gmtime
,
1414 [wu_option_label
] = {
1418 .descr
= "Show labels of each field",
1419 .store
= wu_store_label
,
1423 * Relevant for each of the fields below
1425 [wu_option_suppress
] = {
1426 .longopt
= "suppress",
1429 .descr
= "Suppress printing of the field description",
1430 .store
= wu_store_suppress
,
1434 * These options print values from the device and exit.
1437 .longopt
= "calibrate",
1440 .descr
= "Print calibration parameters",
1441 .show
= wu_show_cal
,
1444 [wu_option_header
] = {
1445 .longopt
= "header",
1448 .descr
= "Print data field names (as read from device)",
1449 .show
= wu_show_header
,
1453 * These options have an optional parameter.
1454 * W/o that parameter, they print values from the device.
1455 * W/ that parameter, they set that option and read data.
1457 * Except when the 'set-only' parameter is used, then the
1458 * parameters are set, then re-read and printed.
1460 [wu_option_interval
] = {
1461 .longopt
= "interval",
1464 .descr
= "Get/Set sampling interval",
1466 .show
= wu_show_interval
,
1467 .store
= wu_store_interval
,
1470 [wu_option_mode
] = {
1474 .descr
= "Get/Set display mode",
1476 .show
= wu_show_mode
,
1477 .store
= wu_store_mode
,
1480 [wu_option_user
] = {
1484 .descr
= "Get/Set user parameters",
1486 .format
= "<cost per kwh>,<2nd tier cost>,"
1487 "<2nd tier threshold>,"
1488 "<duty cycle threshold>",
1489 .show
= wu_show_user
,
1490 .store
= wu_store_user
,
1493 [wu_option_info_all
] = {
1494 .longopt
= "show-all",
1497 .descr
= "Show all device parameters",
1498 .store
= wu_store_info_all
,
1501 [wu_option_no_data
] = {
1502 .longopt
= "no-data",
1505 .descr
= "Don't read any data (just read device info)",
1506 .store
= wu_store_no_data
,
1509 [wu_option_set_only
] = {
1510 .longopt
= "set-only",
1513 .descr
= "Set parameters only (don't read them back)",
1514 .store
= wu_store_set_only
,
1518 #define wu_num_options ARRAY_SIZE(wu_options)
1520 static int wu_show_version(int unused
)
1522 printf("%s Version %s\n", prog_name
, wu_version
);
1526 static int wu_show_help(int unused
)
1531 wu_show_version(unused
);
1532 printf(" A program for interfacing with the Watts Up? Power Meter\n");
1535 printf("Usage: %s [<options> ... ]<device> [<values> ... ]\n",
1539 printf("<device> is the serial port the device is connected at.\n");
1542 printf("<options> are any of the following:\n");
1543 for (i
= 0; i
< wu_num_options
; i
++) {
1544 n
= printf(" -%c", wu_options
[i
].shortopt
);
1546 if (wu_options
[i
].param
== 0)
1548 else if (wu_options
[i
].param
== 1)
1549 n
= printf(" %s", wu_options
[i
].option
);
1550 else if (wu_options
[i
].param
== 2)
1551 n
= printf(" [%s]", wu_options
[i
].option
);
1553 n
+= printf("%*c| ", n
- 12, ' ');
1554 n
+= printf("--%s", wu_options
[i
].longopt
);
1556 if (wu_options
[i
].param
== 0)
1558 else if (wu_options
[i
].param
== 1)
1559 n
+= printf("=%s", wu_options
[i
].option
);
1560 else if (wu_options
[i
].param
== 2)
1561 n
+= printf("[=%s]", wu_options
[i
].option
);
1564 40 - n
, ' ', wu_options
[i
].descr
);
1567 printf("<value> specifies which of these to print out (default: ALL)\n");
1568 for (i
= 0; i
< wu_num_fields
; i
++) {
1569 printf("%12s -- %s\n", wu_fields
[i
].name
, wu_fields
[i
].descr
);
1577 static char * wu_option_value(unsigned int index
)
1579 return (index
< wu_num_options
) ? wu_options
[index
].value
: NULL
;
1583 static int wu_check_option_show(int index
)
1586 * Return 1 if we need to print something out for
1587 * a particular option.
1589 if (index
< wu_num_options
) {
1590 if (wu_options
[index
].flag
) {
1597 static int wu_check_option_store(int index
)
1600 * Return a 1 if this option is set.
1603 if (index
< wu_num_options
) {
1604 if (wu_options
[index
].flag
) {
1612 static int wu_show(int index
, int dev_fd
)
1614 if (wu_options
[index
].show
)
1615 return wu_options
[index
].show(dev_fd
);
1620 * Check if the option is set, and call its method if so.
1621 * Return whether or not we did anything..
1624 static int wu_check_show(int index
, int dev_fd
)
1626 if (wu_check_option_show(index
)) {
1627 wu_show(index
, dev_fd
);
1635 * Check if the option is set and if so, call it
1636 * Return the value from the ->store() method.
1639 static int wu_check_store(int index
, int dev_fd
)
1641 if (wu_check_option_store(index
)) {
1642 if (wu_options
[index
].store
)
1643 return wu_options
[index
].store(dev_fd
);
1649 static void make_longopt(struct option
* l
)
1653 for (i
= 0; i
< wu_num_options
; i
++) {
1654 l
[i
].name
= wu_options
[i
].longopt
;
1655 l
[i
].has_arg
= wu_options
[i
].param
;
1656 l
[i
].flag
=&wu_options
[i
].flag
;
1661 static void make_shortopt(char * str
)
1666 for (i
= 0; i
< wu_num_options
; i
++) {
1667 *s
++ = wu_options
[i
].shortopt
;
1668 if (wu_options
[i
].param
)
1669 *s
++ = wu_options
[i
].param
== 1 ? ':' : ';';
1673 static void enable_short_option(int c
, char * arg
)
1678 * Friggin' getopt_long() will return the
1679 * character if we get a short option (e.g. '-h'),
1680 * instead of returning 0 like it does when it
1681 * gets a long option (e.g. "--help"). Ugh.
1683 for (i
= 0; i
< wu_num_options
; i
++) {
1684 if (wu_options
[i
].shortopt
== c
) {
1685 wu_options
[i
].flag
= 1;
1687 wu_options
[i
].value
= strdup(arg
);
1693 static int parse_args(int argc
, char ** argv
)
1695 struct option longopts
[wu_num_options
+ 1] = { };
1696 char shortopts
[wu_num_options
* 2] = "";
1698 make_longopt(longopts
);
1699 make_shortopt(shortopts
);
1706 c
= getopt_long(argc
, argv
, shortopts
,
1713 wu_options
[index
].flag
= 1;
1715 wu_options
[index
].value
= strdup(optarg
);
1717 printf("long option: val = %c, optarg = %s\n",
1718 wu_options
[index
].shortopt
, optarg
);
1721 err("Bad parameter");
1722 return ret_err(EINVAL
);
1725 enable_short_option(c
, optarg
);
1731 * Check for help request now and bail after
1732 * printing it, if it's set.
1734 if (wu_check_show(wu_option_help
, 0))
1737 if (wu_check_show(wu_option_version
, 0))
1741 * Fields to print out
1746 wu_device
= argv
[optind
++];
1749 for (i
= optind
; i
< argc
; i
++)
1750 enable_field(argv
[i
]);
1752 enable_all_fields();
1755 wu_show(wu_option_help
, 0);
1756 return ret_err(EINVAL
);
1762 int main(int argc
, char ** argv
)
1767 ret
= parse_args(argc
, argv
);
1772 * Try to enable debugging early
1774 if ((ret
= wu_check_store(wu_option_debug
, 0)))
1777 ret
= open_device(wu_device
,&fd
);
1781 dbg("%s: Open for business", wu_device
);
1783 ret
= setup_serial_device(fd
);
1792 * Set delimeter before we print out any fields.
1794 if ((ret
= wu_check_store(wu_option_delim
, fd
)))
1798 * Ditto for 'label' and 'newline' flags.
1800 if ((ret
= wu_check_store(wu_option_label
, fd
)))
1803 if ((ret
= wu_check_store(wu_option_newline
, fd
)))
1806 if ((ret
= wu_check_store(wu_option_suppress
, fd
)))
1809 if ((ret
= wu_check_store(wu_option_localtime
, fd
)))
1812 if ((ret
= wu_check_store(wu_option_gmtime
, fd
)))
1815 if ((ret
= wu_check_store(wu_option_set_only
, fd
)))
1818 if ((ret
= wu_check_store(wu_option_no_data
, fd
)))
1821 if ((ret
= wu_check_store(wu_option_info_all
, fd
)))
1826 * Options to set device parameters.
1828 if ((ret
= wu_check_store(wu_option_interval
, fd
)))
1831 if ((ret
= wu_check_store(wu_option_mode
, fd
)))
1834 if ((ret
= wu_check_store(wu_option_user
, fd
)))
1838 * Check for options to print device info
1841 wu_show(wu_option_cal
, fd
);
1842 wu_show(wu_option_header
, fd
);
1843 wu_show(wu_option_interval
, fd
);
1844 wu_show(wu_option_mode
, fd
);
1845 wu_show(wu_option_user
, fd
);
1847 wu_check_show(wu_option_cal
, fd
);
1848 wu_check_show(wu_option_header
, fd
);
1851 wu_check_show(wu_option_interval
, fd
);
1852 wu_check_show(wu_option_mode
, fd
);
1853 wu_check_show(wu_option_user
, fd
);
1859 if ((ret
= wu_check_store(wu_option_count
, fd
)))
1862 if ((ret
= wu_check_store(wu_option_final
, fd
)))
1865 if ((ret
= wu_start_log()))