Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pico: usb host multiplayer #817

Merged
merged 4 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions 32blit-pico/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
2 changes: 2 additions & 0 deletions 32blit-pico/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "file.hpp"
#include "input.hpp"
#include "led.hpp"
#include "multiplayer.hpp"
#include "usb.hpp"

#include "engine/api_private.hpp"
Expand Down Expand Up @@ -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));
Expand Down
110 changes: 110 additions & 0 deletions 32blit-pico/multiplayer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include <cstring>
#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();
}
9 changes: 9 additions & 0 deletions 32blit-pico/multiplayer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once
#include <cstdint>

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);
2 changes: 1 addition & 1 deletion 32blit-pico/tusb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions 32blit-pico/usb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
125 changes: 19 additions & 106 deletions 32blit-pico/usb_device.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
#include "usb.hpp"

#include <cstring>

#include "tusb.h"

#include "config.h"
#include "file.hpp"
#include "storage.hpp"

#include "engine/api_private.hpp"

// msc
static bool storage_ejected = false;

Expand Down Expand Up @@ -95,130 +91,47 @@ 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) {
if(!tud_cdc_connected())
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();
}
Loading