/* * lw12ctl.c * Copyright (C) 2017 jpk * * Distributed under terms of the MIT license. */ #include #include #include #include #include #include #include #include "lw12.h" #define DebugPrintPos fprintf(stderr, "%s:%d\n", __FILE__, __LINE__) struct config { char *host; int port; }; int exit_interactive_session = 0; int sockfd = 0; struct sockaddr_in server_addr; static void help_lw12_cmd_light() { printf("Not enough parameters, choices are:\n"); printf(" on\n"); printf(" off\n"); printf(" set \n\n"); printf("Color:\n------\nred\ngreen\nblue\nrgb\n\n" "The colors red, green and blue require one additional\n" "parameter as number between 0 - 255. The `rgb` value\n" "has to be given in #RRGGBB hex format.\n"); } static int lw12_cmd_light(int argc, char *argv[]) { if (argc == 0) { help_lw12_cmd_light(); return 1; } if (strncasecmp(argv[0], "on", strlen(argv[0])) == 0) { lw12_sendcmd(sockfd, &server_addr, (char *)LIGHTS_ON); lw12_sendcmd(sockfd, &server_addr, (char *)LIGHTS_INIT); } else if (strncasecmp(argv[0], "off", strlen(argv[0])) == 0) { lw12_sendcmd(sockfd, &server_addr, (char *)LIGHTS_OFF); } else if (strncasecmp(argv[0], "help", strlen(argv[0])) == 0) { help_lw12_cmd_light(); return 1; } else if (strncasecmp(argv[0], "set", strlen(argv[0])) == 0) { if (argc < 3) { printf("Not enough parameters, usage:\n" " - set \n\b"); return 1; } // todo set color unsigned char cmd[LW12_CMD_LENGTH]; // last char gets not copied?! strncpy((char *)cmd, LIGHT_COLOR, LW12_CMD_LENGTH); if (strncasecmp(argv[1], "red", strlen(argv[1])) == 0) { uint8_t colorvalue = (uint8_t)atoi(argv[2]); cmd[4] = (char)colorvalue; } else if (strncasecmp(argv[1], "green", strlen(argv[1])) == 0) { uint8_t colorvalue = (uint8_t)atoi(argv[2]); cmd[5] = (char)colorvalue; } else if (strncasecmp(argv[1], "blue", strlen(argv[1])) == 0) { uint8_t colorvalue = (uint8_t)atoi(argv[2]); cmd[6] = (char)colorvalue; } else if (strncasecmp(argv[1], "rgb", strlen(argv[1])) == 0) { if (strlen(argv[2]) != 7) { printf("Invalid RGB value. Example: #ff138a\n"); return 1; } char *pos = argv[2]; if (*pos == '#') pos++; int colorvalue = (int)strtol(pos, 0, 16); // exchange byte order to match RR GG BB colorvalue = (colorvalue & 0x000000ff) << 16 | (colorvalue & 0x00ff0000) >> 16 | (colorvalue & 0x0000ff00); memcpy(cmd+4, &colorvalue, 4); } else { printf("Unknown color selected, use: red, green or blue\n"); return 1; } // last char gets not copied?! cmd[LW12_CMD_LENGTH-1] = '\xef'; lw12_sendcmd(sockfd, &server_addr, (char *)cmd); } else { printf("What?!\n"); } return 0; } static int lw12_cmd_exit(int argc, char *argv[]) { exit_interactive_session = 1; return 0; } struct lw12_command { const char *cmd; int (*handler)(int argc, char *argv[]); const char *usage; }; static struct lw12_command lw12_commands[] = { {"light", lw12_cmd_light, "Control the LED stripe. Turn it on/off and change the colors" }, {"exit", lw12_cmd_exit, "Exit program"}, {"quit", lw12_cmd_exit, "Exit program"} }; int parse_commands(int argc, char *argv[]) { struct lw12_command *cmd, *match = NULL; int count = 0; int ret = 0; if (argc < 1) return 1; cmd = lw12_commands; while (cmd->cmd) { if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { match = cmd; // nessecary? if (strcasecmp(cmd->cmd, argv[0]) == 0) { count = 1; break; } count++; } cmd++; } if (count > 1) { printf("Ambiguous commnd '%s'; possible commands:", argv[0]); cmd = lw12_commands; while (cmd->cmd) { if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { printf(" %s", cmd->cmd); } cmd++; } printf("\n"); ret = 1; } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); ret = 1; } else { ret = match->handler(argc - 1, &argv[1]); } return ret; } void cmd_loop() { #define max_args 10 #define buf_size 256 char *cmd, *cmd_start; char *pos; char *argv[max_args]; int argc; do { cmd = readline("> "); if (cmd == NULL) break; add_history(cmd); cmd_start = pos = cmd; while (*pos != '\0') { // convert \n to separate argument if (*pos == '\n') { *pos = '\0'; break; } pos++; } argc = 0; pos = cmd; // count number of arguments for (;;) { // ignore spaces in the beginning while (*pos == ' ') pos++; if (*pos == '\0') break; argv[argc] = pos; argc++; if (argc == max_args) break; // string arguments if (*pos == '"') { char *pos2 = strrchr(pos, '"'); if (pos2) pos = pos2 + 1; } while (*pos != '\0' && *pos != ' ') pos++; if (*pos == ' ') *pos++ = '\0'; } parse_commands(argc, argv); free(cmd); } while (!exit_interactive_session); } int read_conf(const char *filename, struct config *conf){ FILE *fd; const size_t line_size = 300; char *line = (char *)malloc(line_size); char *start_pos, *pos; char *value = NULL; // set default conf->host = NULL; conf->port = 5000; // read config fd = fopen(filename, "r"); if (fd) { while (fgets(line, line_size, fd) != NULL) { pos = line; while (*pos == ' ') pos++; if (*pos == '#' || *pos == '\n') continue; start_pos = pos; while (*pos != '\0') { if (*pos == '\n') { *pos = '\0'; break; } pos++; } value = strrchr(start_pos, '='); start_pos[value - start_pos - 1] = '\0'; while (*value == ' ' || *value == '=') value++; if (strncasecmp(start_pos, "host", 4) == 0) { size_t param_len = strlen(value); conf->host = (char *)malloc(param_len); strncpy(conf->host, value, param_len); } else if (strncasecmp(start_pos, "port", 4) == 0) { conf->port = atoi(value); } } } free(line); return 0; } int main() { struct passwd *pw = getpwuid(getuid()); const char *homedir = pw->pw_dir; char confpath[510] = {}; struct config conf; strcat(confpath, homedir); strcat(confpath, "/.lw12rc"); read_conf(confpath, &conf); if (conf.host == NULL) { fprintf(stderr, "Option 'host' is missing or not set in config.\n"); return 1; } rl_bind_key('\t', rl_abort); lw12_connect(&sockfd, &server_addr, conf.port, conf.host); cmd_loop(); close(sockfd); // Clean config environment free(conf.host); return 0; }