Compare commits
4 Commits
v0.1.0
...
75d8f87b40
| Author | SHA1 | Date | |
|---|---|---|---|
|
75d8f87b40
|
|||
|
9762476e4b
|
|||
|
3014bc0c3b
|
|||
|
a1cb13a2f9
|
+2
-2
@@ -1,2 +1,2 @@
|
||||
/build/**/*
|
||||
/external/**/*
|
||||
/*/**/*
|
||||
!/html/**/*
|
||||
|
||||
+5
-1
@@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.13)
|
||||
set(PICO_SDK_PATH /home/kenji/programming/pico/c/pico-sdk)
|
||||
set(PICO_PIO_USB_PATH /home/kenji/programming/pico/c/Pico-PIO-USB)
|
||||
set(TUSB_NETWORKING_PATH ${PICO_SDK_PATH}/lib/tinyusb/lib/networking)
|
||||
if (NOT DEFINED PICO_BOARD)
|
||||
set(PICO_BOARD pico)
|
||||
endif()
|
||||
include (${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
|
||||
project(${PROJECT} C CXX ASM)
|
||||
|
||||
@@ -67,5 +70,6 @@ target_link_libraries(${PROJECT} PRIVATE
|
||||
hardware_adc
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(${PROJECT})
|
||||
set_target_properties(${PROJECT} PROPERTIES OUTPUT_NAME "${PROJECT}-${PICO_BOARD}")
|
||||
|
||||
pico_add_extra_outputs(${PROJECT})
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# HyperX Alloy Elite 2 RGB Controller
|
||||
|
||||
This project provides individual controls of the RGB LEDs of a HyperX Alloy
|
||||
Elite 2 keyboard using a webpage served over a USB connection. ADC readings
|
||||
from an attached light dependent resistor can also be used to make the
|
||||
lighting adaptive to the environment.
|
||||
Elite 2 keyboard using a webpage served over a USB connection from a Raspberry
|
||||
Pi Pico (2). ADC readings from an attached light dependent resistor can also be
|
||||
used to make the lighting adaptive to the environment.
|
||||
|
||||

|
||||
|
||||
@@ -12,23 +12,25 @@ lighting adaptive to the environment.
|
||||
### Hardware
|
||||
|
||||
You will need the following hardware to make the device:
|
||||
- Raspberry Pi Pico
|
||||
- Raspberry Pi Pico or Raspberry Pi Pico 2
|
||||
- USB extension cable
|
||||
- light dependent resistor such as GL5528 (specific part number may vary)
|
||||
- 10k ohm resistor (resistance value may vary)
|
||||
|
||||

|
||||
|
||||
You will need to cut the USB extension in half and connect the wires from the
|
||||
female end to the Raspberry Pi Pico. The default configuration is to attach the
|
||||
USB's green wire to pin 1/GP0 and USB's white wire to pin 2/GP1. You will also
|
||||
need to connect the red to 5V VBUS/VSYS (since you'll be powering from the
|
||||
female end to the Raspberry Pi Pico (2). The default configuration is to attach
|
||||
the USB's green wire to pin 1/GP0 and USB's white wire to pin 2/GP1. You will
|
||||
also need to connect the red to 5V VBUS/VSYS (since you'll be powering from the
|
||||
USB host device, VBUS should be fine) and the black to any ground pin. Pin 38
|
||||
is the closest and most convenient. While you can connect the Raspberry Pi Pico
|
||||
to the host device using the micro USB port and a micro USB cable, since
|
||||
(2) to the host device using the micro USB port and a micro USB cable, since
|
||||
you have already sacrificed half of the USB extension cable, you might as well
|
||||
use the male half to create a standard USB-A connection. If you wish to do so,
|
||||
then simply connect the red and black wires of the male connector end to
|
||||
VBUS (5V) and GND, respectively. For the data wires, you can solder them to the
|
||||
two test points TP2 and TP3 on the back of the Raspberry Pi Pico. The white
|
||||
two test points TP2 and TP3 on the back of the Raspberry Pi Pico (2). The white
|
||||
cable goes to TP2 and the green cable to TP3.
|
||||
|
||||

|
||||
@@ -49,23 +51,23 @@ hole for the LDR to detect ambient light.
|
||||
|
||||
## Software
|
||||
|
||||
Flash the elite2_rgb.uf2 file from the latest
|
||||
Flash the elite2_rgb-pico.uf2 or elite2_rgb-pico2.uf2 file from the latest
|
||||
[release](https://git.kkozai.com/kenji/alloy_elite2_rgb/releases) to the
|
||||
Raspberry Pi Pico, and connect the keyboard to the female USB port and insert
|
||||
the male USB connector of the device into your host device such as PC.
|
||||
Raspberry Pi Pico (2), and connect the keyboard to the female USB port and
|
||||
insert the male USB connector of the device into your host device such as PC.
|
||||
|
||||
To load the UI for configuring the RGB lighting, open a browser to the page at
|
||||
http://alloyelite2.usb, or if that doesn't load, to http://192.168.226.1
|
||||
(226 is E2 for "Elite 2" in hexademical). From the webpage, you can click on
|
||||
(226 is E2 for "Elite 2" in hexadecimal). From the webpage, you can click on
|
||||
any individual key that you want to configure and change the color using the
|
||||
color selector or by manually inputting the RGB color value into the text
|
||||
boxes. To finalize setting the color for the selected key(s), click on the
|
||||
"Set Color" button.
|
||||
|
||||
To save the lighting configuration to the Pico 2 so that it loads the next time
|
||||
it is powered on, click on the "Save" button under the "Flash Memory" section.
|
||||
If you make unsaved changes and want to reload the configuration from memory,
|
||||
you can also click the "Load" button to reset to the last saved setting.
|
||||
To save the lighting configuration to the Pico (2) so that it loads the next
|
||||
time it is powered on, click on the "Save" button under the "Flash Memory"
|
||||
section. If you make unsaved changes and want to reload the configuration from
|
||||
memory, you can also click the "Load" button to reset to the last saved setting.
|
||||
|
||||
If the checkbox next to "Adaptive" is selected when setting the color, the key's
|
||||
brightness will automatically adjust with the ambient lighting, as determined by
|
||||
|
||||
+14
-28
@@ -1,4 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/multicore.h"
|
||||
@@ -13,7 +14,8 @@
|
||||
|
||||
static absolute_time_t lastSend;
|
||||
static absolute_time_t lastRead;
|
||||
static uint16_t adc_value = 0;
|
||||
//static uint16_t adc_value = 0;
|
||||
static uint8_t adc_value = 0;
|
||||
static bool mute = false;
|
||||
|
||||
static unsigned char buf[BUF_SIZE];
|
||||
@@ -165,7 +167,7 @@ static struct key key_list[NUM_KEYS] =
|
||||
void get_light() {
|
||||
// get ADC reading from LDR every 500ms
|
||||
if ( absolute_time_diff_us(lastRead, get_absolute_time()) >= 500000) {
|
||||
adc_value = adc_read();
|
||||
adc_value = log2(adc_read());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,24 +178,6 @@ void rgb_task(uint8_t dev_addr) {
|
||||
// updated color info (packets_sent>0) and continue to send the next
|
||||
// packet if so at a rate of one packet every 20ms
|
||||
// otherwise, wait 0.5s before sending the next set of color packets
|
||||
|
||||
/*if (packets_sent>0) {
|
||||
if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 20000) {
|
||||
if (backlight) {
|
||||
send_color(dev_addr, 0x20, 0x20, 0x20);
|
||||
// send a dim white color (#202020) for all keys
|
||||
} else {
|
||||
send_color(dev_addr, 0x00, 0x00, 0x00);
|
||||
// turn off all lighting by sending (#000000) for all keys
|
||||
}
|
||||
lastSend = get_absolute_time();
|
||||
}
|
||||
} else {
|
||||
if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= 500000) {
|
||||
send_initial(dev_addr);
|
||||
lastSend = get_absolute_time();
|
||||
}
|
||||
}*/
|
||||
if ( absolute_time_diff_us(lastSend, get_absolute_time()) >= delay) {
|
||||
if ( packets_sent == 0) {
|
||||
// first packet is initialization packet
|
||||
@@ -227,9 +211,9 @@ static void send_color(uint8_t dev_addr) {
|
||||
buf[buf_idx] = 0x81;
|
||||
switch (key_list[key_idx].mode) {
|
||||
case RGB_MODE_ADAPTIVE: // adjust brightness based on LDR ADC reading
|
||||
buf[buf_idx+1] = (ADC_MAX-adc_value)*key_list[key_idx].red/ADC_MAX;
|
||||
buf[buf_idx+2] = (ADC_MAX-adc_value)*key_list[key_idx].green/ADC_MAX;
|
||||
buf[buf_idx+3] = (ADC_MAX-adc_value)*key_list[key_idx].blue/ADC_MAX;
|
||||
buf[buf_idx+1] = (ADC_MAX_LOG2-adc_value)*key_list[key_idx].red/ADC_MAX_LOG2;
|
||||
buf[buf_idx+2] = (ADC_MAX_LOG2-adc_value)*key_list[key_idx].green/ADC_MAX_LOG2;
|
||||
buf[buf_idx+3] = (ADC_MAX_LOG2-adc_value)*key_list[key_idx].blue/ADC_MAX_LOG2;
|
||||
break;
|
||||
case RGB_MODE_MUTE:
|
||||
if (mute) {
|
||||
@@ -328,8 +312,6 @@ void parse_colors(char * data, uint16_t len) {
|
||||
if (token != NULL) {
|
||||
// first string is the RGB color code
|
||||
uint8_t red, green, blue;
|
||||
// sscanf(token, "%2x%2x%2x", &red, &green, &blue);
|
||||
// sscanf causes Pico 1 to crash
|
||||
red = hexbyte(token);
|
||||
green = hexbyte(token+2);
|
||||
blue = hexbyte(token+4);
|
||||
@@ -378,11 +360,15 @@ void startADC() {
|
||||
|
||||
// forward HID report after processing
|
||||
bool forward_report(uint8_t instance, uint8_t const* report, uint16_t len) {
|
||||
if (instance == 0x01 && report[0] == 0x03 && report[1] == 0xE2) {
|
||||
mute = !mute;
|
||||
if (device_state == DEVICE_ACTIVE ) {
|
||||
if (instance == 0x01 && report[0] == 0x03 && report[1] == 0xE2) {
|
||||
mute = !mute;
|
||||
}
|
||||
|
||||
return tud_hid_n_report(instance, 0, report, len);
|
||||
}
|
||||
|
||||
return tud_hid_n_report(instance, 0, report, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
// save RGB configuration to flash
|
||||
|
||||
+8
-1
@@ -11,6 +11,7 @@
|
||||
#define NUM_KEYS 126
|
||||
#define BUF_SIZE 64
|
||||
#define ADC_MAX 4096
|
||||
#define ADC_MAX_LOG2 log2(ADC_MAX)
|
||||
|
||||
enum {
|
||||
RGG_MODE_INVALID=0,
|
||||
@@ -187,6 +188,12 @@ bool load_rgb_config(void);
|
||||
|
||||
#define CFG_SIGNATURE 0x9e4c
|
||||
|
||||
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
|
||||
#if PICO_RP2040
|
||||
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
|
||||
#elif PICO_RP2350
|
||||
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_BLOCK_SIZE - FLASH_SECTOR_SIZE)
|
||||
#else
|
||||
#error "Unsupported device. Expected RP2040 or RP2350."
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+25
-1
@@ -1034,7 +1034,31 @@ static const unsigned char data_index_html[] = {
|
||||
0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x3c, 0x20, 0x30, 0x29,
|
||||
0x20, 0x7b, 0xa, 0x9, 0x9, 0x9, 0x63, 0x68, 0x61, 0x6e,
|
||||
0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20,
|
||||
0x3d, 0x20, 0x30, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0xa, 0x9,
|
||||
0x3d, 0x20, 0x30, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0x20, 0x65,
|
||||
0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x20, 0x69,
|
||||
0x73, 0x4e, 0x61, 0x4e, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65,
|
||||
0x49, 0x6e, 0x74, 0x28, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65,
|
||||
0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x29, 0x20,
|
||||
0x29, 0x20, 0x7b, 0xa, 0x9, 0x9, 0x9, 0x2f, 0x2f, 0x20,
|
||||
0x6e, 0x6f, 0x6e, 0x2d, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69,
|
||||
0x63, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20,
|
||||
0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2c, 0x20, 0x73,
|
||||
0x65, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x66, 0x61,
|
||||
0x75, 0x6c, 0x74, 0xa, 0x9, 0x9, 0x9, 0x63, 0x68, 0x61,
|
||||
0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x20, 0x3d, 0x20, 0x31, 0x32, 0x38, 0x3b, 0xa, 0x9, 0x9,
|
||||
0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0xa, 0x9,
|
||||
0x9, 0x9, 0x2f, 0x2f, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20,
|
||||
0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x62,
|
||||
0x6f, 0x78, 0x20, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x73, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x70, 0x61, 0x72,
|
||||
0x73, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x6b, 0x73,
|
||||
0xa, 0x9, 0x9, 0x9, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65,
|
||||
0x6c, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20,
|
||||
0x70, 0x61, 0x72, 0x73, 0x65, 0x49, 0x6e, 0x74, 0x28, 0x63,
|
||||
0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x29, 0x3b, 0xa, 0x9, 0x9, 0x7d, 0xa, 0x9,
|
||||
0x7d, 0xa, 0xa, 0x9, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x72,
|
||||
|
||||
+14772
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 268 KiB |
+12
-10
@@ -13,9 +13,9 @@
|
||||
|
||||
#include "usb_device.h"
|
||||
|
||||
char cdc_buf[64];
|
||||
char cdc_buf[128];
|
||||
uint16_t cdc_len;
|
||||
size_t cdc_count;
|
||||
uint32_t cdc_count;
|
||||
device_state_t device_state;
|
||||
|
||||
static uint8_t desc_configuration[DESC_CFG_MAX];
|
||||
@@ -75,19 +75,17 @@ void usb_device_main(void) {
|
||||
while (true) {
|
||||
switch ( device_state ) {
|
||||
case DEVICE_ACTIVE:
|
||||
if (!tud_mounted()) {
|
||||
device_state = DEVICE_INACTIVE;
|
||||
}
|
||||
break;
|
||||
case DEVICE_INACTIVE:
|
||||
break;
|
||||
case DEVICE_RESTART:
|
||||
if (tud_disconnect()) {
|
||||
device_state = DEVICE_INACTIVE;
|
||||
sleep_ms(10);
|
||||
if (tud_connect()) {
|
||||
if ( host_state == HOST_INACTIVE ) {
|
||||
device_state = DEVICE_INACTIVE;
|
||||
} else {
|
||||
device_state = DEVICE_ACTIVE;
|
||||
}
|
||||
}
|
||||
tud_connect();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -214,7 +212,6 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
||||
@@ -238,6 +235,11 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void) {
|
||||
device_state = DEVICE_ACTIVE;
|
||||
}
|
||||
|
||||
// print message to CDC in raw hex
|
||||
void cdc_print_hex(uint8_t const* msg, uint16_t msg_len) {
|
||||
(void) msg;
|
||||
|
||||
+2
-2
@@ -30,9 +30,9 @@ typedef enum {
|
||||
DEVICE_RESTART,
|
||||
} device_state_t;
|
||||
|
||||
extern char cdc_buf[64];
|
||||
extern char cdc_buf[128];
|
||||
extern uint16_t cdc_len;
|
||||
extern size_t cdc_count;
|
||||
extern uint32_t cdc_count;
|
||||
extern device_state_t device_state;
|
||||
|
||||
void usb_device_main(void);
|
||||
|
||||
+30
-6
@@ -19,6 +19,7 @@ uint8_t num_mounted=0;
|
||||
static absolute_time_t request_time;
|
||||
static bool enabled=false;
|
||||
static uint8_t kb_addr=0;
|
||||
static struct hid_report last_report;
|
||||
|
||||
static void usb_host_init(void);
|
||||
static void host_ready(void);
|
||||
@@ -79,6 +80,22 @@ void usb_host_main(void) {
|
||||
if (enabled) {
|
||||
rgb_task(kb_addr);
|
||||
}
|
||||
|
||||
if (last_report.len > 0 ) {
|
||||
// previous report was not forwarded, resend
|
||||
if ( forward_report(last_report.instance, last_report.report, last_report.len) ) {
|
||||
// clear queue
|
||||
last_report.len = 0;
|
||||
memset(last_report.report, 0x00, REPORT_MAX_SIZE);
|
||||
|
||||
// continue requesting reports
|
||||
if ( !tuh_hid_receive_report(last_report.dev_addr, last_report.instance) ) {
|
||||
tud_cdc_write_str("Error: cannot request report\r\n");
|
||||
}
|
||||
} else {
|
||||
tud_cdc_write_str("Error: failed resend report\r\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -142,12 +159,19 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||
cdc_print_hex(report, len);
|
||||
}
|
||||
|
||||
forward_report(instance, report, len);
|
||||
|
||||
// continue to request to receive report
|
||||
if ( !tuh_hid_receive_report(dev_addr, instance) )
|
||||
{
|
||||
tud_cdc_write_str("Error: cannot request report\r\n");
|
||||
// forward report to device output
|
||||
if ( !forward_report(instance, report, len) ) {
|
||||
tud_cdc_write_str("Error: cannot forward report\r\n");
|
||||
// queue report for resending
|
||||
last_report.dev_addr = dev_addr;
|
||||
last_report.instance = instance;
|
||||
last_report.len = len;
|
||||
memcpy(last_report.report, report, len);
|
||||
} else {
|
||||
// continue to request to receive report
|
||||
if ( !tuh_hid_receive_report(dev_addr, instance) ) {
|
||||
tud_cdc_write_str("Error: cannot request report\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,13 @@ struct report_desc {
|
||||
bool listening;
|
||||
};
|
||||
|
||||
struct hid_report {
|
||||
uint8_t dev_addr;
|
||||
uint8_t instance;
|
||||
uint16_t len;
|
||||
uint8_t report[REPORT_MAX_SIZE];
|
||||
};
|
||||
|
||||
#define REPORT_DESC_ALLOC() (struct report_desc *)malloc(sizeof(struct report_desc))
|
||||
|
||||
extern host_state_t host_state;
|
||||
|
||||
+4
-3
@@ -354,12 +354,14 @@ static err_t ws_read(struct altcp_pcb *pcb, struct ws_state *wss, struct pbuf *p
|
||||
uint8_t masked = data[1] & 0x80;
|
||||
uint16_t msg_len = data[1] & 0x7F;
|
||||
uint8_t *msg;
|
||||
uint8_t *mask;
|
||||
|
||||
switch (msg_len) {
|
||||
case 126: // next two bytes are length
|
||||
memcpy(&msg_len, &data[2], 2);
|
||||
msg_len = ( (uint16_t)data[2] << 8) | data[3];
|
||||
if (len >= 8) {
|
||||
msg = &data[8];
|
||||
mask = &data[4];
|
||||
}
|
||||
break;
|
||||
case 127: // next four bytes are length
|
||||
@@ -369,6 +371,7 @@ static err_t ws_read(struct altcp_pcb *pcb, struct ws_state *wss, struct pbuf *p
|
||||
default:
|
||||
if (len >= 6) {
|
||||
msg = &data[6];
|
||||
mask = &data[2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -382,8 +385,6 @@ static err_t ws_read(struct altcp_pcb *pcb, struct ws_state *wss, struct pbuf *p
|
||||
if (msg && ws_receive_cb != NULL) {
|
||||
// unmask the data if mask bit is received
|
||||
if (masked) {
|
||||
uint8_t *mask = &data[2];
|
||||
|
||||
for (int i=0; i<msg_len; i++) {
|
||||
msg[i] ^= mask[i % 4];
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
#define WS_MAX_RETRIES 10
|
||||
#define WS_POLL_INTERVAL 60 // WS_POLL_INTERVAL/2 seconds
|
||||
#define WS_MAX_CONN 4
|
||||
#define WS_BUFFER_SIZE 512
|
||||
#define WS_BUFFER_SIZE 1024
|
||||
|
||||
#define OP_CONT 0x00
|
||||
#define OP_TEXT 0x01
|
||||
|
||||
Reference in New Issue
Block a user