From 23892620b51762521f683b63cbb758f6d036c24d Mon Sep 17 00:00:00 2001 From: Michael Gernoth Date: Sat, 18 May 2013 21:26:04 +0200 Subject: [PATCH] commandline parsing --- fs20pcs.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 247 insertions(+), 8 deletions(-) diff --git a/fs20pcs.c b/fs20pcs.c index 2a4ec37..c149392 100644 --- a/fs20pcs.c +++ b/fs20pcs.c @@ -10,6 +10,8 @@ #define ID_VENDOR 0x18ef #define ID_PRODUCT 0xe015 +extern char *optarg; + /* Not in all libusb-1.0 versions, so we have to roll our own :-( */ static char * usb_strerror(int e) { @@ -137,7 +139,7 @@ int fs20pcs_send(libusb_device_handle *devh, unsigned char* send_data) printf("Success"); break; case 0x01: - printf("Firmware V%d.%d", ((recv_data[4] & 0xf0) >> 4) & 0x0f, recv_data[4] & 0x0f); + printf("Firmware: V%d.%d", ((recv_data[4] & 0xf0) >> 4) & 0x0f, recv_data[4] & 0x0f); break; case 0x02: printf("Unknown command"); @@ -164,21 +166,258 @@ int fs20pcs_send(libusb_device_handle *devh, unsigned char* send_data) return ret; } +unsigned char *parse_housecode(char *hc) +{ + static unsigned char housecode[2]; + char hc_fixed[9]; + char *ep; + unsigned long val; + int i; + + if (hc == NULL) + return NULL; + + memset(housecode, 0, sizeof(housecode)); + + switch(strlen(hc)) { + case 6: + if (strncmp(hc, "0x", 2)) { + fprintf(stderr, "Not a 2 byte hexstring: %s\n", hc); + return NULL; + } + case 4: + val = strtoul(hc, &ep, 16); + if (*ep != '\0') { + fprintf(stderr, "Not a 2 byte hexstring: %s\n", hc); + return NULL; + } + break; + case 8: + memset(hc_fixed, 0, sizeof(hc_fixed)); + for (i = 0; i < 8; i++) { + if ((hc[i] < '1') || (hc[i] > '4')) { + fprintf(stderr, "Not a valid ELV housecode: %s\n", hc); + return NULL; + } + hc_fixed[i] = hc[i] - 1; + val = strtoul(hc_fixed, &ep, 4); + + if (*ep != '\0') { + fprintf(stderr, "Can't parse fixed ELV housecode: %s\n", hc_fixed); + return NULL; + } + } + break; + default: + fprintf(stderr, "Housecode has to be 4 or 8 chars long!\n"); + return NULL; + break; + } + + housecode[0] = (val & 0xff00) >> 8; + housecode[1] = (val & 0xff); + + return housecode; +} + +void syntax(char *prog) +{ + fprintf(stderr, "Syntax: %s options\n\n", prog); + fprintf(stderr, "Possible options:\n"); + fprintf(stderr, "\t-V\t\trequest hardware-version\n"); + fprintf(stderr, "\t-x\t\tabort sending long press\n"); + fprintf(stderr, "\t-h [ELV|hex]\thousecode in ELV- or hex-notation\n"); + fprintf(stderr, "The following actions need an housecode:\n"); + fprintf(stderr, "\t-a n\t\tsend commands to device at address n\n"); + fprintf(stderr, "\t-s hex\t\tsend command byte\n"); + fprintf(stderr, "\t-e hex\t\textension byte for command\n"); + fprintf(stderr, "\t-r n\t\trepeat sending n times\n"); + fprintf(stderr, "\nCommand bytes (without extension byte):\n"); + fprintf(stderr, "0x00\t\tswitch off\n"); + fprintf(stderr, "0x01-0x10\tswitch on dimmed (0x01: 6.25%%, 0x02: 12.5%%, ..., 0x10: 100%%)\n"); + fprintf(stderr, "0x11\t\tswitch on\n"); + fprintf(stderr, "0x12\t\ttoggle\n"); + fprintf(stderr, "0x13\t\tdimup\n"); + fprintf(stderr, "0x14\t\tdimdown\n"); + fprintf(stderr, "0x15\t\tdimup, pause, dimdown, pause, ...\n"); + fprintf(stderr, "0x16\t\tstart/stop programming internal timer\n"); + fprintf(stderr, "0x17\t\tlearn housecode/address\n"); + fprintf(stderr, "0x18\t\toff for internal timer, then back on with current level\n"); + fprintf(stderr, "0x19\t\ton (100%%) for internal timer, then off\n"); + fprintf(stderr, "0x1a\t\ton (old level) for internal timer, then off\n"); + fprintf(stderr, "0x1b\t\tfactory reset\n"); + fprintf(stderr, "0x1e\t\ton (100%%) for internal timer, then old level\n"); + fprintf(stderr, "0x1f\t\ton (old level) for internal timer, then old state\n"); + fprintf(stderr, "\nCommand bytes (with timer as extension byte):\n"); + fprintf(stderr, "0x20\t\tdim down to off while timer is running\n"); + fprintf(stderr, "0x21-0x30\tdim to (0x01: 6.25%%, 0x02: 12.5%%, ..., 0x10: 100%%) while timer is running\n"); + fprintf(stderr, "0x31\t\tdim to last level while timer is running\n"); + fprintf(stderr, "0x32\t\tdim to off, then after timer dim to off\n"); + fprintf(stderr, "0x33\t\tdimup now and switch off after timer\n"); + fprintf(stderr, "0x34\t\tdimdown now and switch off after timer\n"); + fprintf(stderr, "0x35\t\tdimup or dimdown (toggle) and switch off after timer\n"); + fprintf(stderr, "0x36\t\tprogram internal timer\n"); + fprintf(stderr, "0x38\t\toff for timer, then back on with current level\n"); + fprintf(stderr, "0x39\t\ton (100%%) for timer, then off\n"); + fprintf(stderr, "0x3a\t\ton (old level) for timer, then off\n"); + fprintf(stderr, "0x3c\t\tprogram internal ramp-up-time\n"); + fprintf(stderr, "0x3d\t\tprogram internal ramp-down-time\n"); + fprintf(stderr, "0x3e\t\ton (100%%) for timer, then old level\n"); + fprintf(stderr, "0x3f\t\ton (old level) for timer, then old state\n"); +}; + +enum { + NO_ACTION, + REQUEST_FIRMWARE, + SEND_COMMAND, + ABORT_LONG_PRESS +}; + +#define DUPLICATE_ACTION if (action != NO_ACTION) { \ + fprintf(stderr, "duplicate action specified!\n"); \ + exit(EXIT_FAILURE); } + int main(int argc, char **argv) { unsigned char send_data[11]; + unsigned char *housecode = NULL; libusb_device_handle *devh = NULL; + char *ep; int err; - int i; + int opt; + int action = NO_ACTION; + uint8_t command = 0x00; + uint8_t extension = 0x00; + uint8_t repeat = 0; + int addr = -1; - if ((argc < 2) || (argc > 12)) { - fprintf(stderr, "Invalid number of parameters!\n"); - return EXIT_FAILURE; + memset(send_data, 0, sizeof(send_data)); + + send_data[0] = 0x01; + + while ((opt = getopt(argc, argv, "Vxs:h:a:r:e:")) != -1) { + switch(opt) { + case 'V': + DUPLICATE_ACTION; + action = REQUEST_FIRMWARE; + break; + case 'x': + DUPLICATE_ACTION; + action = ABORT_LONG_PRESS; + break; + case 's': + DUPLICATE_ACTION; + action = SEND_COMMAND; + + command = strtoul(optarg, &ep, 16); + if (*ep != '\0') { + fprintf(stderr, "Can't parse command!\n"); + exit(EXIT_FAILURE); + } +#ifdef DEBUG + printf("Got command: %d\n", command); +#endif + break; + case 'h': + housecode = parse_housecode(optarg); + if (!housecode) { + fprintf(stderr, "Can't parse housecode!\n"); + exit(EXIT_FAILURE); + } +#ifdef DEBUG + printf("Got housecode: 0x%02x%02x\n", housecode[0], housecode[1]); +#endif + break; + case 'a': + addr = strtoul(optarg, &ep, 10); + if (*ep != '\0') { + fprintf(stderr, "Can't parse address!\n"); + exit(EXIT_FAILURE); + } +#ifdef DEBUG + printf("Got address: 0x%02x\n", addr); +#endif + break; + case 'r': + repeat = strtoul(optarg, &ep, 10); + if (*ep != '\0') { + fprintf(stderr, "Can't parse repeat!\n"); + exit(EXIT_FAILURE); + } +#ifdef DEBUG + printf("Got repeat: %d\n", repeat); +#endif + break; + case 'e': + extension = strtoul(optarg, &ep, 16); + if (*ep != '\0') { + fprintf(stderr, "Can't parse extension!\n"); + exit(EXIT_FAILURE); + } +#ifdef DEBUG + printf("Got extension: %d\n", extension); +#endif + break; + case ':': + case '?': + default: + syntax(argv[0]); + exit(EXIT_FAILURE); + break; + } } - memset(send_data, 0, sizeof(send_data)); - for (i = 0; i < argc - 1; i++) { - send_data[i] = strtoul(argv[i+1], NULL, 16); + switch(action) { + case REQUEST_FIRMWARE: + send_data[1] = 0x01; + send_data[2] = 0xf0; + printf("Requesting firmware version...\n"); + + break; + case ABORT_LONG_PRESS: + send_data[1] = 0x01; + send_data[2] = 0xf3; + printf("Aborting long press...\n"); + + break; + case SEND_COMMAND: + if (housecode == NULL) { + fprintf(stderr, "housecode needed!\n"); + exit(EXIT_FAILURE); + } + if (addr == -1) { + fprintf(stderr, "address needed!\n"); + exit(EXIT_FAILURE); + } + + if (repeat) { + send_data[1] = 0x07; + send_data[2] = 0xf2; + send_data[8] = repeat; + printf("Sending 0x%02x 0x%02x to address %d (hc: 0x%02x%02x) (repeated %d times)\n", + command, extension, addr, + housecode[0], housecode[1], + repeat); + } else { + send_data[1] = 0x06; + send_data[2] = 0xf1; + printf("Sending 0x%02x 0x%02x to address %d (hc: 0x%02x%02x)\n", + command, extension, addr, + housecode[0], housecode[1]); + } + send_data[3] = housecode[0]; + send_data[4] = housecode[1]; + send_data[5] = addr; + send_data[6] = command; + send_data[7] = extension; + + break; + case NO_ACTION: + default: + fprintf(stderr, "No action specified!\n\n"); + syntax(argv[0]); + exit(EXIT_FAILURE); + break; } err = libusb_init(NULL); -- 2.39.2