blob: d687e807beddf50a89c53043a884ba66d1a94fd3 [file] [log] [blame] [edit]
#include "usb.hpp"
#include <cstring>
#include "bsp/board.h"
#include "tusb.h"
#include "config.h"
#include "file.hpp"
#include "storage.hpp"
#include "engine/api_private.hpp"
// msc
static bool storage_ejected = false;
void tud_mount_cb() {
storage_ejected = false;
}
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
(void) lun;
const char vid[] = USB_VENDOR_STR;
const char pid[] = USB_PRODUCT_STR " Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
if(storage_ejected) {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
return true;
}
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
(void) lun;
get_storage_size(*block_size, *block_count);
}
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
(void) lun;
(void) power_condition;
if(load_eject) {
if (start) {
} else
storage_ejected = true;
}
return true;
}
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
(void) lun;
return storage_read(lba, offset, buffer, bufsize);
}
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
(void) lun;
return storage_write(lba, offset, buffer, bufsize);
}
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
void const* response = NULL;
uint16_t resplen = 0;
switch (scsi_cmd[0]) {
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
// Host is about to read/write etc ... better not to disconnect disk
resplen = 0;
break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
return resplen;
}
bool tud_msc_is_writable_cb(uint8_t lun) {
return !get_files_open();
}
// 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);
}
bool is_multiplayer_connected() {
return multiplayer_enabled && peer_connected;
}
void set_multiplayer_enabled(bool enabled) {
multiplayer_enabled = enabled;
if(!enabled)
send_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)
};
send_all(buf, 10);
send_all((uint8_t *)data, len);
tud_cdc_write_flush();
}