#include "streamdeck.h" #include #include struct Image { void* data; size_t size; }; struct Key { bool isFolder; void* command; image* key; pthread_mutex_t key_mutex; }; /* How should we deal with invalid keys with nothing? Well we can use * a bitmask */ /* * Keys are numbered left to right. * so in the mini streamdeck we have * 0 1 2 * 3 4 5 */ struct Screen { key* keys; }; struct Handler { hid_device* handler; }; struct Streamdeck { handler* hid_handle; void* callback_funcs; screen* curr_screen; int numkeys; int devicetype; }; pthread_mutex_t inflate_lock; int update_current_folder (screen* folder); int load_folder (); int load_key (); int createreadthread(); int init () { /* * Init the HIDAPI library */ if (hid_init() < 0) { (void) fprintf(stderr, "Could not init the HID library\n"); return -1; } /* * Initialize the lock for inflating the config file */ if (pthread_mutex_init(&inflate_lock, NULL)) { (void) fprintf(stderr, "Could not init lock\n"); return -2; } return 0; } handler* create_hid_handler () { handler* res = NULL; res = malloc(sizeof(handler)); if (!res) { return NULL; } /* * Create the device handler */ /* These are dev id and manufacturer id for the mini */ res->handler = hid_open(0x0fd9, 0x0063, NULL); if (!res->handler) { (void) fprintf(stderr, "Could not open Streamdeck!\n"); free(res); hid_exit(); return NULL; } /* * Set handler to be non-blocking */ if (hid_set_nonblocking(res->handler, 1) < 0) { (void) fprintf(stderr, "Could not set HIDAPI handler to be non-blocking\n"); free(res); hid_exit(); return NULL; } return res; } streamdeck* connect() { streamdeck* res = malloc(sizeof(streamdeck)); if (!res) return NULL; res->hid_handle = create_hid_handler (); if (1) /* Replace this with the actual ID of the different streamdecks */ { screen* startscreen = malloc(sizeof(screen)); startscreen->keys = malloc(sizeof(key) * STREAMDECK_MINI); for (int i = 0; i < STREAMDECK_MINI; i++) { /* Upon second thought, this may actually not be necessary */ pthread_mutex_init(&(startscreen->keys + i)->key_mutex , NULL); } } /* We will either to this before or after we initialize the streamdeck struct */ if (resetkeystream(res->hid_handle) != 0) { fprintf (stderr, "Failed to reset key stream!\n"); } return res; } int createreadthread() { return 0; } int resetkeystream(handler* deck) { unsigned char data[IMAGE_REPORT_LENGTH]; if (!memset(data, 0x00, IMAGE_REPORT_LENGTH)) return -2; data[0] = 0x02; if (hid_write(deck->handler, data, IMAGE_REPORT_LENGTH) == -1) return -1; return 0; } /* Clears the buttons and displays "standby image" */ int reset(handler* deck) { unsigned char data[17]; if (set_data(data) == -1) return -2; data[0] = 0x0B; data[1] = 0x63; if (hid_send_feature_report(deck->handler, data, 17) == -1) return -1; return 0; } int set_key_image(streamdeck* deck, int key, image* img) { if (!(0 <= key && key < deck->numkeys)) return -1; /* Pass NULL for blank key */ if (!img) { } size_t remaining = img->size; int pages = 0; unsigned char data[17]; while (remaining > 0) { size_t sent_len = (remaining > IMAGE_REPORT_LENGTH) ? IMAGE_REPORT_LENGTH : remaining; size_t total_sent = pages * IMAGE_REPORT_LENGTH; if (set_data(data) == -1) return -1; data[0] = 0x02; data[1] = 0x01; data[2] = pages; data[4] = (remaining == sent_len) ? 1 : 0; data[5] = key + 1; unsigned char* payload = calloc (17 + sent_len, sizeof (unsigned char)); memcpy(payload, data, 17); memcpy(payload + 17, img->data + total_sent, sent_len); if (hid_write(deck->hid_handle->handler, payload, IMAGE_REPORT_LENGTH + 17) == -1) return -1; remaining = remaining - sent_len; pages++; } } int update_current_folder (screen* folder) { for (int i = 0; i < STREAMDECK_MINI; i++ ) { ; } return 0; } int load_folder () { } int load_key () { } void destroy_streamdeck (streamdeck* target) { hid_close (target->hid_handle->handler); free (target->hid_handle); free (target->curr_screen); free (target); } void clean_exit () { hid_exit (); }