added voltage and temperature diagnostic

This commit is contained in:
Mateusz Faderewski 2024-01-19 04:48:05 +01:00
parent e1ecb0cac3
commit 5c4ad29f61
14 changed files with 274 additions and 78 deletions

View File

@ -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

View File

@ -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 |

View File

@ -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 |
---

View File

@ -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, },

View File

@ -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;
}

View File

@ -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

View File

@ -10,10 +10,22 @@
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);
@ -25,9 +37,19 @@ static void test_sc64_cfg (void) {
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 {

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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(())
}

View File

@ -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<Local>,
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<FpgaDebugData, Error> {
fn command_fpga_debug_data_get(&mut self) -> Result<FpgaDebugData, Error> {
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<McuStackUsage, Error> {
fn command_diagnostic_data_get(&mut self) -> Result<DiagnosticData, Error> {
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()?,
})
}

View File

@ -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<Vec<u8>> for McuStackUsage {
pub struct DiagnosticDataV1 {
pub voltage: f32,
pub temperature: f32,
}
pub enum DiagnosticData {
V0(DiagnosticDataV0),
V1(DiagnosticDataV1),
Unknown,
}
impl TryFrom<Vec<u8>> for DiagnosticData {
type Error = Error;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
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)