prgKbd-ws2812b/software/main.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;
}