diff --git a/source/board/steami/steami32.c b/source/board/steami/steami32.c index 0b1326836..48142efc9 100644 --- a/source/board/steami/steami32.c +++ b/source/board/steami/steami32.c @@ -112,6 +112,10 @@ typedef enum { TASK_READ_SECTOR, + TASK_WRITE_CONFIG, + TASK_READ_CONFIG, + TASK_CLEAR_CONFIG, + TASK_WAIT_FLASH_BUSY, } steami_task; @@ -205,6 +209,40 @@ static void on_I2C_receive_command(steami_i2c_command cmd, uint8_t* rx, uint16_t break; } + case WRITE_CONFIG:{ + if(is_busy()){ + steami_uart_write_string("ERROR I2C busy.\n"); + break; + } + if(rx_len < 3){ + error_status_bad_parameter(&status_error); + break; + } + current_task = TASK_WRITE_CONFIG; + memcpy(task_rx, rx, rx_len); + task_rx_len = rx_len; + break; + } + + case READ_CONFIG:{ + if(is_busy()){ + steami_uart_write_string("ERROR I2C busy.\n"); + break; + } + current_task = TASK_READ_CONFIG; + memcpy(task_rx, rx, rx_len); + task_rx_len = rx_len; + break; + } + + case CLEAR_CONFIG: + if(is_busy()){ + steami_uart_write_string("ERROR I2C busy.\n"); + break; + } + current_task = TASK_CLEAR_CONFIG; + break; + case STATUS:{ uint8_t status = 0x00; @@ -394,6 +432,69 @@ void process_task() } + case TASK_WRITE_CONFIG:{ + if( steami_flash_is_busy() ){ + break; + } + // task_rx: [offset_hi, offset_lo, len, data...] + if( task_rx_len >= 3 ){ + uint16_t offset = ((uint16_t)task_rx[0] << 8) | task_rx[1]; + uint16_t len = task_rx[2]; + if( len > task_rx_len - 3 ){ + error_status_bad_parameter(&status_error); + steami_uart_write_string("ERROR Bad config write parameters.\n"); + } + else if( steami_flash_write_config(offset, task_rx + 3, len) ){ + steami_uart_write_string("Config written.\n"); + } + else{ + error_status_set_last_command_fail(&status_error); + steami_uart_write_string("ERROR Unable to write config.\n"); + } + } + else{ + error_status_bad_parameter(&status_error); + } + current_task = TASK_NONE; + break; + } + + case TASK_READ_CONFIG:{ + if( steami_flash_is_busy() ){ + break; + } + if( task_rx_len == 2 ){ + uint16_t offset = ((uint16_t)task_rx[0] << 8) | task_rx[1]; + if( steami_flash_read_config(offset, buffer_sector, STEAMI_FLASH_SECTOR) ){ + steami_i2c_set_tx_data(buffer_sector, STEAMI_FLASH_SECTOR); + } + else{ + error_status_set_last_command_fail(&status_error); + steami_uart_write_string("ERROR Unable to read config.\n"); + } + } + else{ + error_status_bad_parameter(&status_error); + } + current_task = TASK_NONE; + break; + } + + case TASK_CLEAR_CONFIG:{ + if( steami_flash_is_busy() ){ + break; + } + if( steami_flash_erase_config() ){ + steami_uart_write_string("Config erased.\n"); + } + else{ + error_status_set_last_command_fail(&status_error); + steami_uart_write_string("ERROR Unable to erase config.\n"); + } + current_task = TASK_NONE; + break; + } + case TASK_WAIT_FLASH_BUSY: if( !steami_flash_is_busy() ){ current_task = TASK_NONE; diff --git a/source/board/steami/steami_flash.c b/source/board/steami/steami_flash.c index e8ae58d2e..41caeb01d 100644 --- a/source/board/steami/steami_flash.c +++ b/source/board/steami/steami_flash.c @@ -138,7 +138,7 @@ uint32_t steami_flash_get_size(){ for(uint16_t i = 0; i < STEAMI_FLASH_MAX_DATA_SIZE; ++i){ if( data[i] == 0xFF ){ - return STEAMI_FLASH_FILE_ADDR + offset + i; + return offset + i; } } @@ -219,4 +219,49 @@ uint16_t steami_flash_read_file(uint8_t* data, uint16_t data_len, uint32_t offse bool steami_flash_is_busy(){ return w25q64_is_busy(); +} + +bool steami_flash_erase_config(){ + steami_led_turn_on_blue(); + + w25q64_write_enable(); + wait_w25q64_wel(); + wait_w25q64_busy(); + bool result = w25q64_sector_erase(STEAMI_FLASH_CONFIG_ADDR); + wait_w25q64_busy(); + + steami_led_turn_off_blue(); + return result; +} + +bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len){ + if( len == 0 || len > 256 ){ + return false; + } + if( offset + len > STEAMI_FLASH_CONFIG_SIZE ){ + return false; + } + if( (offset % 256) + len > 256 ){ + return false; + } + + steami_led_turn_on_blue(); + + w25q64_write_enable(); + wait_w25q64_wel(); + wait_w25q64_busy(); + bool result = w25q64_page_program(data, STEAMI_FLASH_CONFIG_ADDR + offset, len); + wait_w25q64_busy(); + + steami_led_turn_off_blue(); + return result; +} + +bool steami_flash_read_config(uint16_t offset, uint8_t* data, uint16_t len){ + if( offset + len > STEAMI_FLASH_CONFIG_SIZE ){ + return false; + } + + wait_w25q64_busy(); + return w25q64_read_data(data, STEAMI_FLASH_CONFIG_ADDR + offset, len); } \ No newline at end of file diff --git a/source/board/steami/steami_flash.h b/source/board/steami/steami_flash.h index a9d0a6771..bd1e181fa 100644 --- a/source/board/steami/steami_flash.h +++ b/source/board/steami/steami_flash.h @@ -3,10 +3,12 @@ #include #include -#define STEAMI_FLASH_FILE_ADDR (uint32_t)0x00000000 -#define STEAMI_FLASH_NAME_ADDR (uint32_t)0x007FF000 +#define STEAMI_FLASH_FILE_ADDR (uint32_t)0x00000000 +#define STEAMI_FLASH_CONFIG_ADDR (uint32_t)0x007FE000 /* last 4K before filename */ +#define STEAMI_FLASH_CONFIG_SIZE 4096 +#define STEAMI_FLASH_NAME_ADDR (uint32_t)0x007FF000 -#define STEAMI_FLASH_FILE_SIZE 8384512 +#define STEAMI_FLASH_FILE_SIZE 8380416 /* 0x7FE000 - 0x000000 (excludes config) */ #define STEAMI_FLASH_SECTOR 256 #define STEAMI_FLASH_4K 4096 @@ -108,4 +110,31 @@ uint16_t steami_flash_read_file(uint8_t* data, uint16_t data_len, uint32_t offse * * @return TRUE if the flash is buzy flag is high, FALSE otherwise */ -bool steami_flash_is_busy(); \ No newline at end of file +bool steami_flash_is_busy(); + +/** + * @brief Erase the 4K config zone at STEAMI_FLASH_CONFIG_ADDR. + * + * @return TRUE if successful, FALSE otherwise + */ +bool steami_flash_erase_config(); + +/** + * @brief Write data to the config zone. + * + * @param offset byte offset within the config zone (0-4095) + * @param data data array + * @param len number of bytes to write (max 28 per call via I2C, must stay within one 256-byte page) + * @return TRUE if successful, FALSE otherwise + */ +bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len); + +/** + * @brief Read data from the config zone. + * + * @param offset byte offset within the config zone (0-4095) + * @param data buffer for read data + * @param len number of bytes to read + * @return TRUE if successful, FALSE otherwise + */ +bool steami_flash_read_config(uint16_t offset, uint8_t* data, uint16_t len); \ No newline at end of file diff --git a/source/board/steami/steami_i2c.c b/source/board/steami/steami_i2c.c index 44a53c1f1..716e95d38 100644 --- a/source/board/steami/steami_i2c.c +++ b/source/board/steami/steami_i2c.c @@ -35,6 +35,9 @@ static bool is_command_valid(uint8_t cmd){ case GET_FILENAME: case WRITE_DATA: case READ_SECTOR: + case WRITE_CONFIG: + case READ_CONFIG: + case CLEAR_CONFIG: case STATUS: case ERROR_STATUS: return true; @@ -65,6 +68,15 @@ static uint16_t get_argument_byte_number(uint8_t cmd){ case READ_SECTOR: return 2; + case WRITE_CONFIG: + return 31; /* fixed frame: [offset_hi, offset_lo, len, data(28 bytes max)] */ + + case READ_CONFIG: + return 2; + + case CLEAR_CONFIG: + return 0; + case STATUS: return 0; diff --git a/source/board/steami/steami_i2c.h b/source/board/steami/steami_i2c.h index 5fdda83cd..6249006cd 100644 --- a/source/board/steami/steami_i2c.h +++ b/source/board/steami/steami_i2c.h @@ -26,7 +26,11 @@ typedef enum { WRITE_DATA = 0x11, READ_SECTOR = 0x20, - + + WRITE_CONFIG = 0x30, + READ_CONFIG = 0x31, + CLEAR_CONFIG = 0x32, + STATUS = 0x80, ERROR_STATUS = 0x81, } steami_i2c_command;