From 741e83444e330c5aa001d1c34c41bd1997b3e32a Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Fri, 10 Feb 2023 21:38:49 +0100 Subject: [PATCH] [SC64][SW] Added LED I/O blinking persistent setting --- docs/02_usb_commands.md | 2 ++ docs/03_n64_commands.md | 2 ++ docs/04_config_options.md | 23 ++++++++++++++++++ sw/bootloader/src/sc64.c | 14 +++++++++++ sw/bootloader/src/sc64.h | 6 +++++ sw/controller/src/cfg.c | 48 +++++++++++++++++++++++++++++++++++++ sw/controller/src/cfg.h | 2 ++ sw/controller/src/cic.c | 4 ++-- sw/controller/src/led.c | 26 +++++++++++++++----- sw/controller/src/rtc.c | 50 +++++++++++++++++++++++++++++++++++++-- sw/controller/src/rtc.h | 20 ++++++++++------ sw/controller/src/usb.c | 14 +++++++++++ sw/pc/sc64.py | 26 ++++++++++++++++++++ 13 files changed, 220 insertions(+), 17 deletions(-) diff --git a/docs/02_usb_commands.md b/docs/02_usb_commands.md index 6eb64e2..5d6b598 100644 --- a/docs/02_usb_commands.md +++ b/docs/02_usb_commands.md @@ -11,6 +11,8 @@ | `B` | **CIC_PARAMS_SET** | cic_params_0 | cic_params_1 | --- | --- | Set CIC disable/mode/seed/checksum | | `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option | | `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option | +| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting | +| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting | | `t` | **TIME_GET** | --- | --- | --- | time | Get current RTC value | | `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set RTC value | | `m` | **MEMORY_READ** | address | length | --- | data | Read data from specified memory address | diff --git a/docs/03_n64_commands.md b/docs/03_n64_commands.md index 02725e9..d7d7ed6 100644 --- a/docs/03_n64_commands.md +++ b/docs/03_n64_commands.md @@ -9,6 +9,8 @@ | `v` | **VERSION_GET** | --- | --- | api_version | --- | Get command API 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 | +| `c` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option | +| `C` | **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 RTC value | | `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart | diff --git a/docs/04_config_options.md b/docs/04_config_options.md index 62344a6..301e51c 100644 --- a/docs/04_config_options.md +++ b/docs/04_config_options.md @@ -14,6 +14,8 @@ - [`12`: **BUTTON\_STATE**](#12-button_state) - [`13`: **BUTTON\_MODE**](#13-button_mode) - [`14`: **ROM\_EXTENDED\_ENABLE**](#14-rom_extended_enable) +- [Supported persistent setting options](#supported-persistent-setting-options) + - [`0`: **LED\_ENABLE**](#0-led_enable) --- @@ -231,3 +233,24 @@ type: *bool* | default: `0` - `1` - ROM extended PI access is enabled Use this setting to enable PI access for extended ROM data located inside flash memory. + +--- + +## Supported persistent setting options + +These options are similar to config options but state is persisted through power cycles. + +| id | name | type | description | +| --- | -------------- | ------ | --------------------------------------------- | +| `0` | **LED_ENABLE** | *bool* | Enables or disables LED I/O activity blinking | + +--- + +### `0`: **LED_ENABLE** + +type: *bool* | default: `1` + +- `0` - LED I/O activity blinking is disabled +- `1` - LED I/O activity blinking is enabled + +Use this setting to enable or disable LED I/O activity blinking. diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index c2c96ed..b377465 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -27,6 +27,8 @@ typedef enum { SC64_CMD_VERSION_GET = 'v', SC64_CMD_CONFIG_GET = 'c', SC64_CMD_CONFIG_SET = 'C', + SC64_CMD_SETTING_GET = 'a', + SC64_CMD_SETTING_SET = 'A', SC64_CMD_TIME_GET = 't', SC64_CMD_TIME_SET = 'T', SC64_CMD_USB_READ = 'm', @@ -126,6 +128,18 @@ void sc64_set_config (sc64_cfg_id_t id, uint32_t value) { sc64_execute_cmd(SC64_CMD_CONFIG_SET, args, NULL); } +uint32_t sc64_get_setting (sc64_setting_id_t id) { + uint32_t args[2] = { id, 0 }; + uint32_t result[2]; + sc64_execute_cmd(SC64_CMD_SETTING_GET, args, result); + return result[1]; +} + +void sc64_set_setting (sc64_setting_id_t id, uint32_t value) { + uint32_t args[2] = { id, value }; + sc64_execute_cmd(SC64_CMD_SETTING_SET, args, NULL); +} + void sc64_get_boot_info (sc64_boot_info_t *info) { info->boot_mode = (sc64_boot_mode_t) sc64_get_config(CFG_ID_BOOT_MODE); info->cic_seed = (sc64_cic_seed_t) sc64_get_config(CFG_ID_CIC_SEED); diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index b8bdb9d..887ea83 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -34,6 +34,10 @@ typedef enum { CFG_ID_ROM_EXTENDED_ENABLE, } sc64_cfg_id_t; +typedef enum { + SETTING_ID_LED_ENABLE, +} sc64_setting_id_t; + typedef enum { DD_MODE_DISABLED = 0, DD_MODE_REGS = 1, @@ -121,6 +125,8 @@ void sc64_irq_clear (void); uint32_t sc64_get_config (sc64_cfg_id_t id); void sc64_set_config (sc64_cfg_id_t id, uint32_t value); +uint32_t sc64_get_setting (sc64_setting_id_t id); +void sc64_set_setting (sc64_setting_id_t id, uint32_t value); void sc64_get_boot_info (sc64_boot_info_t *info); void sc64_get_time (sc64_rtc_time_t *t); diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index 783ec3b..649a1f1 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -32,6 +32,10 @@ typedef enum { CFG_ID_ROM_EXTENDED_ENABLE, } cfg_id_t; +typedef enum { + SETTING_ID_LED_ENABLE, +} setting_id_t; + typedef enum { DD_MODE_DISABLED = 0, DD_MODE_REGS = 1, @@ -356,6 +360,36 @@ bool cfg_update (uint32_t *args) { return false; } +bool cfg_query_setting (uint32_t *args) { + rtc_settings_t settings = (*rtc_get_settings()); + + switch (args[0]) { + case SETTING_ID_LED_ENABLE: + args[1] = settings.led_enabled; + break; + default: + return true; + } + + return false; +} + +bool cfg_update_setting (uint32_t *args) { + rtc_settings_t settings = (*rtc_get_settings()); + + switch (args[0]) { + case SETTING_ID_LED_ENABLE: + settings.led_enabled = args[1]; + break; + default: + return true; + } + + rtc_set_settings(&settings); + + return false; +} + bool cfg_set_rom_write_enable (bool value) { uint32_t scr = fpga_reg_get(REG_CFG_SCR); cfg_change_scr_bits(CFG_SCR_ROM_WRITE_ENABLED, value); @@ -447,6 +481,20 @@ void cfg_process (void) { args[1] = prev_cfg[1]; break; + case 'a': + if (cfg_query_setting(args)) { + cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + return; + } + break; + + case 'A': + if (cfg_update_setting(args)) { + cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + return; + } + break; + case 't': cfg_get_time(args); break; diff --git a/sw/controller/src/cfg.h b/sw/controller/src/cfg.h index 4d3b409..ef9efac 100644 --- a/sw/controller/src/cfg.h +++ b/sw/controller/src/cfg.h @@ -19,6 +19,8 @@ typedef enum { uint32_t cfg_get_version (void); bool cfg_query (uint32_t *args); bool cfg_update (uint32_t *args); +bool cfg_query_setting (uint32_t *args); +bool cfg_update_setting (uint32_t *args); bool cfg_set_rom_write_enable (bool value); save_type_t cfg_get_save_type (void); void cfg_get_time (uint32_t *args); diff --git a/sw/controller/src/cic.c b/sw/controller/src/cic.c index ccf8dbe..d839d63 100644 --- a/sw/controller/src/cic.c +++ b/sw/controller/src/cic.c @@ -318,7 +318,7 @@ static void cic_soft_reset_timeout (void) { static void cic_soft_reset (void) { cic_read(); - hw_tim_setup(TIM_ID_CIC, 550, cic_soft_reset_timeout); + hw_tim_setup(TIM_ID_CIC, 500, cic_soft_reset_timeout); task_yield(); } @@ -367,7 +367,7 @@ void cic_task (void) { cic_write_id(region); - hw_tim_setup(TIM_ID_CIC, 1000, cic_write_id_failed); + hw_tim_setup(TIM_ID_CIC, 100, cic_write_id_failed); cic_write_seed(); hw_tim_stop(TIM_ID_CIC); diff --git a/sw/controller/src/led.c b/sw/controller/src/led.c index ba5cd69..2cefc03 100644 --- a/sw/controller/src/led.c +++ b/sw/controller/src/led.c @@ -1,6 +1,7 @@ #include #include "hw.h" #include "led.h" +#include "rtc.h" #include "task.h" #include "timer.h" @@ -26,16 +27,29 @@ static void led_task_resume (void) { task_set_ready(TASK_ID_LED); } +static void led_set_state (bool state, bool force) { + rtc_settings_t *settings = rtc_get_settings(); + if (settings->led_enabled || force) { + if (state) { + hw_gpio_set(GPIO_ID_LED); + } else { + hw_gpio_reset(GPIO_ID_LED); + } + } else { + hw_gpio_reset(GPIO_ID_LED); + } +} + static void led_update_error_mode (void) { if (error_mode) { if (!(cic_error || rtc_error)) { - hw_gpio_reset(GPIO_ID_LED); + led_set_state(false, true); error_mode = false; act_timer = 0; } } else { if (cic_error || rtc_error) { - hw_gpio_reset(GPIO_ID_LED); + led_set_state(false, true); error_mode = true; error_timer = 0; } @@ -58,10 +72,10 @@ static void led_process_errors (void) { if (error_timer >= LED_ERROR_TICKS_PERIOD) { uint32_t error_cycle = (error_timer % LED_ERROR_TICKS_PERIOD); if (error_cycle == LED_ERROR_TICKS_ON) { - hw_gpio_set(GPIO_ID_LED); + led_set_state(true, true); } if (error_cycle == 0) { - hw_gpio_reset(GPIO_ID_LED); + led_set_state(false, true); } } } @@ -78,10 +92,10 @@ static void led_process_act (void) { if (act_timer > 0) { act_timer -= 1; if (act_timer == LED_ACT_TICKS_ON) { - hw_gpio_set(GPIO_ID_LED); + led_set_state(true, false); } if (act_timer == 0) { - hw_gpio_reset(GPIO_ID_LED); + led_set_state(false, false); } } } diff --git a/sw/controller/src/rtc.c b/sw/controller/src/rtc.c index 3aad083..5ffd443 100644 --- a/sw/controller/src/rtc.c +++ b/sw/controller/src/rtc.c @@ -18,15 +18,17 @@ #define RTC_ADDRESS_OSCTRIM (0x08) #define RTC_ADDRESS_SRAM_MAGIC (0x20) #define RTC_ADDRESS_SRAM_REGION (0x24) +#define RTC_ADDRESS_SRAM_VERSION (0x28) +#define RTC_ADDRESS_SRAM_SETTINGS (0x2C) #define RTC_RTCSEC_ST (1 << 7) #define RTC_RTCWKDAY_VBATEN (1 << 3) #define RTC_RTCWKDAY_OSCRUN (1 << 5) +#define RTC_SETTINGS_VERSION (1) + -static uint8_t rtc_region = 0xFF; -static volatile bool rtc_region_pending = false; static rtc_time_t rtc_time = { .second = 0x00, .minute = 0x00, @@ -39,6 +41,14 @@ static rtc_time_t rtc_time = { static bool rtc_time_valid = false; static volatile bool rtc_time_pending = false; +static uint8_t rtc_region = 0xFF; +static volatile bool rtc_region_pending = false; + +static rtc_settings_t rtc_settings = { + .led_enabled = true, +}; +static volatile bool rtc_settings_pending = false; + static const uint8_t rtc_regs_bit_mask[7] = { 0b01111111, 0b01111111, @@ -151,10 +161,19 @@ static void rtc_write_region (void) { rtc_write(RTC_ADDRESS_SRAM_REGION, &rtc_region, 1); } +static void rtc_read_settings (void) { + rtc_read(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings)); +} + +static void rtc_write_settings (void) { + rtc_write(RTC_ADDRESS_SRAM_SETTINGS, (uint8_t *) (&rtc_settings), sizeof(rtc_settings)); +} + static void rtc_init (void) { bool uninitialized = false; const char *magic = "SC64"; uint8_t buffer[4]; + uint32_t settings_version; rtc_read(RTC_ADDRESS_SRAM_MAGIC, buffer, 4); @@ -172,6 +191,14 @@ static void rtc_init (void) { rtc_write_time(); rtc_write_region(); } + + rtc_read(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4); + + if (uninitialized || (settings_version != RTC_SETTINGS_VERSION)) { + settings_version = RTC_SETTINGS_VERSION; + rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4); + rtc_write_settings(); + } } @@ -222,10 +249,24 @@ void rtc_set_region (uint8_t region) { rtc_region_pending = true; } +rtc_settings_t *rtc_get_settings (void) { + return (&rtc_settings); +} + +void rtc_set_settings (rtc_settings_t *settings) { + hw_tim_disable_irq(TIM_ID_LED); + + rtc_settings = *settings; + rtc_settings_pending = true; + + hw_tim_enable_irq(TIM_ID_LED); +} + void rtc_task (void) { rtc_init(); rtc_read_region(); + rtc_read_settings(); while (1) { if (rtc_time_pending) { @@ -238,6 +279,11 @@ void rtc_task (void) { rtc_write_region(); } + if (rtc_settings_pending) { + rtc_settings_pending = false; + rtc_write_settings(); + } + rtc_read_time(); hw_tim_setup(TIM_ID_RTC, 50, rtc_task_resume); diff --git a/sw/controller/src/rtc.h b/sw/controller/src/rtc.h index 3df6502..06c70cf 100644 --- a/sw/controller/src/rtc.h +++ b/sw/controller/src/rtc.h @@ -7,20 +7,26 @@ typedef struct { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t weekday; - uint8_t day; - uint8_t month; - uint8_t year; + volatile uint8_t second; + volatile uint8_t minute; + volatile uint8_t hour; + volatile uint8_t weekday; + volatile uint8_t day; + volatile uint8_t month; + volatile uint8_t year; } rtc_time_t; +typedef struct { + volatile bool led_enabled; +} rtc_settings_t; + bool rtc_get_time (rtc_time_t *time); void rtc_set_time (rtc_time_t *time); uint8_t rtc_get_region (void); void rtc_set_region (uint8_t region); +rtc_settings_t *rtc_get_settings (void); +void rtc_set_settings (rtc_settings_t *settings); void rtc_task (void); void rtc_process (void); diff --git a/sw/controller/src/usb.c b/sw/controller/src/usb.c index 9a1e367..43e773f 100644 --- a/sw/controller/src/usb.c +++ b/sw/controller/src/usb.c @@ -189,6 +189,20 @@ static void usb_rx_process (void) { p.response_pending = true; break; + case 'a': + p.response_error = cfg_query_setting(p.rx_args); + p.rx_state = RX_STATE_IDLE; + p.response_pending = true; + p.response_info.data_length = 4; + p.response_info.data[0] = p.rx_args[1]; + break; + + case 'A': + p.response_error = cfg_update_setting(p.rx_args); + p.rx_state = RX_STATE_IDLE; + p.response_pending = true; + break; + case 't': cfg_get_time(p.rx_args); p.rx_state = RX_STATE_IDLE; diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 50ea2a1..8c1715c 100755 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -243,6 +243,9 @@ class SC64: BUTTON_MODE = 13 ROM_EXTENDED_ENABLE = 14 + class __SettingId(IntEnum): + LED_ENABLE = 0 + class __UpdateError(IntEnum): OK = 0 TOKEN = 1 @@ -342,6 +345,19 @@ class SC64: raise ValueError(f'Could not get config {config.name}') return self.__get_int(data) + def __set_setting(self, setting: __SettingId, value: int) -> None: + try: + self.__link.execute_cmd(cmd=b'A', args=[setting, value]) + except ConnectionException: + raise ValueError(f'Could not set setting {setting.name} to {value:08X}') + + def __get_setting(self, setting: __SettingId) -> int: + try: + data = self.__link.execute_cmd(cmd=b'a', args=[setting, 0]) + except ConnectionException: + raise ValueError(f'Could not get setting {setting.name}') + return self.__get_int(data) + def __write_memory(self, address: int, data: bytes) -> None: if (len(data) > 0): self.__link.execute_cmd(cmd=b'M', args=[address, len(data)], data=data, timeout=20.0) @@ -424,6 +440,7 @@ class SC64: 'button_state': bool(self.__get_config(self.__CfgId.BUTTON_STATE)), 'button_mode': self.__ButtonMode(self.__get_config(self.__CfgId.BUTTON_MODE)), 'rom_extended_enable': bool(self.__get_config(self.__CfgId.ROM_EXTENDED_ENABLE)), + 'led_enable': bool(self.__get_setting(self.__SettingId.LED_ENABLE)), } def debug_send(self, datatype: __DebugDatatype, data: bytes) -> None: @@ -531,6 +548,9 @@ class SC64: self.__link.execute_cmd(cmd=b'B', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])]) return (seed, checksum) + def set_led_enable(self, enabled: bool) -> None: + self.__set_setting(self.__SettingId.LED_ENABLE, enabled) + def update_firmware(self, data: bytes, status_callback: Optional[Callable[[str], None]]=None) -> None: address = self.__Address.FIRMWARE self.__write_memory(address, data) @@ -816,6 +836,7 @@ if __name__ == '__main__': parser.add_argument('--update-bootloader', metavar='file', help='update SC64 bootloader (not recommended, use --update-firmware instead)') parser.add_argument('--reset-state', action='store_true', help='reset SC64 internal state') parser.add_argument('--print-state', action='store_true', help='print SC64 internal state') + parser.add_argument('--led-enabled', metavar='{true,false}', help='disable or enable LED I/O activity blinking') parser.add_argument('--boot', type=SC64.BootMode, action=EnumAction, help='set boot mode') parser.add_argument('--tv', type=SC64.TVType, action=EnumAction, help='force TV type to set value') parser.add_argument('--cic', type=SC64.CICSeed, action=EnumAction, help='force CIC seed to set value') @@ -874,6 +895,11 @@ if __name__ == '__main__': value = getattr(value, 'name') print(f' {key}: {value}') + if (args.led_enabled != None): + value = (args.led_enabled == 'true') + sc64.set_led_enable(value) + print(f'LED blinking set to [{"ENABLED" if value else "DISABLED"}]') + if (args.boot != None): sc64.set_boot_mode(args.boot) print(f'Boot mode set to [{args.boot.name}]')