From 8290bbee44d0a36d145156144862a08dd4ec210f Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Thu, 3 Mar 2022 19:46:06 -0600 Subject: [PATCH] Add basic I2C protocol for serial LED strips --- .../LEDStripController/LEDStripController.cpp | 705 ++++++++++-------- .../LEDStripController/LEDStripController.h | 7 +- .../LEDStripControllerDetect.cpp | 4 + 3 files changed, 395 insertions(+), 321 deletions(-) diff --git a/Controllers/LEDStripController/LEDStripController.cpp b/Controllers/LEDStripController/LEDStripController.cpp index 4b925e62a..1df62b7a5 100644 --- a/Controllers/LEDStripController/LEDStripController.cpp +++ b/Controllers/LEDStripController/LEDStripController.cpp @@ -1,320 +1,385 @@ -/*---------------------------------------------------------*\ -| Processing Code for Generic LED Strip Interface | -| | -| Adam Honse (calcprogrammer1@gmail.com), 12/11/2016 | -\*---------------------------------------------------------*/ - -#include "LEDStripController.h" - -#include -#include -#include - -LEDStripController::LEDStripController() -{ - -} - - -LEDStripController::~LEDStripController() -{ -} - -void LEDStripController::Initialize(char* ledstring, led_protocol proto) -{ - LPSTR numleds = NULL; - LPSTR source = NULL; - LPSTR udpport_baud = NULL; - LPSTR next = NULL; - - //Set the protocol - protocol = proto; - - //Assume serial device unless a different protocol is specified - bool serial = TRUE; - - source = strtok_s(ledstring, ",", &next); - - //Check if we are setting up a Keyboard Visualizer UDP protocol device - if (strncmp(source, "udp:", 4) == 0) - { - source = source + 4; - serial = FALSE; - } - - //Check for either the UDP port or the serial baud rate - if (strlen(next)) - { - udpport_baud = strtok_s(next, ",", &next); - } - - //Check for the number of LEDs - if (strlen(next)) - { - numleds = strtok_s(next, ",", &next); - } - - if (serial) - { - if (udpport_baud == NULL) - { - //Initialize with default baud rate - InitializeSerial(source, 115200); - } - else - { - //Initialize with custom baud rate - InitializeSerial(source, atoi(udpport_baud)); - } - } - else - { - if (udpport_baud == NULL) - { - //Do something - } - else - { - //Initialize UDP port - InitializeUDP(source, udpport_baud); - } - } - - if (numleds != NULL && strlen(numleds)) - { - num_leds = atoi(numleds); - } -} - -void LEDStripController::InitializeSerial(char* portname, int baud) -{ - portname = strtok(portname, "\r"); - port_name = portname; - baud_rate = baud; - serialport = new serial_port(port_name.c_str(), baud_rate); - udpport = NULL; -} - -void LEDStripController::InitializeUDP(char * clientname, char * port) -{ - client_name = clientname; - port_name = port; - - udpport = new net_port(client_name.c_str(), port_name.c_str()); - serialport = NULL; -} - -std::string LEDStripController::GetLocation() -{ - if(serialport != NULL) - { - return("COM: " + port_name); - } - else if(udpport != NULL) - { - return("UDP: " + client_name + ":" + port_name); - } - else - { - return(""); - } -} - -char* LEDStripController::GetLEDString() -{ - return(led_string); -} - -void LEDStripController::SetLEDs(std::vector colors) -{ - switch(protocol) - { - case LED_PROTOCOL_KEYBOARD_VISUALIZER: - SetLEDsKeyboardVisualizer(colors); - break; - - case LED_PROTOCOL_ADALIGHT: - SetLEDsAdalight(colors); - break; - - case LED_PROTOCOL_TPM2: - SetLEDsTPM2(colors); - break; - } -} - -void LEDStripController::SetLEDsKeyboardVisualizer(std::vector colors) -{ - unsigned char *serial_buf; - - /*-------------------------------------------------------------*\ - | Keyboard Visualizer Arduino Protocol | - | | - | Packet size: Number of data bytes + 3 | - | | - | 0: Packet Start Byte (0xAA) | - | 1-n: Data bytes | - | n+1: Checksum MSB | - | n+2: Checksum LSB | - \*-------------------------------------------------------------*/ - unsigned int payload_size = (colors.size() * 3); - unsigned int packet_size = payload_size + 3; - - serial_buf = new unsigned char[packet_size]; - - /*-------------------------------------------------------------*\ - | Set up header | - \*-------------------------------------------------------------*/ - serial_buf[0x00] = 0xAA; - - /*-------------------------------------------------------------*\ - | Copy in color data in RGB order | - \*-------------------------------------------------------------*/ - for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++) - { - unsigned int color_offset = color_idx * 3; - - serial_buf[0x01 + color_offset] = RGBGetRValue(colors[color_idx]); - serial_buf[0x02 + color_offset] = RGBGetGValue(colors[color_idx]); - serial_buf[0x03 + color_offset] = RGBGetBValue(colors[color_idx]); - } - - /*-------------------------------------------------------------*\ - | Calculate the checksum | - \*-------------------------------------------------------------*/ - unsigned short sum = 0; - - for(unsigned int i = 0; i < (payload_size + 1); i++) - { - sum += serial_buf[i]; - } - - /*-------------------------------------------------------------*\ - | Fill in the checksum bytes | - \*-------------------------------------------------------------*/ - serial_buf[(num_leds * 3) + 1] = sum >> 8; - serial_buf[(num_leds * 3) + 2] = sum & 0x00FF; - - /*-------------------------------------------------------------*\ - | Send the packet | - \*-------------------------------------------------------------*/ - if (serialport != NULL) - { - serialport->serial_write((char *)serial_buf, packet_size); - } - else if (udpport != NULL) - { - udpport->udp_write((char *)serial_buf, packet_size); - } - - delete[] serial_buf; -} - -void LEDStripController::SetLEDsAdalight(std::vector colors) -{ - unsigned char *serial_buf; - - /*-------------------------------------------------------------*\ - | Adalight Protocol | - | | - | Packet size: Number of data bytes + 6 | - | | - | 0: 'A' (0x41) | - | 1: 'd' (0x64) | - | 2: 'a' (0x61) | - | 3: LED count MSB | - | 4: LED count LSB | - | 5: Checksum (MSB xor LSB xor 0x55) | - | 6-n: Data Bytes | - \*-------------------------------------------------------------*/ - unsigned int led_count = colors.size(); - unsigned int payload_size = (led_count * 3); - unsigned int packet_size = payload_size + 6; - - serial_buf = new unsigned char[packet_size]; - - /*-------------------------------------------------------------*\ - | Set up header | - \*-------------------------------------------------------------*/ - serial_buf[0x00] = 0x41; - serial_buf[0x01] = 0x64; - serial_buf[0x02] = 0x61; - serial_buf[0x03] = (led_count >> 8); - serial_buf[0x04] = (led_count & 0xFF); - serial_buf[0x05] = (serial_buf[0x03] ^ serial_buf[0x04] ^ 0x55); - - /*-------------------------------------------------------------*\ - | Copy in color data in RGB order | - \*-------------------------------------------------------------*/ - for(unsigned int color_idx = 0; color_idx < led_count; color_idx++) - { - unsigned int color_offset = color_idx * 3; - - serial_buf[0x06 + color_offset] = RGBGetRValue(colors[color_idx]); - serial_buf[0x07 + color_offset] = RGBGetGValue(colors[color_idx]); - serial_buf[0x08 + color_offset] = RGBGetBValue(colors[color_idx]); - } - - /*-------------------------------------------------------------*\ - | Send the packet | - \*-------------------------------------------------------------*/ - if (serialport != NULL) - { - serialport->serial_write((char *)serial_buf, packet_size); - } - - delete[] serial_buf; -} - -void LEDStripController::SetLEDsTPM2(std::vector colors) -{ - unsigned char *serial_buf; - - /*-------------------------------------------------------------*\ - | TPM2 Protocol | - | | - | Packet size: Number of data bytes + 5 | - | | - | 0: Packet Start Byte (0xC9) | - | 1: Packet Type (0xDA - Data, 0xC0 - Command, 0xAA - Read) | - | 2: Payload Size MSB | - | 3: Payload Size LSB | - | 4-n: Data Bytes | - | n+1: Packet End Byte (0x36) | - \*-------------------------------------------------------------*/ - unsigned int payload_size = (colors.size() * 3); - unsigned int packet_size = payload_size + 5; - - serial_buf = new unsigned char[packet_size]; - - /*-------------------------------------------------------------*\ - | Set up header and end byte | - \*-------------------------------------------------------------*/ - serial_buf[0x00] = 0xC9; - serial_buf[0x01] = 0xDA; - serial_buf[0x02] = (payload_size >> 8); - serial_buf[0x03] = (payload_size & 0xFF); - serial_buf[packet_size - 1] = 0x36; - - /*-------------------------------------------------------------*\ - | Copy in color data in RGB order | - \*-------------------------------------------------------------*/ - for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++) - { - unsigned int color_offset = color_idx * 3; - - serial_buf[0x04 + color_offset] = RGBGetRValue(colors[color_idx]); - serial_buf[0x05 + color_offset] = RGBGetGValue(colors[color_idx]); - serial_buf[0x06 + color_offset] = RGBGetBValue(colors[color_idx]); - } - - /*-------------------------------------------------------------*\ - | Send the packet | - \*-------------------------------------------------------------*/ - if (serialport != NULL) - { - serialport->serial_write((char *)serial_buf, packet_size); - } - - delete[] serial_buf; -} +/*---------------------------------------------------------*\ +| Processing Code for Generic LED Strip Interface | +| | +| Adam Honse (calcprogrammer1@gmail.com), 12/11/2016 | +\*---------------------------------------------------------*/ + +#include "LEDStripController.h" +#include "ResourceManager.h" + +#include +#include +#include + +LEDStripController::LEDStripController() +{ + +} + + +LEDStripController::~LEDStripController() +{ +} + +void LEDStripController::Initialize(char* ledstring, led_protocol proto) +{ + LPSTR numleds = NULL; + LPSTR source = NULL; + LPSTR udpport_baud = NULL; + LPSTR next = NULL; + + //Set the protocol + protocol = proto; + + //Assume serial device unless a different protocol is specified + bool serial = TRUE; + + source = strtok_s(ledstring, ",", &next); + + //Check if we are setting up a Keyboard Visualizer UDP protocol device + if (strncmp(source, "udp:", 4) == 0) + { + source = source + 4; + serial = FALSE; + } + + //Check for either the UDP port or the serial baud rate + if (strlen(next)) + { + udpport_baud = strtok_s(next, ",", &next); + } + + //Check for the number of LEDs + if (strlen(next)) + { + numleds = strtok_s(next, ",", &next); + } + + if (serial) + { + if (protocol == LED_PROTOCOL_BASIC_I2C) + { + InitializeI2C(source); + } + else if (udpport_baud == NULL) + { + //Initialize with default baud rate + InitializeSerial(source, 115200); + } + else + { + //Initialize with custom baud rate + InitializeSerial(source, atoi(udpport_baud)); + } + } + else + { + if (udpport_baud == NULL) + { + //Do something + } + else + { + //Initialize UDP port + InitializeUDP(source, udpport_baud); + } + } + + if (numleds != NULL && strlen(numleds)) + { + num_leds = atoi(numleds); + } +} + +void LEDStripController::InitializeI2C(char* i2cname) +{ + for(unsigned int i2c_idx = 0; i2c_idx < ResourceManager::get()->GetI2CBusses().size(); i2c_idx++) + { + if(ResourceManager::get()->GetI2CBusses()[i2c_idx]->device_name == std::string(i2cname)) + { + i2cport = ResourceManager::get()->GetI2CBusses()[i2c_idx]; + break; + } + } + + serialport = NULL; + udpport = NULL; +} + +void LEDStripController::InitializeSerial(char* portname, int baud) +{ + portname = strtok(portname, "\r"); + port_name = portname; + baud_rate = baud; + serialport = new serial_port(port_name.c_str(), baud_rate); + udpport = NULL; + i2cport = NULL; +} + +void LEDStripController::InitializeUDP(char * clientname, char * port) +{ + client_name = clientname; + port_name = port; + + udpport = new net_port(client_name.c_str(), port_name.c_str()); + serialport = NULL; + i2cport = NULL; +} + +std::string LEDStripController::GetLocation() +{ + if(serialport != NULL) + { + return("COM: " + port_name); + } + else if(udpport != NULL) + { + return("UDP: " + client_name + ":" + port_name); + } + else + { + return(""); + } +} + +char* LEDStripController::GetLEDString() +{ + return(led_string); +} + +void LEDStripController::SetLEDs(std::vector colors) +{ + switch(protocol) + { + case LED_PROTOCOL_KEYBOARD_VISUALIZER: + SetLEDsKeyboardVisualizer(colors); + break; + + case LED_PROTOCOL_ADALIGHT: + SetLEDsAdalight(colors); + break; + + case LED_PROTOCOL_TPM2: + SetLEDsTPM2(colors); + break; + } +} + +void LEDStripController::SetLEDsKeyboardVisualizer(std::vector colors) +{ + unsigned char *serial_buf; + + /*-------------------------------------------------------------*\ + | Keyboard Visualizer Arduino Protocol | + | | + | Packet size: Number of data bytes + 3 | + | | + | 0: Packet Start Byte (0xAA) | + | 1-n: Data bytes | + | n+1: Checksum MSB | + | n+2: Checksum LSB | + \*-------------------------------------------------------------*/ + unsigned int payload_size = (colors.size() * 3); + unsigned int packet_size = payload_size + 3; + + serial_buf = new unsigned char[packet_size]; + + /*-------------------------------------------------------------*\ + | Set up header | + \*-------------------------------------------------------------*/ + serial_buf[0x00] = 0xAA; + + /*-------------------------------------------------------------*\ + | Copy in color data in RGB order | + \*-------------------------------------------------------------*/ + for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++) + { + unsigned int color_offset = color_idx * 3; + + serial_buf[0x01 + color_offset] = RGBGetRValue(colors[color_idx]); + serial_buf[0x02 + color_offset] = RGBGetGValue(colors[color_idx]); + serial_buf[0x03 + color_offset] = RGBGetBValue(colors[color_idx]); + } + + /*-------------------------------------------------------------*\ + | Calculate the checksum | + \*-------------------------------------------------------------*/ + unsigned short sum = 0; + + for(unsigned int i = 0; i < (payload_size + 1); i++) + { + sum += serial_buf[i]; + } + + /*-------------------------------------------------------------*\ + | Fill in the checksum bytes | + \*-------------------------------------------------------------*/ + serial_buf[(num_leds * 3) + 1] = sum >> 8; + serial_buf[(num_leds * 3) + 2] = sum & 0x00FF; + + /*-------------------------------------------------------------*\ + | Send the packet | + \*-------------------------------------------------------------*/ + if (serialport != NULL) + { + serialport->serial_write((char *)serial_buf, packet_size); + } + else if (udpport != NULL) + { + udpport->udp_write((char *)serial_buf, packet_size); + } + + delete[] serial_buf; +} + +void LEDStripController::SetLEDsAdalight(std::vector colors) +{ + unsigned char *serial_buf; + + /*-------------------------------------------------------------*\ + | Adalight Protocol | + | | + | Packet size: Number of data bytes + 6 | + | | + | 0: 'A' (0x41) | + | 1: 'd' (0x64) | + | 2: 'a' (0x61) | + | 3: LED count MSB | + | 4: LED count LSB | + | 5: Checksum (MSB xor LSB xor 0x55) | + | 6-n: Data Bytes | + \*-------------------------------------------------------------*/ + unsigned int led_count = colors.size(); + unsigned int payload_size = (led_count * 3); + unsigned int packet_size = payload_size + 6; + + serial_buf = new unsigned char[packet_size]; + + /*-------------------------------------------------------------*\ + | Set up header | + \*-------------------------------------------------------------*/ + serial_buf[0x00] = 0x41; + serial_buf[0x01] = 0x64; + serial_buf[0x02] = 0x61; + serial_buf[0x03] = (led_count >> 8); + serial_buf[0x04] = (led_count & 0xFF); + serial_buf[0x05] = (serial_buf[0x03] ^ serial_buf[0x04] ^ 0x55); + + /*-------------------------------------------------------------*\ + | Copy in color data in RGB order | + \*-------------------------------------------------------------*/ + for(unsigned int color_idx = 0; color_idx < led_count; color_idx++) + { + unsigned int color_offset = color_idx * 3; + + serial_buf[0x06 + color_offset] = RGBGetRValue(colors[color_idx]); + serial_buf[0x07 + color_offset] = RGBGetGValue(colors[color_idx]); + serial_buf[0x08 + color_offset] = RGBGetBValue(colors[color_idx]); + } + + /*-------------------------------------------------------------*\ + | Send the packet | + \*-------------------------------------------------------------*/ + if (serialport != NULL) + { + serialport->serial_write((char *)serial_buf, packet_size); + } + + delete[] serial_buf; +} + +void LEDStripController::SetLEDsTPM2(std::vector colors) +{ + unsigned char *serial_buf; + + /*-------------------------------------------------------------*\ + | TPM2 Protocol | + | | + | Packet size: Number of data bytes + 5 | + | | + | 0: Packet Start Byte (0xC9) | + | 1: Packet Type (0xDA - Data, 0xC0 - Command, 0xAA - Read) | + | 2: Payload Size MSB | + | 3: Payload Size LSB | + | 4-n: Data Bytes | + | n+1: Packet End Byte (0x36) | + \*-------------------------------------------------------------*/ + unsigned int payload_size = (colors.size() * 3); + unsigned int packet_size = payload_size + 5; + + serial_buf = new unsigned char[packet_size]; + + /*-------------------------------------------------------------*\ + | Set up header and end byte | + \*-------------------------------------------------------------*/ + serial_buf[0x00] = 0xC9; + serial_buf[0x01] = 0xDA; + serial_buf[0x02] = (payload_size >> 8); + serial_buf[0x03] = (payload_size & 0xFF); + serial_buf[packet_size - 1] = 0x36; + + /*-------------------------------------------------------------*\ + | Copy in color data in RGB order | + \*-------------------------------------------------------------*/ + for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++) + { + unsigned int color_offset = color_idx * 3; + + serial_buf[0x04 + color_offset] = RGBGetRValue(colors[color_idx]); + serial_buf[0x05 + color_offset] = RGBGetGValue(colors[color_idx]); + serial_buf[0x06 + color_offset] = RGBGetBValue(colors[color_idx]); + } + + /*-------------------------------------------------------------*\ + | Send the packet | + \*-------------------------------------------------------------*/ + if (serialport != NULL) + { + serialport->serial_write((char *)serial_buf, packet_size); + } + + delete[] serial_buf; +} + +void LEDStripController::SetLEDsBasicI2C(std::vector colors) +{ + unsigned char serial_buf[30]; + + /*-------------------------------------------------------------*\ + | Basic I2C Protocol | + | | + | Packet size: At most 32 bytes (SMBus block size) | + | | + | Packet is in RGBRGBRGB... format, also provide start index | + \*-------------------------------------------------------------*/ + + unsigned char index = 0; + unsigned char offset = 0; + + for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++) + { + serial_buf[(index * 3) + 0] = RGBGetRValue(colors[color_idx]); + serial_buf[(index * 3) + 1] = RGBGetGValue(colors[color_idx]); + serial_buf[(index * 3) + 2] = RGBGetBValue(colors[color_idx]); + + index += 3; + + if(index >= 30) + { + if(i2cport != NULL) + { + i2cport->i2c_smbus_write_block_data(0x08, offset, 30, serial_buf); + offset += 30; + index = 0; + } + } + } + + if(index > 0) + { + if(i2cport != NULL) + { + i2cport->i2c_smbus_write_block_data(0x08, offset, index, serial_buf); + } + } +} \ No newline at end of file diff --git a/Controllers/LEDStripController/LEDStripController.h b/Controllers/LEDStripController/LEDStripController.h index cf0a3f41d..b787db621 100644 --- a/Controllers/LEDStripController/LEDStripController.h +++ b/Controllers/LEDStripController/LEDStripController.h @@ -8,6 +8,7 @@ #define LED_STRIP_H #include "RGBController.h" +#include "i2c_smbus.h" #include "serial_port.h" #include "net_port.h" #include @@ -29,7 +30,8 @@ enum { LED_PROTOCOL_KEYBOARD_VISUALIZER, LED_PROTOCOL_ADALIGHT, - LED_PROTOCOL_TPM2 + LED_PROTOCOL_TPM2, + LED_PROTOCOL_BASIC_I2C }; struct LEDStripDevice @@ -49,6 +51,7 @@ public: void Initialize(char* ledstring, led_protocol proto); + void InitializeI2C(char* i2cname); void InitializeSerial(char* portname, int baud); void InitializeUDP(char* clientname, char* port); @@ -60,6 +63,7 @@ public: void SetLEDsKeyboardVisualizer(std::vector colors); void SetLEDsAdalight(std::vector colors); void SetLEDsTPM2(std::vector colors); + void SetLEDsBasicI2C(std::vector colors); int num_leds; @@ -71,6 +75,7 @@ private: std::string client_name; serial_port *serialport; net_port *udpport; + i2c_smbus_interface *i2cport; led_protocol protocol; }; diff --git a/Controllers/LEDStripController/LEDStripControllerDetect.cpp b/Controllers/LEDStripController/LEDStripControllerDetect.cpp index bc2240ffa..7c8ed43d8 100644 --- a/Controllers/LEDStripController/LEDStripControllerDetect.cpp +++ b/Controllers/LEDStripController/LEDStripControllerDetect.cpp @@ -74,6 +74,10 @@ void DetectLEDStripControllers(std::vector &rgb_controllers) { dev.protocol = LED_PROTOCOL_TPM2; } + else if(protocol_string == "basic_i2c") + { + dev.protocol = LED_PROTOCOL_BASIC_I2C; + } } std::string value = dev.port + "," + std::to_string(dev.baud) + "," + std::to_string(dev.num_leds);