#include /* Standard input/output definitions */ #include #include #include #include #include #include #include #include "libfn.h" typedef struct { char * name; char * description; uint8_t cmd; } command_t; static command_t commands[] = { {"fade", "set color/fade to color", REMOTE_CMD_FADE_RGB}, {"save", "save color to EEPROM", REMOTE_CMD_SAVE_RGB}, {"modify", "modify current color", REMOTE_CMD_MODIFY_CURRENT}, {"stop", "stop color changing", REMOTE_CMD_STOP}, {"start", "start program", REMOTE_CMD_START_PROGRAM}, {"powerdown", "power down the device", REMOTE_CMD_POWERDOWN}, {"config", "configure startup & offsets", REMOTE_CMD_CONFIG_OFFSETS}, {"reset", "reset fnordlichter", REMOTE_CMD_BOOTLOADER}, {0, 0} /* stop condition for iterator */ }; static struct option long_options[] = { {"delay", required_argument, 0, 'd'}, {"step", required_argument, 0, 's'}, {"address", required_argument, 0, 'a'}, {"mask", required_argument, 0, 'm'}, {"slot", required_argument, 0, 't'}, {"pause", required_argument, 0, 'p'}, {"color", required_argument, 0, 'c'}, {"help", required_argument, 0, 'h'}, {"port", required_argument, 0, 'P'}, {"host", required_argument, 0, 'H'}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0} /* stop condition for iterator */ }; void print_cmd(struct remote_msg_t * msg) { printf("sending: "); int i; for (i = 0; i < REMOTE_MSG_LEN; i++) { printf("%X", *((uint8_t *) msg+i)); } printf("\n"); } void usage(char ** argv) { printf("usage: %s command [options]\n\n", argv[0]); printf(" following commands are available:\n"); command_t * cp = commands; while (cp->name) { printf("\t%s%s%s\n", cp->name, (strlen(cp->name) < 7) ? "\t\t" : "\t", cp->description); cp++; } printf("\n"); printf(" following options are available\n"); struct option * op = long_options; while (op->name) { printf("\t--%s,%s-%c\n", op->name, (strlen(op->name) < 5) ? "\t\t" : "\t", op->val); op++; } } struct rgb_color_t parse_color(char * color_def) { struct rgb_color_t color; if (strlen(color_def) != 6) fprintf(stderr, "invalid color definition: %s", color_def); sscanf(color_def, "%2x%2x%2x", (unsigned int *) (&color.red), (unsigned int *) (&color.green), (unsigned int *) (&color.blue)); return color; } int main(int argc, char ** argv) { /* options */ uint8_t address = 255; uint8_t step = 255; uint8_t slot = 0; uint8_t delay = 0; uint8_t pause = 0; char host[255]; char port[255] = "7970"; int verbose; struct rgb_color_t color; struct remote_msg_t msg; memset(&msg, 0, sizeof msg); /* connection */ int fd; struct addrinfo hints, *res; struct termios oldtio; /* parse command */ if (argc <= 1) { fprintf(stderr, "command required\n"); usage(argv); exit(-1); } command_t * cp = commands; while (cp->name && strcmp(cp->name, argv[1]) != 0) { cp++; } /* parse cli arguments */ while (1) { /* getopt_long stores the option index here. */ int option_index = 0; int c = getopt_long(argc, argv, "hva:m:d:s:d:p:c:P:H:", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; switch (c) { case 'a': address = atoi(optarg); break; case 'm': fprintf(stderr, "not yet implemented\n"); exit(-1); break; case 's': step = atoi(optarg); break; case 'd': delay = atoi(optarg); break; case 't': slot = atoi(optarg); break; case 'p': pause = atoi(optarg); break; case 'c': color = parse_color(optarg); break; case 'H': { char * ps = strrchr(optarg, ':'); if (ps) { /* with port: "localhost:1234" */ strcpy(port, optarg + 1); strncpy(host, optarg, ps - optarg); } else { /* without port */ strcpy(host, optarg); } } memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; /* both IPv4 & IPv6 */ hints.ai_socktype = SOCK_STREAM; getaddrinfo(host, port, &hints, &res); fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); connect(fd, res->ai_addr, res->ai_addrlen); if (fd < 0) { perror(port); exit(-1); } fn_sync(fd); usleep(200000); break; case 'P': fd = open(optarg, O_RDWR | O_NOCTTY); if (fd < 0) { perror(optarg); exit(-1); } oldtio = fn_init(fd); break; case 'v': verbose = 1; break; case 'h': case '?': usage(argv); exit((c == '?') ? -1 : 0); } } /* check address */ if (strlen(host) == 0 && address != 255 && address > fn_count_devices(fd)) { fprintf(stderr, "device with address %d not found\n", address); exit(-1); } if (verbose) { printf("command: %s: %s\n", cp->name, cp->description); printf("port: %s\n", port); printf("host: %s\n", host); printf("address: %d\n", address); printf("found %d fnordlichts\n", fn_count_devices(fd)); } switch (cp->cmd) { case REMOTE_CMD_FADE_RGB: { struct remote_msg_fade_rgb_t * param = (void *) &msg; param->step = step; param->delay = delay; param->color = color; } break; case REMOTE_CMD_MODIFY_CURRENT: { struct remote_msg_modify_current_t * param = (void *) &msg; struct rgb_color_offset_t ofs = {50,50,50}; param->step = step; param->delay = delay; param->rgb = ofs; } break; case REMOTE_CMD_SAVE_RGB: { struct remote_msg_save_rgb_t * param = (void *) &msg; param->slot = slot; param->step = step; param->delay = delay; param->pause = pause; param->color = color; } break; case REMOTE_CMD_START_PROGRAM: { struct remote_msg_start_program_t * param = (void *) &msg; } break; case REMOTE_CMD_STOP: { struct remote_msg_stop_t * param = (void *) &msg; } break; case REMOTE_CMD_POWERDOWN: case REMOTE_CMD_BOOTLOADER: break; default: fprintf(stderr, "unknown subcomand: %s\n", argv[1]); usage(argv); exit(-1); } msg.address = address; msg.cmd = cp->cmd; int i = fn_send(fd, &msg); if (i < 0) fprintf(stderr, "failed on writing %d bytes to fnordlichts", REMOTE_MSG_LEN); if (verbose) { print_cmd(&msg); } if (strlen(host) == 0) { /* reset port to old state */ tcsetattr(fd, TCSANOW, &oldtio); } return 0; }