diff --git a/components/micropython/usermodule/mp_sys_kernel.c b/components/micropython/usermodule/mp_sys_kernel.c index ac045ab7e943e5825e8178e68e70b3bc5695cff3..035eef968ea9e0a428f58583d4b81c052da1c166 100644 --- a/components/micropython/usermodule/mp_sys_kernel.c +++ b/components/micropython/usermodule/mp_sys_kernel.c @@ -8,6 +8,7 @@ #include "py/obj.h" #include "py/runtime.h" #include "st3m_console.h" +#include "st3m_fs_sd.h" #include "st3m_io.h" #include "st3m_usb.h" #include "st3m_version.h" @@ -407,6 +408,26 @@ STATIC mp_obj_t mp_battery_charging(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_battery_charging_obj, mp_battery_charging); +STATIC mp_obj_t mp_sd_oem(void) { + int32_t res = st3m_fs_sd_oem_id(); + if (res == -1) { + return mp_const_none; + } + return mp_obj_new_int(res); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_sd_oem_obj, mp_sd_oem); + +STATIC mp_obj_t mp_sd_mfg(void) { + int32_t res = st3m_fs_sd_mfg_id(); + if (res == -1) { + return mp_const_none; + } + return mp_obj_new_int(res); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_sd_mfg_obj, mp_sd_mfg); + STATIC const mp_rom_map_elem_t globals_table[] = { { MP_ROM_QSTR(MP_QSTR_scheduler_snapshot), MP_ROM_PTR(&mp_scheduler_snapshot_obj) }, @@ -422,6 +443,8 @@ STATIC const mp_rom_map_elem_t globals_table[] = { { MP_ROM_QSTR(MP_QSTR_i2c_scan), MP_ROM_PTR(&mp_i2c_scan_obj) }, { MP_ROM_QSTR(MP_QSTR_battery_charging), MP_ROM_PTR(&mp_battery_charging_obj) }, + { MP_ROM_QSTR(MP_QSTR_sd_oem), MP_ROM_PTR(&mp_sd_oem_obj) }, + { MP_ROM_QSTR(MP_QSTR_sd_mfg), MP_ROM_PTR(&mp_sd_mfg_obj) }, { MP_ROM_QSTR(MP_QSTR_RUNNING), MP_ROM_INT(eRunning) }, { MP_ROM_QSTR(MP_QSTR_READY), MP_ROM_INT(eReady) }, diff --git a/components/st3m/st3m_fs_sd.c b/components/st3m/st3m_fs_sd.c index 99b8ce3ebfc365a554e2e9f1df4e4e58de585908..3721365f1ca22cbe72563573ac1dcb49cbfe4ca6 100644 --- a/components/st3m/st3m_fs_sd.c +++ b/components/st3m/st3m_fs_sd.c @@ -263,6 +263,10 @@ static esp_err_t _st3m_fs_sd_probe_unlocked(st3m_fs_sd_props_t *props) { esp_err_to_name(ret)); return ret; } + // useful for collecting info about SDcards that are problematic, ask users + // about this to potentially add to blocklist. Also in about menu. + ESP_LOGI(TAG, "SD CID: mfg_id: %i, oem_id: %i, date: %i", _card.cid.mfg_id, + _card.cid.oem_id, _card.cid.date); _status = st3m_fs_sd_status_probed; @@ -309,6 +313,22 @@ esp_err_t st3m_fs_sd_probe(st3m_fs_sd_props_t *props) { return ret; } +int32_t st3m_fs_sd_oem_id() { + if (_status == st3m_fs_sd_status_probed || + _status == st3m_fs_sd_status_mounted) { + return _card.cid.oem_id; + } + return -1; +} + +int32_t st3m_fs_sd_mfg_id() { + if (_status == st3m_fs_sd_status_probed || + _status == st3m_fs_sd_status_mounted) { + return _card.cid.mfg_id; + } + return -1; +} + int32_t st3m_fs_sd_read10(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { if (offset != 0) { diff --git a/components/st3m/st3m_fs_sd.h b/components/st3m/st3m_fs_sd.h index 2f058acac863d5045dadda921febe3d62ce7c14d..29e65aa61e31a7bee7a329145def073f3da7d139 100644 --- a/components/st3m/st3m_fs_sd.h +++ b/components/st3m/st3m_fs_sd.h @@ -42,6 +42,12 @@ esp_err_t st3m_fs_sd_unmount(void); // No-op if card is already ejected. esp_err_t st3m_fs_sd_eject(void); +// for identifying sdcards in python land to warn about known problematic +// SDcards +int32_t st3m_fs_sd_oem_id(); + +int32_t st3m_fs_sd_mfg_id(); + // SCSI Read (10) and Write (10) compatible operations. Offset must be 0. If an // error occurs during the read/write operation, the card will be checked for // errors, and might get ejected if deemed uanvailable/broken. diff --git a/python_payload/apps/gr33nhouse/__init__.py b/python_payload/apps/gr33nhouse/__init__.py index 5d0a9aa23d5fbe40c98239cf4cb567b15e7b8db9..e3089becf3ff3b8363144b6966718e2377998e14 100644 --- a/python_payload/apps/gr33nhouse/__init__.py +++ b/python_payload/apps/gr33nhouse/__init__.py @@ -4,6 +4,7 @@ from st3m.input import InputState from st3m.ui.interactions import ScrollController from st3m.ui import colours from st3m.ui.view import ViewManager +from st3m.utils import sd_card_unreliable import st3m.wifi from ctx import Context import network @@ -16,6 +17,7 @@ from .manual import ManualInputView class ViewState(Enum): CONTENT = 1 NO_INTERNET = 2 + BAD_SDCARD = 3 class Gr33nhouseApp(Application): @@ -30,6 +32,7 @@ class Gr33nhouseApp(Application): self.background = Flow3rView() self._sc = ScrollController() self._sc.set_item_count(3) + self.acceptSdCard = False self.state = ViewState.CONTENT @@ -38,6 +41,37 @@ class Gr33nhouseApp(Application): return True def draw(self, ctx: Context) -> None: + if self.state == ViewState.BAD_SDCARD: + ctx.move_to(0, 0) + ctx.rgb(*colours.BLACK) + ctx.rectangle( + -120.0, + -120.0, + 240.0, + 240.0, + ).fill() + + ctx.save() + ctx.rgb(*colours.WHITE) + ctx.font = "Camp Font 3" + ctx.font_size = 18 + ctx.text_align = ctx.CENTER + ctx.text_baseline = ctx.MIDDLE + + ctx.move_to(0, -15) + ctx.text("Unreliable SD card detected!") + ctx.move_to(0, 5) + ctx.text("Please replace it.") + + ctx.gray(0.75) + ctx.move_to(0, 40) + ctx.font_size = 16 + ctx.text("Press the app button to") + ctx.move_to(0, 55) + ctx.text("continue anyway.") + + ctx.restore() + return if self.state == ViewState.NO_INTERNET: ctx.move_to(0, 0) ctx.rgb(*colours.BLACK) @@ -106,6 +140,20 @@ class Gr33nhouseApp(Application): self.background.think(ins, delta_ms) + if not self.acceptSdCard: + if sd_card_unreliable(): + self.state = ViewState.BAD_SDCARD + else: + self.acceptSdCard = True + + if self.state == ViewState.BAD_SDCARD and self.input.buttons.app.middle.pressed: + self.state = ViewState.CONTENT + self.acceptSdCard = True + return + + if self.state == ViewState.BAD_SDCARD: + return + if not self.is_active(): return diff --git a/python_payload/apps/updat3r/__init__.py b/python_payload/apps/updat3r/__init__.py index 1f3a31759831d59ab4fc8181309bc22cad6d35b8..cc40cec17c92253fdf0fc53c807521b0cd603c94 100644 --- a/python_payload/apps/updat3r/__init__.py +++ b/python_payload/apps/updat3r/__init__.py @@ -1,7 +1,7 @@ from st3m.application import Application, ApplicationContext from st3m.input import InputState from st3m.goose import Optional -from st3m.utils import sd_card_plugged +from st3m.utils import sd_card_plugged, sd_card_unreliable from ctx import Context import sys_kernel import urequests @@ -58,9 +58,9 @@ class UpdaterApp(Application): and not self.fetched_version and not self.vm.transitioning ): - ctx.move_to(0, 40) + ctx.move_to(0, 45) ctx.text("press the app button to") - ctx.move_to(0, 55) + ctx.move_to(0, 60) ctx.text("enter Wi-Fi settings") def version_to_number(self, version_raw: str): @@ -185,10 +185,19 @@ class UpdaterApp(Application): if not self._sd_present: return + if sd_card_unreliable(): + self._state_text = ( + "Your SD card model is\n" + "known to cause errors.\n" + "It is recommended to swap it!\n" + "Flash firmware via USB instead\nhttps://flow3r.garden/flasher" + ) + return + if self._sd_failed: self._state_text = ( "don't panic, but...\na weird SD bug happened D:\nturn off and on flow3r power (ha)\n" - "and retry. some SD cards don't\nwork for this at all tho :/\n\n" + "and retry. Please report the \nSD IDs in the About menu to the team\n\n" "if this error repeats try\nhttps://flow3r.garden/flasher\ninstead!" ) return diff --git a/python_payload/st3m/about.py b/python_payload/st3m/about.py index ee2b0a65b36fa4f572e29532df9f6a4bc6c1ebbc..48534a0961f680c2344ddf9418c71d1fc4a05b39 100644 --- a/python_payload/st3m/about.py +++ b/python_payload/st3m/about.py @@ -1,10 +1,11 @@ from ctx import Context from st3m import InputState, Responder from st3m.ui.view import BaseView, ViewTransitionSwipeRight -from st3m.utils import tau, sd_card_plugged +from st3m.utils import tau, sd_card_plugged, sd_card_unreliable from st3m.goose import List, Optional import math import os +import sys_kernel class Screen(Responder): @@ -157,7 +158,11 @@ class SpaceScreen(Screen): ctx.move_to(0, 21) ctx.font = "Camp Font 2" if self.sd_plugged: - ctx.text("SD Card") + if sd_card_unreliable(): + ctx.font_size = 20 + ctx.text("SD Card (Unreliable model)") + else: + ctx.text("SD Card") else: ctx.text("No SD Detected") @@ -175,6 +180,8 @@ class SpaceScreen(Screen): ctx.font_size = 15 ctx.move_to(0, 49) ctx.text(self.sd_text) + ctx.move_to(0, 67) + ctx.text("ID: " + str(sys_kernel.sd_oem()) + ", " + str(sys_kernel.sd_mfg())) class About(BaseView): diff --git a/python_payload/st3m/utils.py b/python_payload/st3m/utils.py index 924c6b032203c52ea33220438617d546fd622bf4..c43c5b5a2dfb01a332ea873cd916ac43fd269d17 100644 --- a/python_payload/st3m/utils.py +++ b/python_payload/st3m/utils.py @@ -147,6 +147,22 @@ def sd_card_plugged() -> bool: return False +def sd_card_unreliable(): + if not sd_card_plugged(): + return None + elif sys_kernel.sd_oem() == 21930 and sys_kernel.sd_mfg() == 200: + # for SDcards that have shown to reliably fail to download a firmware update + # these occasionally fail to download apps too. This seems to be likely an issue + # with the Espressif SDIO stack or PHY as there are many reports like this over many years + # These cards tend to work fine in an SD card reader on a PC + # The card with mfg id 200 and oem id 21930 is from the supplied SDcards at CCCamp 2023 + # We had identified two variants so far from that batch, the other variant (0, 12288) seems to have been fine + # Two of each type had been tested so far. + return True + else: + return False + + def is_simulator() -> bool: return sys_kernel.hardware_version() == "simulator"