diff --git a/docker_build.sh b/docker_build.sh index b336eb8..f244af9 100755 --- a/docker_build.sh +++ b/docker_build.sh @@ -1,6 +1,6 @@ #!/bin/bash -BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.8" +BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.9" pushd $(dirname $0) > /dev/null diff --git a/docs/02_n64_commands.md b/docs/02_n64_commands.md index c10d2c9..a832454 100644 --- a/docs/02_n64_commands.md +++ b/docs/02_n64_commands.md @@ -4,27 +4,28 @@ ## N64 commands -| id | name | arg0 | arg1 | rsp0 | rsp1 | description | -| --- | --------------------- | -------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- | -| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` | -| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version | -| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | -| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value | -| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option | -| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option | -| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value | -| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value | -| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart | -| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB | -| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length | -| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status | -| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card | -| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation | -| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart | -| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card | -| `D` | **DISK_MAPPING_SET** | pi_address | table_size | --- | --- | Set 64DD disk mapping for SD mode | -| `w` | **WRITEBACK_PENDING** | --- | --- | pending_status | --- | Get save writeback status (is write queued to the SD card) | -| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it | -| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer | -| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size | -| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase | +| id | name | arg0 | arg1 | rsp0 | rsp1 | description | +| --- | --------------------- | ------------- | ------------ | ---------------- | -------------- | ---------------------------------------------------------- | +| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` | +| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version | +| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | +| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value | +| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option | +| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option | +| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value | +| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value | +| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart | +| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB | +| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length | +| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status | +| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card | +| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation | +| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart | +| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card | +| `D` | **DISK_MAPPING_SET** | pi_address | table_size | --- | --- | Set 64DD disk mapping for SD mode | +| `w` | **WRITEBACK_PENDING** | --- | --- | pending_status | --- | Get save writeback status (is write queued to the SD card) | +| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it | +| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer | +| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size | +| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase | +| `%` | **DIAGNOSTIC_GET** | diagnostic_id | --- | --- | value | Get diagnostic data | diff --git a/docs/03_usb_interface.md b/docs/03_usb_interface.md index 8b6b089..8b85b06 100644 --- a/docs/03_usb_interface.md +++ b/docs/03_usb_interface.md @@ -170,7 +170,7 @@ Available packet IDs are listed in the [asynchronous packets](#asynchronous-pack | `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address | | `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address | | `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info | -| `%` | **STACK_USAGE_GET** | --- | --- | --- | stack_usage | Get per task stack usage | +| `%` | **DIAGNOSTIC_GET** | --- | --- | --- | diagnostic_data | Get diagnostic data | --- diff --git a/sw/bootloader/src/font.c b/sw/bootloader/src/font.c index 0732a3f..b688666 100644 --- a/sw/bootloader/src/font.c +++ b/sw/bootloader/src/font.c @@ -68,7 +68,7 @@ const uint8_t font_data[96][FONT_CHAR_BYTES] = { { 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x00, }, { 0x00, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, }, - { 0x00, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, }, + { 0x1C, 0x63, 0x63, 0x1C, 0x00, 0x00, 0x00, 0x00, }, { 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, }, { 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, }, { 0x00, 0x3C, 0x66, 0x06, 0x06, 0x06, 0x7C, 0x00, }, diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index b560f60..f6ada8f 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -48,6 +48,7 @@ typedef enum { CMD_ID_FLASH_PROGRAM = 'K', CMD_ID_FLASH_WAIT_BUSY = 'p', CMD_ID_FLASH_ERASE_BLOCK = 'P', + CMD_ID_DIAGNOSTIC_GET = '%', } sc64_cmd_id_t; typedef enum { @@ -436,3 +437,14 @@ sc64_error_t sc64_flash_erase_block (void *address) { }; return sc64_execute_cmd(&cmd); } + + +sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value) { + sc64_cmd_t cmd = { + .id = CMD_ID_DIAGNOSTIC_GET, + .arg = { id } + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *value = cmd.rsp[1]; + return error; +} diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 775acb7..4d6457b 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -93,6 +93,10 @@ typedef enum { BUTTON_MODE_DD_DISK_SWAP, } sc64_button_mode_t; +typedef enum { + DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, +} sc64_diagnostic_id_t; + typedef struct { sc64_boot_mode_t boot_mode; sc64_cic_seed_t cic_seed; @@ -174,5 +178,7 @@ sc64_error_t sc64_flash_wait_busy (void); sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size); sc64_error_t sc64_flash_erase_block (void *address); +sc64_error_t sc64_get_diagnostic (sc64_diagnostic_id_t id, uint32_t *value); + #endif diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c index bba6629..89eac45 100644 --- a/sw/bootloader/src/test.c +++ b/sw/bootloader/src/test.c @@ -10,24 +10,46 @@ static void test_sc64_cfg (void) { sc64_error_t error; + uint32_t button_state; uint32_t identifier; uint16_t major; uint16_t minor; uint32_t revision; + uint32_t tmp; + + display_printf("Waiting for the button to be released... "); + + do { + if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) { + error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error); + } + } while (button_state != 0); + + display_printf("done\n\n"); if ((error = sc64_get_identifier(&identifier)) != SC64_OK) { error_display("Command IDENTIFIER_GET failed: %d", error); return; } - + if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) { error_display("Command VERSION_GET failed: %d", error); return; } - display_printf("Identifier: 0x%08X\n\n", identifier); + if ((error = sc64_get_diagnostic(DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, &tmp)) != SC64_OK) { + error_display("Command DIAGNOSTIC_GET failed: %d", error); + return; + } - display_printf("SC64 firmware version: %d.%d.%d\n", major, minor, revision); + uint16_t voltage = (uint16_t) (tmp >> 16); + int16_t temperature = (int16_t) (tmp & 0xFFFF); + + display_printf("Identifier: 0x%08X\n", identifier); + display_printf("SC64 firmware version: %d.%d.%d\n\n", major, minor, revision); + + display_printf("Voltage: %d.%03d V\n", (voltage / 1000), (voltage % 1000)); + display_printf("Temperature: %d.%01d `C\n", (temperature / 10), (temperature % 10)); } static void test_rtc (void) { @@ -233,7 +255,7 @@ bool test_check (void) { error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error); } - return button_state != 0; + return (button_state != 0); } static struct { diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index 3a28b2d..7dad6a5 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -4,6 +4,7 @@ #include "dd.h" #include "flash.h" #include "fpga.h" +#include "hw.h" #include "isv.h" #include "led.h" #include "rtc.h" @@ -84,6 +85,10 @@ typedef enum { SD_CARD_OP_BYTE_SWAP_OFF = 5, } sd_card_op_t; +typedef enum { + DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE = 0, +} diagnostic_id_t; + typedef enum { SDRAM = (1 << 0), FLASH = (1 << 1), @@ -226,6 +231,22 @@ static bool cfg_set_save_type (save_type_t save_type) { return false; } +static bool cfg_read_diagnostic_data (uint32_t *args) { + switch (args[0]) { + case DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE: { + uint16_t voltage; + int16_t temperature; + hw_adc_read_voltage_temperature(&voltage, &temperature); + args[1] = ((uint32_t) (voltage) << 16) | ((uint32_t) (temperature)); + break; + } + default: + return true; + } + + return false; +} + uint32_t cfg_get_identifier (void) { return fpga_reg_get(REG_CFG_IDENTIFIER); @@ -700,6 +721,13 @@ void cfg_process (void) { } break; + case '%': + if (cfg_read_diagnostic_data(args)) { + cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + return; + } + break; + default: cfg_set_error(CFG_ERROR_UNKNOWN_CMD); return; diff --git a/sw/controller/src/hw.c b/sw/controller/src/hw.c index aaef8e2..28fae2d 100644 --- a/sw/controller/src/hw.c +++ b/sw/controller/src/hw.c @@ -45,23 +45,23 @@ static void hw_clock_init (void) { static void hw_timeout_init (void) { RCC->APBENR1 |= RCC_APBENR1_DBGEN; - DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM17_STOP; + DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM1_STOP; - RCC->APBENR2 |= RCC_APBENR2_TIM17EN; + RCC->APBENR2 |= RCC_APBENR2_TIM1EN; - TIM17->CR1 = TIM_CR1_OPM; - TIM17->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1); - TIM17->EGR = TIM_EGR_UG; + TIM1->CR1 = TIM_CR1_OPM; + TIM1->PSC = (((CPU_FREQ / 1000 / 1000) * TIMEOUT_US_PER_TICK) - 1); + TIM1->EGR = TIM_EGR_UG; } static void hw_timeout_start (void) { - TIM17->CR1 &= ~(TIM_CR1_CEN); - TIM17->CNT = 0; - TIM17->CR1 |= TIM_CR1_CEN; + TIM1->CR1 &= ~(TIM_CR1_CEN); + TIM1->CNT = 0; + TIM1->CR1 |= TIM_CR1_CEN; } static bool hw_timeout_occured (uint32_t timeout_us) { - uint16_t count = TIM17->CNT; + uint16_t count = TIM1->CNT; uint32_t adjusted_timeout = ((timeout_us + (TIMEOUT_US_PER_TICK - 1)) / TIMEOUT_US_PER_TICK); @@ -73,29 +73,46 @@ static bool hw_timeout_occured (uint32_t timeout_us) { } +#define DELAY_US_PER_TICK (1) #define DELAY_MS_PER_TICK (1) static void hw_delay_init (void) { RCC->APBENR1 |= RCC_APBENR1_DBGEN; - DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM16_STOP; + DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP; - RCC->APBENR2 |= RCC_APBENR2_TIM16EN; + RCC->APBENR1 |= RCC_APBENR1_TIM3EN; - TIM16->CR1 = TIM_CR1_OPM; - TIM16->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1); - TIM16->EGR = TIM_EGR_UG; + TIM3->CR1 = TIM_CR1_OPM; + TIM3->EGR = TIM_EGR_UG; +} + +void hw_delay_us (uint32_t delay_us) { + TIM3->CR1 &= ~(TIM_CR1_CEN); + TIM3->PSC = (((CPU_FREQ / 1000 / 1000) * DELAY_US_PER_TICK) - 1); + TIM3->CNT = 0; + TIM3->EGR = TIM_EGR_UG; + TIM3->CR1 |= TIM_CR1_CEN; + + uint32_t adjusted_delay = ((delay_us + (DELAY_US_PER_TICK - 1)) / DELAY_US_PER_TICK); + + uint16_t count; + do { + count = TIM3->CNT; + } while ((count < adjusted_delay) && (count != 0xFFFF)); } void hw_delay_ms (uint32_t delay_ms) { - TIM16->CR1 &= ~(TIM_CR1_CEN); - TIM16->CNT = 0; - TIM16->CR1 |= TIM_CR1_CEN; + TIM3->CR1 &= ~(TIM_CR1_CEN); + TIM3->PSC = (((CPU_FREQ / 1000) * DELAY_MS_PER_TICK) - 1); + TIM3->CNT = 0; + TIM3->EGR = TIM_EGR_UG; + TIM3->CR1 |= TIM_CR1_CEN; uint32_t adjusted_delay = ((delay_ms + (DELAY_MS_PER_TICK - 1)) / DELAY_MS_PER_TICK); uint16_t count; do { - count = TIM16->CNT; + count = TIM3->CNT; } while ((count < adjusted_delay) && (count != 0xFFFF)); } @@ -493,6 +510,61 @@ void hw_loader_get_parameters (loader_parameters_t *parameters) { } +#define ADC_VREF_CAL_POINT (3000) +#define ADC_VREF_CAL_VALUE (*(uint16_t *) (0x1FFF75AAUL)) + +#define TEMP_CAL_POINT_1 (30) +#define TEMP_CAL_VALUE_1 (*(uint16_t *) (0x1FFF75A8UL)) + +#define TEMP_CAL_POINT_2 (130) +#define TEMP_CAL_VALUE_2 (*(uint16_t *) (0x1FFF75CAUL)) + +#define TEMP_CAL_VREF (3000) + +#define TEMP_SCALE (10) + +static void hw_adc_init (void) { + RCC->APBENR2 |= RCC_APBENR2_ADCEN; + + ADC1->CFGR2 = ADC_CFGR2_CKMODE_1; + + ADC->CCR = (ADC_CCR_TSEN | ADC_CCR_VREFEN); + ADC1->CR = ADC_CR_ADVREGEN; + + hw_delay_us(120); + + ADC1->ISR = ADC_ISR_EOCAL; + ADC1->CR |= ADC_CR_ADCAL; + while (!(ADC1->ISR & ADC_ISR_EOCAL)); + + ADC1->CFGR1 = (ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT | ADC_CFGR1_SCANDIR); + ADC1->CFGR2 |= (ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSE); + ADC1->SMPR = (ADC_SMPR_SMP1_2 | ADC_SMPR_SMP1_1 | ADC_SMPR_SMP1_0); + + ADC1->ISR = ADC_ISR_CCRDY; + ADC1->CHSELR = (ADC_CHSELR_CHSEL13 | ADC_CHSELR_CHSEL12); + while (!(ADC1->ISR & ADC_ISR_CCRDY)); + + ADC1->CR |= ADC_CR_ADEN; +} + +void hw_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature) { + ADC1->CR |= ADC_CR_ADSTART; + + while (!(ADC1->ISR & ADC_ISR_EOC)); + uint16_t adc_vref = ((ADC_VREF_CAL_POINT * ADC_VREF_CAL_VALUE) / ADC1->DR); + + while (!(ADC1->ISR & ADC_ISR_EOC)); + int16_t adc_temp = ((ADC1->DR * adc_vref) / TEMP_CAL_VREF); + + *voltage = adc_vref; + *temperature = ( + ((adc_temp - TEMP_CAL_VALUE_1) * (TEMP_CAL_POINT_2 - TEMP_CAL_POINT_1) * TEMP_SCALE) / + (TEMP_CAL_VALUE_2 - TEMP_CAL_VALUE_1) + ) + (TEMP_CAL_POINT_1 * TEMP_SCALE); +} + + static void hw_led_init (void) { hw_gpio_init(GPIO_ID_LED, GPIO_OUTPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_0, 0); } @@ -530,6 +602,7 @@ void hw_app_init (void) { hw_clock_init(); hw_timeout_init(); hw_delay_init(); + hw_adc_init(); hw_led_init(); hw_misc_init(); hw_uart_init(); diff --git a/sw/controller/src/hw.h b/sw/controller/src/hw.h index ba9ce58..b74a2aa 100644 --- a/sw/controller/src/hw.h +++ b/sw/controller/src/hw.h @@ -85,6 +85,8 @@ void hw_reset (loader_parameters_t *parameters); void hw_loader_get_parameters (loader_parameters_t *parameters); +void hw_adc_read_voltage_temperature (uint16_t *voltage, int16_t *temperature); + void hw_primer_init (void); void hw_loader_init (void); void hw_app_init (void); diff --git a/sw/controller/src/usb.c b/sw/controller/src/usb.c index 882e3aa..760f68d 100644 --- a/sw/controller/src/usb.c +++ b/sw/controller/src/usb.c @@ -3,6 +3,7 @@ #include "dd.h" #include "flash.h" #include "fpga.h" +#include "hw.h" #include "rtc.h" #include "timer.h" #include "update.h" @@ -21,6 +22,9 @@ #define DEBUG_WRITE_TIMEOUT_MS (1000) +#define DIAGNOSTIC_DATA_MARKER (1 << 31) +#define DIAGNOSTIC_DATA_VERSION (1) + enum rx_state { RX_STATE_IDLE, @@ -381,15 +385,19 @@ static void usb_rx_process (void) { p.response_info.data[1] = fpga_reg_get(REG_DEBUG_1); break; - case '%': + case '%': { + uint16_t voltage; + int16_t temperature; + hw_adc_read_voltage_temperature(&voltage, &temperature); p.rx_state = RX_STATE_IDLE; p.response_pending = true; p.response_info.data_length = 16; - p.response_info.data[0] = 0; - p.response_info.data[1] = 0; - p.response_info.data[2] = 0; + p.response_info.data[0] = (DIAGNOSTIC_DATA_MARKER | DIAGNOSTIC_DATA_VERSION); + p.response_info.data[1] = (uint32_t) (voltage); + p.response_info.data[2] = (uint32_t) (temperature); p.response_info.data[3] = 0; break; + } default: p.rx_state = RX_STATE_IDLE; diff --git a/sw/deployer/src/main.rs b/sw/deployer/src/main.rs index 7dee5c0..49ddcbe 100644 --- a/sw/deployer/src/main.rs +++ b/sw/deployer/src/main.rs @@ -738,7 +738,7 @@ fn handle_info_command(connection: Connection) -> Result<(), sc64::Error> { println!(" LED blink: {}", state.led_enable); println!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address); println!(" FPGA debug data: {}", state.fpga_debug_data); - println!(" MCU stack usage: {}", state.mcu_stack_usage); + println!(" Diagnostic data: {}", state.diagnostic_data); Ok(()) } diff --git a/sw/deployer/src/sc64/mod.rs b/sw/deployer/src/sc64/mod.rs index 5f0e8eb..1dafd80 100644 --- a/sw/deployer/src/sc64/mod.rs +++ b/sw/deployer/src/sc64/mod.rs @@ -12,7 +12,7 @@ pub use self::{ server::ServerEvent, types::{ BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode, - DebugPacket, DiskPacket, DiskPacketKind, FpgaDebugData, McuStackUsage, SaveType, + DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType, SaveWriteback, Switch, TvType, }, }; @@ -55,7 +55,7 @@ pub struct DeviceState { pub led_enable: Switch, pub datetime: DateTime, pub fpga_debug_data: FpgaDebugData, - pub mcu_stack_usage: McuStackUsage, + pub diagnostic_data: DiagnosticData, } const SC64_V2_IDENTIFIER: &[u8; 4] = b"SCv2"; @@ -350,7 +350,7 @@ impl SC64 { Ok(u32::from_be_bytes(data[0..4].try_into().unwrap()).try_into()?) } - fn command_debug_get(&mut self) -> Result { + fn command_fpga_debug_data_get(&mut self) -> Result { let data = self.link.execute_command(&Command { id: b'?', args: [0, 0], @@ -359,7 +359,7 @@ impl SC64 { Ok(data.try_into()?) } - fn command_stack_usage_get(&mut self) -> Result { + fn command_diagnostic_data_get(&mut self) -> Result { let data = self.link.execute_command(&Command { id: b'%', args: [0, 0], @@ -557,8 +557,8 @@ impl SC64 { rom_extended_enable: get_config!(self, RomExtendedEnable)?, led_enable: get_setting!(self, LedEnable)?, datetime: self.get_datetime()?, - fpga_debug_data: self.command_debug_get()?, - mcu_stack_usage: self.command_stack_usage_get()?, + fpga_debug_data: self.command_fpga_debug_data_get()?, + diagnostic_data: self.command_diagnostic_data_get()?, }) } diff --git a/sw/deployer/src/sc64/types.rs b/sw/deployer/src/sc64/types.rs index 505db68..58ffc59 100644 --- a/sw/deployer/src/sc64/types.rs +++ b/sw/deployer/src/sc64/types.rs @@ -828,37 +828,81 @@ impl Display for FpgaDebugData { } } -pub struct McuStackUsage { +pub struct DiagnosticDataV0 { pub cic: u32, pub rtc: u32, pub led: u32, pub gvr: u32, } -impl TryFrom> for McuStackUsage { +pub struct DiagnosticDataV1 { + pub voltage: f32, + pub temperature: f32, +} + +pub enum DiagnosticData { + V0(DiagnosticDataV0), + V1(DiagnosticDataV1), + Unknown, +} + +impl TryFrom> for DiagnosticData { type Error = Error; fn try_from(value: Vec) -> Result { - if value.len() != 16 { - return Err(Error::new("Invalid data length for MCU stack usage")); + if value.len() < 4 { + return Err(Error::new("Invalid data length for diagnostic data")); + } + let raw_version = u32::from_be_bytes(value[0..4].try_into().unwrap()); + let unversioned = raw_version & (1 << 31) == 0; + let version = raw_version & !(1 << 31); + + if unversioned { + if value.len() != 16 { + return Err(Error::new("Invalid data length for V0 diagnostic data")); + } + return Ok(DiagnosticData::V0(DiagnosticDataV0 { + cic: u32::from_be_bytes(value[0..4].try_into().unwrap()), + rtc: u32::from_be_bytes(value[4..8].try_into().unwrap()), + led: u32::from_be_bytes(value[8..12].try_into().unwrap()), + gvr: u32::from_be_bytes(value[12..16].try_into().unwrap()), + })); + } + + match version { + 1 => { + if value.len() != 16 { + return Err(Error::new("Invalid data length for V1 diagnostic data")); + } + let raw_voltage = u32::from_be_bytes(value[4..8].try_into().unwrap()) as f32; + let raw_temperature = u32::from_be_bytes(value[8..12].try_into().unwrap()) as f32; + Ok(DiagnosticData::V1(DiagnosticDataV1 { + voltage: raw_voltage / 1000.0, + temperature: raw_temperature / 10.0, + })) + } + _ => Ok(DiagnosticData::Unknown), } - Ok(McuStackUsage { - cic: u32::from_be_bytes(value[0..4].try_into().unwrap()), - rtc: u32::from_be_bytes(value[4..8].try_into().unwrap()), - led: u32::from_be_bytes(value[8..12].try_into().unwrap()), - gvr: u32::from_be_bytes(value[12..16].try_into().unwrap()), - }) } } -impl Display for McuStackUsage { +impl Display for DiagnosticData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.cic > 0 { - f.write_fmt(format_args!("CIC: {}, ", self.cic))?; + match self { + DiagnosticData::V0(d) => { + if d.cic > 0 { + f.write_fmt(format_args!("CIC: {}, ", d.cic))?; + } + f.write_fmt(format_args!( + "RTC: {}, LED: {}, GVR: {}", + d.rtc, d.led, d.gvr + )) + } + DiagnosticData::V1(d) => f.write_fmt(format_args!( + "{:.03} V / {:.01} °C", + d.voltage, d.temperature + )), + DiagnosticData::Unknown => f.write_str("Unknown"), } - f.write_fmt(format_args!( - "RTC: {}, LED: {}, GVR: {}", - self.rtc, self.led, self.gvr - )) } } @@ -874,7 +918,7 @@ macro_rules! get_config { macro_rules! get_setting { ($sc64:ident, $setting:ident) => {{ - // Note: remove 'allow(irrefutable_let_patterns)' below when more settings are added + // NOTE: remove 'allow(irrefutable_let_patterns)' below when more settings are added #[allow(irrefutable_let_patterns)] if let Setting::$setting(value) = $sc64.command_setting_get(SettingId::$setting)? { Ok(value)