298 lines
8.1 KiB
C
298 lines
8.1 KiB
C
|
// Note: I have 198 LEDs
|
||
|
// 0 - 118 front
|
||
|
// 119 - 197 back
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <usb.h>
|
||
|
#include <inttypes.h>
|
||
|
#include <string.h>
|
||
|
#include <glib.h>
|
||
|
|
||
|
#define USBDEV_SHARED_VENDOR 0x16C0 /* VOTI */
|
||
|
#define USBDEV_SHARED_PRODUCT 0x05dc /* Obdev's free shared PID */
|
||
|
#define PRODUCT_NAME "LED-Strip"
|
||
|
#define PRODUCT_MANFG "markus@notsyncing.net"
|
||
|
|
||
|
#define BLOCKSIZE 200
|
||
|
#define BLOCKCOUNT 12
|
||
|
|
||
|
#define CMD_PING 0
|
||
|
#define CMD_SWVERSION 1
|
||
|
#define CMD_EEWRITE 2
|
||
|
#define CMD_EEREAD 3
|
||
|
#define CMD_EEOPEN 4 // Can be used if errors occour while writing to the device.
|
||
|
#define CMD_RESET 5 // WDT RESET
|
||
|
#define CMD_SETBLOCK 9
|
||
|
#define CMD_SETLED 10
|
||
|
|
||
|
#define BLOCK_META_RENDER 254
|
||
|
|
||
|
struct shell_state {
|
||
|
int run;
|
||
|
int current_block;
|
||
|
};
|
||
|
|
||
|
struct command_list_struct {
|
||
|
char *regex;
|
||
|
char *help;
|
||
|
int (*funcPtr)(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
};
|
||
|
|
||
|
int command_help(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
int command_exit(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
int command_block(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
int command_set_led_single(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
int command_set_led_multi(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
int command_error(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info);
|
||
|
|
||
|
int set_block(struct usb_dev_handle *dev, int block);
|
||
|
int set_led(struct usb_dev_handle *dev, int block, int led, int r, int g, int b);
|
||
|
int set_templed(struct usb_dev_handle *dev, int block, int led, int r, int g, int b);
|
||
|
int cmd_set_led(struct usb_dev_handle *dev, int block, int led, int lede, int r, int g, int b);
|
||
|
|
||
|
struct command_list_struct command_list[] = {
|
||
|
{
|
||
|
.help = "block <block id>\tSelect the current block.",
|
||
|
.regex = "block (\\d*)",
|
||
|
.funcPtr = command_block
|
||
|
},
|
||
|
{
|
||
|
.help = "exit\tTerminate the program.",
|
||
|
.regex = "exit",
|
||
|
.funcPtr = command_exit
|
||
|
},
|
||
|
{
|
||
|
.help = "help\t Show this text.",
|
||
|
.regex = "help",
|
||
|
.funcPtr = command_help
|
||
|
},
|
||
|
{
|
||
|
.help = "tled <led-no> <R> <G> <B>\t Set the LED's RGB color temporarily.",
|
||
|
.regex = "(tled) (\\d*) (\\d*) (\\d*) (\\d*)",
|
||
|
.funcPtr = command_set_led_single
|
||
|
},
|
||
|
{
|
||
|
.help = "tled <led-range> <R> <G> <B>\t Set the color of multiple LEDs temporarily.",
|
||
|
.regex = "(tled) (\\d*)-(\\d*) (\\d*) (\\d*) (\\d*)",
|
||
|
.funcPtr = command_set_led_multi
|
||
|
},
|
||
|
{
|
||
|
.help = "led <led-no> <R> <G> <B>\t Set the LED's RGB color.",
|
||
|
.regex = "(led) (\\d*) (\\d*) (\\d*) (\\d*)",
|
||
|
.funcPtr = command_set_led_single
|
||
|
},
|
||
|
{
|
||
|
.help = "led <led-range> <R> <G> <B>\t Set the color of multiple LEDs.",
|
||
|
.regex = "(led) (\\d*)-(\\d*) (\\d*) (\\d*) (\\d*)",
|
||
|
.funcPtr = command_set_led_multi
|
||
|
},
|
||
|
{
|
||
|
.help = "",
|
||
|
.regex = ".*",
|
||
|
.funcPtr = command_error
|
||
|
},
|
||
|
{
|
||
|
.regex = NULL
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int command_error(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info)
|
||
|
{
|
||
|
printf("Command not found. Enter help to get a list of available commands.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int command_set_led_multi(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info) {
|
||
|
int led, lede;
|
||
|
int r, g, b;
|
||
|
int is_temp;
|
||
|
|
||
|
is_temp = strcmp(g_match_info_fetch(match_info, 1), "led");
|
||
|
led = atoi(g_match_info_fetch(match_info, 2));
|
||
|
lede = atoi(g_match_info_fetch(match_info, 3));
|
||
|
r = atoi(g_match_info_fetch(match_info, 4));
|
||
|
g = atoi(g_match_info_fetch(match_info, 5));
|
||
|
b = atoi(g_match_info_fetch(match_info, 6));
|
||
|
|
||
|
cmd_set_led(dev, is_temp ? BLOCK_META_RENDER : state->current_block, led, lede, r, g, b);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int command_set_led_single(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info)
|
||
|
{
|
||
|
int led;
|
||
|
int r, g, b;
|
||
|
int is_temp;
|
||
|
|
||
|
is_temp = strcmp(g_match_info_fetch(match_info, 1), "led");
|
||
|
led = atoi(g_match_info_fetch(match_info, 2));
|
||
|
r = atoi(g_match_info_fetch(match_info, 3));
|
||
|
g = atoi(g_match_info_fetch(match_info, 4));
|
||
|
b = atoi(g_match_info_fetch(match_info, 5));
|
||
|
|
||
|
cmd_set_led(dev, is_temp ? BLOCK_META_RENDER : state->current_block, led, led, r, g, b);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int cmd_set_led(struct usb_dev_handle *dev, int block, int led, int lede, int r, int g, int b)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (led < 0 || led >= BLOCKSIZE ||
|
||
|
lede < 0 || lede >= BLOCKSIZE) {
|
||
|
printf("ERROR: Valid LED numbers are 0 - %d.\n", BLOCKSIZE - 1);
|
||
|
} else if (r < 0 || r > 255 ||
|
||
|
g < 0 || g > 255 ||
|
||
|
b < 0 || b > 255) {
|
||
|
printf("ERROR: Valid colors are 0 - 255.\n");
|
||
|
} else {
|
||
|
for (i = led; i <= lede; i++) {
|
||
|
if (block == BLOCK_META_RENDER)
|
||
|
set_templed(dev, block, i, r, g, b);
|
||
|
else
|
||
|
set_led(dev, block, i, r, g, b);
|
||
|
}
|
||
|
set_block(dev, block);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int command_block(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info)
|
||
|
{
|
||
|
int block;
|
||
|
|
||
|
block = atoi(g_match_info_fetch(match_info, 1));
|
||
|
if (block >= 0 && block < BLOCKCOUNT) {
|
||
|
state->current_block = block;
|
||
|
set_block(dev, block);
|
||
|
} else {
|
||
|
printf("ERROR: Valid block numbers are 0 - 11.\n");
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int command_exit(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info)
|
||
|
{
|
||
|
state->run = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int command_help(struct usb_dev_handle *dev, struct shell_state *state, GMatchInfo *match_info)
|
||
|
{
|
||
|
struct command_list_struct *check_cmd;
|
||
|
|
||
|
printf("The following commands are available:\n");
|
||
|
for (check_cmd = command_list; check_cmd->funcPtr; check_cmd++) {
|
||
|
printf(" %s\n", check_cmd->help ? check_cmd->help : check_cmd->regex);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
GRegex *regex;
|
||
|
GMatchInfo *match_info;
|
||
|
|
||
|
struct usb_dev_handle *dev = NULL;
|
||
|
struct usb_bus *bus;
|
||
|
struct usb_device *devs;
|
||
|
char iMan[256]; // Manufacturer name
|
||
|
char iProd[256]; // Product name
|
||
|
char cmd[256];
|
||
|
struct shell_state state;
|
||
|
struct command_list_struct *check_cmd;
|
||
|
|
||
|
state.run = 1;
|
||
|
state.current_block = 0;
|
||
|
|
||
|
usb_init();
|
||
|
usb_set_debug(3);
|
||
|
usb_find_busses();
|
||
|
usb_find_devices();
|
||
|
|
||
|
for (bus = usb_busses; bus; bus = bus->next) {
|
||
|
for (devs = bus->devices; devs; devs = devs->next) {
|
||
|
if (devs->descriptor.idVendor == USBDEV_SHARED_VENDOR && devs->descriptor.idProduct == USBDEV_SHARED_PRODUCT) {
|
||
|
dev = usb_open(devs);
|
||
|
if (dev) {
|
||
|
usb_get_string_simple(dev,devs->descriptor.iManufacturer, iMan, sizeof(iMan));
|
||
|
usb_get_string_simple(dev,devs->descriptor.iProduct, iProd, sizeof(iProd));
|
||
|
if (strcmp(iProd, PRODUCT_NAME) || strcmp(iMan, PRODUCT_MANFG)) {
|
||
|
usb_close(dev);
|
||
|
dev = NULL;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (dev) break;
|
||
|
}
|
||
|
|
||
|
if (dev) {
|
||
|
printf("Opened device %s by %s!\n", iProd, iMan);
|
||
|
|
||
|
set_block(dev, state.current_block);
|
||
|
|
||
|
while (state.run) {
|
||
|
printf("%02d$ ", state.current_block);
|
||
|
fgets(cmd, sizeof(cmd), stdin);
|
||
|
|
||
|
for (check_cmd = command_list; check_cmd->funcPtr; check_cmd++) {
|
||
|
regex = g_regex_new(check_cmd->regex, G_REGEX_RAW, 0, NULL);
|
||
|
if (g_regex_match(regex, cmd, 0, &match_info) && g_match_info_matches(match_info)) {
|
||
|
check_cmd->funcPtr(dev, &state, match_info);
|
||
|
g_regex_unref(regex);
|
||
|
break;
|
||
|
}
|
||
|
g_regex_unref(regex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
usb_close(dev);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int set_block(struct usb_dev_handle *dev, int block)
|
||
|
{
|
||
|
if (usb_control_msg(dev,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
|
||
|
CMD_SETBLOCK, block, 0, NULL, 0, 5000) < 0)
|
||
|
return 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int set_led(struct usb_dev_handle *dev, int block, int led, int r, int g, int b)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
if (usb_control_msg(dev,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
|
||
|
CMD_EEWRITE, block * BLOCKSIZE * 3 + led * 3 + 0, r, NULL, 0, 5000) < 0)
|
||
|
return 0;
|
||
|
if (usb_control_msg(dev,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
|
||
|
CMD_EEWRITE, block * BLOCKSIZE * 3 + led * 3 + 1, g, NULL, 0, 5000) < 0)
|
||
|
return 0;
|
||
|
if (usb_control_msg(dev,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
|
||
|
CMD_EEWRITE, block * BLOCKSIZE * 3 + led * 3 + 2, b, NULL, 0, 5000) < 0)
|
||
|
return 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int set_templed(struct usb_dev_handle *dev, int block, int led, int r, int g, int b)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
if (usb_control_msg(dev,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
|
||
|
CMD_SETLED, led + r*256 , g + b*256, NULL, 0, 5000) < 0)
|
||
|
return 0;
|
||
|
return 1;
|
||
|
}
|