libfn/fnctl.c
2010-10-31 22:07:24 +01:00

290 lines
6.2 KiB
C

#include <stdio.h> /* Standard input/output definitions */
#include <termios.h>
#include <fcntl.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#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;
}