diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index a6b6965fa..6aaf8bf64 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -39,6 +39,7 @@ target_sources(BlitHalPico INTERFACE ${CMAKE_CURRENT_LIST_DIR}/led.cpp ${CMAKE_CURRENT_LIST_DIR}/main.cpp ${CMAKE_CURRENT_LIST_DIR}/storage.cpp + ${CMAKE_CURRENT_LIST_DIR}/multiplayer.cpp ${CMAKE_CURRENT_LIST_DIR}/st7789.cpp ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c ) diff --git a/32blit-pico/main.cpp b/32blit-pico/main.cpp index 867302419..32b2eb1b6 100644 --- a/32blit-pico/main.cpp +++ b/32blit-pico/main.cpp @@ -14,6 +14,7 @@ #include "file.hpp" #include "input.hpp" #include "led.hpp" +#include "multiplayer.hpp" #include "usb.hpp" #include "engine/api_private.hpp" @@ -205,6 +206,7 @@ int main() { update_audio(now); update_led(); update_usb(); + update_multiplayer(); if(ms_to_next_update > 1 && !display_render_needed()) best_effort_wfe_or_timeout(make_timeout_time_ms(ms_to_next_update - 1)); diff --git a/32blit-pico/multiplayer.cpp b/32blit-pico/multiplayer.cpp new file mode 100644 index 000000000..3def9e473 --- /dev/null +++ b/32blit-pico/multiplayer.cpp @@ -0,0 +1,110 @@ +#include +#include "multiplayer.hpp" + +#include "usb.hpp" + +#include "engine/api_private.hpp" + +static bool multiplayer_enabled = false; +static bool peer_connected = false; + +static uint8_t cur_header[8]; +static int header_pos = 0; + +static uint16_t mp_buffer_len, mp_buffer_off; +static uint8_t *mp_buffer = nullptr; + +void send_multiplayer_handshake(bool is_reply) { + uint8_t val = 0; + if(multiplayer_enabled) + val = is_reply ? 2 : 1; + + uint8_t buf[]{'3', '2', 'B', 'L', 'M', 'L', 'T','I', val}; + usb_cdc_write(buf, 9); + usb_cdc_flush_write(); +} + +void update_multiplayer() { + if(!usb_cdc_connected()) { + peer_connected = false; + } + + while(usb_cdc_read_available()) { + // match header + if(header_pos < 8) { + usb_cdc_read(cur_header + header_pos, 1); + + const char *expected = "32BL"; + if(header_pos >= 4 || cur_header[header_pos] == expected[header_pos]) + header_pos++; + else + header_pos = 0; + } else { + + // get USER packet + if(mp_buffer) { + mp_buffer_off += usb_cdc_read(mp_buffer + mp_buffer_off, mp_buffer_len - mp_buffer_off); + + if(mp_buffer_off == mp_buffer_len) { + if(blit::api.message_received) + blit::api.message_received(mp_buffer, mp_buffer_len); + + delete[] mp_buffer; + mp_buffer = nullptr; + header_pos = 0; + } + continue; + } + + // got header + if(memcmp(cur_header + 4, "MLTI", 4) == 0) { + // handshake packet + uint8_t b; + usb_cdc_read(&b, 1); + peer_connected = b != 0; + + if(peer_connected) + send_multiplayer_handshake(true); + + // done + header_pos = 0; + } else if(memcmp(cur_header + 4, "USER", 4) == 0) { + if(usb_cdc_read_available() < 2) + break; + + usb_cdc_read((uint8_t *)&mp_buffer_len, 2); + mp_buffer_off = 0; + mp_buffer = new uint8_t[mp_buffer_len]; + + } else { + printf("got: %c%c%c%c%c%c%c%c\n", cur_header[0], cur_header[1], cur_header[2], cur_header[3], cur_header[4], cur_header[5], cur_header[6], cur_header[7]); + header_pos = 0; + } + } + } +} + +bool is_multiplayer_connected() { + return multiplayer_enabled && peer_connected; +} + +void set_multiplayer_enabled(bool enabled) { + multiplayer_enabled = enabled; + + if(!enabled) + send_multiplayer_handshake(); +} + +void send_multiplayer_message(const uint8_t *data, uint16_t len) { + if(!peer_connected) + return; + + uint8_t buf[]{'3', '2', 'B', 'L', 'U', 'S', 'E','R', + uint8_t(len & 0xFF), uint8_t(len >> 8) + }; + usb_cdc_write(buf, 10); + + usb_cdc_write((uint8_t *)data, len); + + usb_cdc_flush_write(); +} diff --git a/32blit-pico/multiplayer.hpp b/32blit-pico/multiplayer.hpp new file mode 100644 index 000000000..af6639ef6 --- /dev/null +++ b/32blit-pico/multiplayer.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +void update_multiplayer(); +void send_multiplayer_handshake(bool is_reply = false); + +bool is_multiplayer_connected(); +void set_multiplayer_enabled(bool enabled); +void send_multiplayer_message(const uint8_t *data, uint16_t len); diff --git a/32blit-pico/tusb_config.h b/32blit-pico/tusb_config.h index 162717ffa..55d4f47a9 100644 --- a/32blit-pico/tusb_config.h +++ b/32blit-pico/tusb_config.h @@ -107,7 +107,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 0 -#define CFG_TUH_CDC 0 +#define CFG_TUH_CDC 1 #ifdef INPUT_USB_HID #define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces #else diff --git a/32blit-pico/usb.hpp b/32blit-pico/usb.hpp index 477897204..59e7016ef 100644 --- a/32blit-pico/usb.hpp +++ b/32blit-pico/usb.hpp @@ -7,7 +7,8 @@ void update_usb(); void usb_debug(const char *message); -// TODO: separate multiplayer from usb -bool is_multiplayer_connected(); -void set_multiplayer_enabled(bool enabled); -void send_multiplayer_message(const uint8_t *data, uint16_t len); +bool usb_cdc_connected(); +uint16_t usb_cdc_read(uint8_t *data, uint16_t len); +uint32_t usb_cdc_read_available(); +void usb_cdc_write(const uint8_t *data, uint16_t len); +void usb_cdc_flush_write(); diff --git a/32blit-pico/usb_device.cpp b/32blit-pico/usb_device.cpp index cc96ebbec..1df405c5d 100644 --- a/32blit-pico/usb_device.cpp +++ b/32blit-pico/usb_device.cpp @@ -1,15 +1,11 @@ #include "usb.hpp" -#include - #include "tusb.h" #include "config.h" #include "file.hpp" #include "storage.hpp" -#include "engine/api_private.hpp" - // msc static bool storage_ejected = false; @@ -95,99 +91,12 @@ bool tud_msc_is_writable_cb(uint8_t lun) { } // cdc -static bool multiplayer_enabled = false; -static bool peer_connected = false; - -static char cur_header[8]; -static int header_pos = 0; - -static uint16_t mp_buffer_len, mp_buffer_off; -static uint8_t *mp_buffer = nullptr; - -static void send_all(const void *buffer, uint32_t len) { - uint32_t done = tud_cdc_write(buffer, len); - - while(done < len) { - tud_task(); - if(!tud_ready()) - break; - - done += tud_cdc_write((const char *)buffer + done, len - done); - } -} - -static void send_handshake(bool is_reply = false) { - uint8_t val = 0; - if(multiplayer_enabled) - val = is_reply ? 2 : 1; - - uint8_t buf[]{'3', '2', 'B', 'L', 'M', 'L', 'T','I', val}; - send_all(buf, 9); - tud_cdc_write_flush(); -} - void init_usb() { tusb_init(); } void update_usb() { tud_task(); - - if(!tud_ready()) { // tud_cdc_connected returns false with STM USB host - peer_connected = false; - } - - while(tud_cdc_available()) { - // match header - if(header_pos < 8) { - cur_header[header_pos] = tud_cdc_read_char(); - - const char *expected = "32BL"; - if(header_pos >= 4 || cur_header[header_pos] == expected[header_pos]) - header_pos++; - else - header_pos = 0; - } else { - - // get USER packet - if(mp_buffer) { - mp_buffer_off += tud_cdc_read(mp_buffer + mp_buffer_off, mp_buffer_len - mp_buffer_off); - - if(mp_buffer_off == mp_buffer_len) { - if(blit::api.message_received) - blit::api.message_received(mp_buffer, mp_buffer_len); - - delete[] mp_buffer; - mp_buffer = nullptr; - header_pos = 0; - } - continue; - } - - // got header - if(memcmp(cur_header + 4, "MLTI", 4) == 0) { - // handshake packet - peer_connected = tud_cdc_read_char() != 0; - - if(peer_connected) - send_handshake(true); - - // done - header_pos = 0; - } else if(memcmp(cur_header + 4, "USER", 4) == 0) { - if(tud_cdc_available() < 2) - break; - - tud_cdc_read(&mp_buffer_len, 2); - mp_buffer_off = 0; - mp_buffer = new uint8_t[mp_buffer_len]; - - } else { - printf("got: %c%c%c%c%c%c%c%c\n", cur_header[0], cur_header[1], cur_header[2], cur_header[3], cur_header[4], cur_header[5], cur_header[6], cur_header[7]); - header_pos = 0; - } - } - } } void usb_debug(const char *message) { @@ -195,30 +104,34 @@ void usb_debug(const char *message) { return; auto len = strlen(message); - send_all(message, len); + usb_cdc_write((uint8_t *)message, len); } -bool is_multiplayer_connected() { - return multiplayer_enabled && peer_connected; +bool usb_cdc_connected() { + // tud_cdc_connected returns false with STM32 USB host + return tud_ready(); //tud_cdc_connected(); } -void set_multiplayer_enabled(bool enabled) { - multiplayer_enabled = enabled; +uint16_t usb_cdc_read(uint8_t *data, uint16_t len) { + return tud_cdc_read(data, len); +} - if(!enabled) - send_handshake(); +uint32_t usb_cdc_read_available() { + return tud_cdc_available(); } -void send_multiplayer_message(const uint8_t *data, uint16_t len) { - if(!peer_connected) - return; +void usb_cdc_write(const uint8_t *data, uint16_t len) { + uint32_t done = tud_cdc_write(data, len); - uint8_t buf[]{'3', '2', 'B', 'L', 'U', 'S', 'E','R', - uint8_t(len & 0xFF), uint8_t(len >> 8) - }; - send_all(buf, 10); + while(done < len) { + tud_task(); + if(!tud_ready()) + break; - send_all((uint8_t *)data, len); + done += tud_cdc_write(data + done, len - done); + } +} +void usb_cdc_flush_write() { tud_cdc_write_flush(); } diff --git a/32blit-pico/usb_host.cpp b/32blit-pico/usb_host.cpp index 585d6d486..1d78b62bd 100644 --- a/32blit-pico/usb_host.cpp +++ b/32blit-pico/usb_host.cpp @@ -1,6 +1,6 @@ #include "usb.hpp" -#include +#include "multiplayer.hpp" #include "tusb.h" @@ -159,26 +159,53 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons } #endif +// cdc +static uint8_t cdc_index = 0; // TODO: multiple devices? + +void tuh_cdc_mount_cb(uint8_t idx) { + cdc_index = idx; + + send_multiplayer_handshake(); +} + void init_usb() { tusb_init(); } void update_usb() { tuh_task(); + + // TODO: resend multiplayer handshake } void usb_debug(const char *message) { } -// multiplayer could be supported with USB host, but we'd need a hub -// (host code is used for hid) -bool is_multiplayer_connected() { - return false; +bool usb_cdc_connected() { + return tuh_cdc_mounted(cdc_index); +} + +uint16_t usb_cdc_read(uint8_t *data, uint16_t len) { + return tuh_cdc_read(cdc_index, data, len); +} + +uint32_t usb_cdc_read_available() { + return tuh_cdc_read_available(cdc_index); } -void set_multiplayer_enabled(bool enabled) { +void usb_cdc_write(const uint8_t *data, uint16_t len) { + uint32_t done = tuh_cdc_write(cdc_index,data, len); + + while(done < len) { + tuh_task(); + if(!tuh_cdc_mounted(cdc_index)) + break; + + done += tuh_cdc_write(cdc_index, data + done, len - done); + } } -void send_multiplayer_message(const uint8_t *data, uint16_t len) { +void usb_cdc_flush_write() { + tuh_cdc_write_flush(cdc_index); }