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

User I2C support v2 #781

Merged
merged 10 commits into from
Sep 27, 2022
1 change: 1 addition & 0 deletions 32blit-stm32/Inc/32blit.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ bool blit_user_code_running();
extern "C" void blit_reset_with_error();
void blit_enable_user_code();
void blit_disable_user_code();
bool blit_user_code_disabled();
RawMetadata *blit_get_running_game_metadata();

void blit_menu_update(uint32_t time);
Expand Down
3 changes: 3 additions & 0 deletions 32blit-stm32/Inc/32blit/i2c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@
namespace i2c {
void init();
void tick();

bool user_send(uint8_t address, uint8_t reg, const uint8_t *data, uint16_t len);
bool user_receive(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len);
}
11 changes: 10 additions & 1 deletion 32blit-stm32/Inc/CDCCommandStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,18 @@ class CDCCommandStream
void Stream(void);
uint8_t Stream(uint8_t *data, uint32_t len);

void SetParsingEnabled(bool enabled);

uint32_t Read(uint8_t *data, uint32_t len);

// USB Packet fifo
uint8_t *GetFifoWriteBuffer(void);
void ReleaseFifoWriteBuffer(uint8_t uLen);
CDCFifoElement *GetFifoReadElement(void);
void ReleaseFifoReadElement(void);

private:
typedef enum { stDetect, stDetectCommandWord, stDispatch, stProcessing, stError } StreamState;
typedef enum { stDetect, stDetectCommandWord, stDispatch, stProcessing, stError, stDisabled } StreamState;

StreamState m_state;

Expand All @@ -63,15 +67,20 @@ class CDCCommandStream

CDCDataStream m_dataStream;

uint32_t uLastResumeTime;

CDCFifoElement m_fifoElements[CDC_FIFO_BUFFERS];
uint8_t m_uFifoReadPos;
uint8_t m_uFifoWritePos;

bool m_bNeedsUSBResume;

uint8_t m_uCurElementOff = 0;


void LogTimeTaken(CDCCommandHandler::StreamResult result, uint32_t uBytesHandled);

void Resume();
};

#endif /* SRC_CDCCOMMANDSTREAM_H_ */
186 changes: 108 additions & 78 deletions 32blit-stm32/Src/32blit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "power.hpp"
#include "quadspi.hpp"

#include "CDCCommandStream.h"
#include "tim.h"
#include "rng.h"
#include "ff.h"
Expand All @@ -31,6 +32,7 @@ using namespace blit;

extern USBD_HandleTypeDef hUsbDeviceHS;
extern USBManager g_usbManager;
extern CDCCommandStream g_commandStream;

FATFS filesystem;
static bool fs_mounted = false;
Expand Down Expand Up @@ -80,19 +82,28 @@ static void init_api_shared() {
api.channels[i] = AudioChannel();

api.message_received = nullptr;
api.i2c_completed = nullptr;

// take CDC back
g_commandStream.SetParsingEnabled(true);
}

bool g_bConsumerConnected = true;
void blit_debug(const char *message) {
if(g_usbManager.GetType() == USBManager::usbtCDC)
{

static bool set_raw_cdc_enabled(bool enabled) {
g_commandStream.SetParsingEnabled(!enabled);
return true;
}

static void cdc_write(const uint8_t *data, uint16_t len) {
if(g_usbManager.GetType() == USBManager::usbtCDC) {
// The mad STM CDC implementation relies on a USB packet being received to set TxState
// Also calls to CDC_Transmit_HS do not buffer the data so we have to rely on TxState before sending new data.
// So if there is no consumer running at the other end we will hang, so we need to check for this
if(g_bConsumerConnected)
{
uint32_t tickstart = HAL_GetTick();
while(g_bConsumerConnected && CDC_Transmit_HS((uint8_t *)message, strlen(message)) == USBD_BUSY)
while(g_bConsumerConnected && CDC_Transmit_HS((uint8_t *)data, len) == USBD_BUSY)
g_bConsumerConnected = !(HAL_GetTick() > (tickstart + 2));
}
else
Expand All @@ -103,6 +114,14 @@ void blit_debug(const char *message) {
}
}

static uint16_t cdc_read(uint8_t *data, uint16_t len) {
return g_commandStream.Read(data, len);
}

void blit_debug(const char *message) {
cdc_write((uint8_t *)message, strlen(message));
}

void blit_exit(bool is_error) {
if(is_error)
blit_reset_with_error(); // likely an abort
Expand Down Expand Up @@ -297,98 +316,105 @@ static void save_screenshot() {
}

void blit_init() {
// enable backup sram
__HAL_RCC_RTC_ENABLE();
__HAL_RCC_BKPRAM_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
HAL_PWREx_EnableBkUpReg();

// need to wit for sram, I tried a few things I found on the net to wait
// based on PWR flags but none seemed to work, a simple delay does work!
HAL_Delay(5);

if(persist.magic_word != persistence_magic_word) {
// Set persistent defaults if the magic word does not match
persist.magic_word = persistence_magic_word;
persist.volume = 0.5f;
persist.backlight = 1.0f;
persist.selected_menu_item = 0;
persist.reset_target = prtFirmware;
persist.reset_error = false;
persist.last_game_offset = 0;
memset(persist.launch_path, 0, sizeof(persist.launch_path));

// clear LTDC buffer to avoid flash of uninitialised data
extern char __ltdc_start;
int len = 320 * 240 * 2;
memset(&__ltdc_start, 0, len);
}
// enable backup sram
__HAL_RCC_RTC_ENABLE();
__HAL_RCC_BKPRAM_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
HAL_PWREx_EnableBkUpReg();

// need to wit for sram, I tried a few things I found on the net to wait
// based on PWR flags but none seemed to work, a simple delay does work!
HAL_Delay(5);

if(persist.magic_word != persistence_magic_word) {
// Set persistent defaults if the magic word does not match
persist.magic_word = persistence_magic_word;
persist.volume = 0.5f;
persist.backlight = 1.0f;
persist.selected_menu_item = 0;
persist.reset_target = prtFirmware;
persist.reset_error = false;
persist.last_game_offset = 0;
memset(persist.launch_path, 0, sizeof(persist.launch_path));

// clear LTDC buffer to avoid flash of uninitialised data
extern char __ltdc_start;
int len = 320 * 240 * 2;
memset(&__ltdc_start, 0, len);
}

// don't switch to game if it crashed, or home is held
if(persist.reset_target == prtGame && (gpio::read(BUTTON_HOME_GPIO_Port, BUTTON_HOME_Pin) || persist.reset_error))
persist.reset_target = prtFirmware;
// don't switch to game if it crashed, or home is held
if(persist.reset_target == prtGame && (gpio::read(BUTTON_HOME_GPIO_Port, BUTTON_HOME_Pin) || persist.reset_error))
persist.reset_target = prtFirmware;

init_api_shared();
init_api_shared();

blit_update_volume();
blit_update_volume();

// enable cycle counting
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
// enable cycle counting
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

fs_mounted = f_mount(&filesystem, "", 1) == FR_OK; // this shouldn't be necessary here right?
fs_mounted = f_mount(&filesystem, "", 1) == FR_OK; // this shouldn't be necessary here right?

i2c::init();
i2c::init();

blit::api.version_major = api_version_major;
blit::api.version_minor = api_version_minor;
blit::api.version_major = api_version_major;
blit::api.version_minor = api_version_minor;

blit::api.debug = blit_debug;
blit::api.now = HAL_GetTick;
blit::api.random = HAL_GetRandom;
blit::api.exit = blit_exit;
blit::api.debug = blit_debug;
blit::api.now = HAL_GetTick;
blit::api.random = HAL_GetRandom;
blit::api.exit = blit_exit;

blit::api.set_screen_mode = display::set_screen_mode;
blit::api.set_screen_palette = display::set_screen_palette;
blit::api.set_screen_mode_format = display::set_screen_mode_format;
blit::api.set_screen_mode = display::set_screen_mode;
blit::api.set_screen_palette = display::set_screen_palette;
blit::api.set_screen_mode_format = display::set_screen_mode_format;

display::set_screen_mode(blit::lores);
display::set_screen_mode(blit::lores);

blit::update = ::update;
blit::render = ::render;
blit::init = ::init;
blit::update = ::update;
blit::render = ::render;
blit::init = ::init;

blit::api.open_file = ::open_file;
blit::api.read_file = ::read_file;
blit::api.write_file = ::write_file;
blit::api.close_file = ::close_file;
blit::api.get_file_length = ::get_file_length;
blit::api.list_files = ::list_files;
blit::api.file_exists = ::file_exists;
blit::api.directory_exists = ::directory_exists;
blit::api.create_directory = ::create_directory;
blit::api.rename_file = ::rename_file;
blit::api.remove_file = ::remove_file;
blit::api.get_save_path = ::get_save_path;
blit::api.is_storage_available = blit_sd_mounted;

blit::api.open_file = ::open_file;
blit::api.read_file = ::read_file;
blit::api.write_file = ::write_file;
blit::api.close_file = ::close_file;
blit::api.get_file_length = ::get_file_length;
blit::api.list_files = ::list_files;
blit::api.file_exists = ::file_exists;
blit::api.directory_exists = ::directory_exists;
blit::api.create_directory = ::create_directory;
blit::api.rename_file = ::rename_file;
blit::api.remove_file = ::remove_file;
blit::api.get_save_path = ::get_save_path;
blit::api.is_storage_available = blit_sd_mounted;
blit::api.enable_us_timer = ::enable_us_timer;
blit::api.get_us_timer = ::get_us_timer;
blit::api.get_max_us_timer = ::get_max_us_timer;

blit::api.enable_us_timer = ::enable_us_timer;
blit::api.get_us_timer = ::get_us_timer;
blit::api.get_max_us_timer = ::get_max_us_timer;
blit::api.decode_jpeg_buffer = blit_decode_jpeg_buffer;
blit::api.decode_jpeg_file = blit_decode_jpeg_file;

blit::api.decode_jpeg_buffer = blit_decode_jpeg_buffer;
blit::api.decode_jpeg_file = blit_decode_jpeg_file;
blit::api.get_launch_path = ::get_launch_path;

blit::api.get_launch_path = ::get_launch_path;
blit::api.is_multiplayer_connected = multiplayer::is_connected;
blit::api.set_multiplayer_enabled = multiplayer::set_enabled;
blit::api.send_message = multiplayer::send_message;

blit::api.is_multiplayer_connected = multiplayer::is_connected;
blit::api.set_multiplayer_enabled = multiplayer::set_enabled;
blit::api.send_message = multiplayer::send_message;
blit::api.get_metadata = ::get_metadata;

blit::api.get_metadata = ::get_metadata;
blit::api.tick_function_changed = false;

blit::api.tick_function_changed = false;
blit::api.i2c_send = i2c::user_send;
blit::api.i2c_receive = i2c::user_receive;

blit::api.set_raw_cdc_enabled = set_raw_cdc_enabled;
blit::api.cdc_write = cdc_write;
blit::api.cdc_read = cdc_read;

display::init();

Expand Down Expand Up @@ -730,6 +756,10 @@ void blit_disable_user_code() {
user_code_disabled = true;
}

bool blit_user_code_disabled() {
return user_code_disabled;
}

RawMetadata *blit_get_running_game_metadata() {
if(!blit_user_code_running())
return nullptr;
Expand Down
Loading