298 lines
7.8 KiB
C
298 lines
7.8 KiB
C
/*
|
|
* lw12ctl.c
|
|
* Copyright (C) 2017 jpk <jpk@thor>
|
|
*
|
|
* Distributed under terms of the MIT license.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <pwd.h>
|
|
|
|
#include <readline/readline.h>
|
|
#include <readline/history.h>
|
|
|
|
#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 <color> <value>\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 <color> <value>\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;
|
|
}
|