mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
added voltage and temperature diagnostic
This commit is contained in:
parent
e1ecb0cac3
commit
5c4ad29f61
@ -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
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
## 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 |
|
||||
@ -28,3 +28,4 @@
|
||||
| `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 |
|
||||
|
@ -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 |
|
||||
|
||||
---
|
||||
|
||||
|
@ -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, },
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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()?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -828,38 +828,82 @@ 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"));
|
||||
}
|
||||
Ok(McuStackUsage {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: {}",
|
||||
self.rtc, self.led, self.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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! get_config {
|
||||
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user