diff --git a/docs/environment.rst b/docs/environment.rst index 36404eb81f928..ed32cfe89dce2 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -1,65 +1,77 @@ Environment Variables ===================== -CircuitPython 8.0.0 introduces support for environment variables. Environment -variables are commonly used to store "secrets" such as Wi-Fi passwords and API -keys. This method *does not* make them secure. It only separates them from the -code. +CircuitPython provides support for environment variables. These values +can be examined by user code, and are also used as settings by CircuitPython during startup. -CircuitPython uses a file called ``settings.toml`` at the drive root (no -folder) as the environment. User code can access the values from the file -using `os.getenv()`. It is recommended to save any values used repeatedly in a -variable because `os.getenv()` will parse the ``settings.toml`` file contents -on every access. +CircuitPython looks for a file called ``settings.toml`` at the ``CIRCUITPY`` drive root +to find the values of environment variables, +The file format is a subset of the `TOML config file language `__. -CircuitPython only supports a subset of the full toml specification, see below -for more details. The subset is very "Python-like", which is a key reason we -selected the format. +User code can access the values from the file using either `os.getenv()` or `supervisor.get_setting()` +The value returned by `os.getenv()` is always a string, but `supervisor.get_setting()` +will parse a value into a Python object: a string, an integer, a float, or a boolean. -Due to technical limitations it probably also accepts some files that are -not valid TOML files; bugs of this nature are subject to change (i.e., be -fixed) without the usual deprecation period for incompatible changes. +Both `os.getenv()` and `supervisor.get_setting()` +read and parse the ``settings.toml`` file on every access. +It will save time to copy any values you use repeatedly into variables. -File format example: +Environment variables are sometimes used to store "secrets" such as Wi-Fi passwords and API +keys. The ``settings.toml`` file *does not* make the secrets secure. It only separates them from the +code. -.. code-block:: +CircuitPython supports only a subset of the full TOML specification; see below for more details. +The subset is very "Python-like", which is a key reason the format was selected. +To make the code simpler, the implementation accepts some files that are +not valid TOML, but do not depend on this. - str_key="Hello world" # with trailing comment - int_key = 7 - unicode_key="œuvre" - unicode_key2="\\u0153uvre" # same as above - unicode_key3="\\U00000153uvre" # same as above - escape_codes="supported, including \\r\\n\\"\\\\" - # comment - [subtable] - subvalue="cannot retrieve this using getenv" +The full TOML specification provides for tables labeled with table names in brackets, like +``[table_name]``. +CircuitPython does not support this and ignores any explicit inline TOML tables. +Here is an example ``settings.toml`` file. +Entries consist of a key and value, separated by an ``=`` sign. +Upper and lower case may both be used in the key name. -Details of the toml language subset +.. code-block:: + + # Comment. + CIRCUITPY_WIFI_PASSWORD = "mypassword" + GREETING="Hello world" # trailing comments are ok + REPEAT_COUNT = 7 # an integer + CIRCUITPY_SDCARD_USB = false # a boolean + delay = 0.75 # a float + FRENCH="œuvre" # unicode can be used + FRENCH2="\\u0153uvre" # same unicode string, using a 16-bit escape code + FRENCH3="\\U00000153uvre" # same unicode string, using a 32-bit escape code + STRING_WITH_ESCAPE_CODES="supported, including \\r\\n\\"\\\\" + +Details of the TOML language subset ----------------------------------- -* The content is required to be in UTF-8 encoding -* The supported data types are string and integer -* Only basic strings are supported, not triple-quoted strings -* Only integers supported by strtol. (no 0o, no 0b, no underscores 1_000, 011 - is 9, not 11) -* Only bare keys are supported +* The content must be in UTF-8 encoding +* The supported data types are strings, integers, floats, and booleans. +* Whitespace is allowed. +* Only basic strings are supported, not triple-quoted strings. +* Only integers supported by ``strtol()`` can be parsed: + no ``0o``, no ``0b``, no underscores ``1_000``, ``011`` is 9, not 11. +* Only bare keys are supported. * Duplicate keys are not diagnosed. -* Comments are supported -* Only values from the "root table" can be retrieved -* due to technical limitations, the content of multi-line - strings can erroneously be parsed as a value. +* Comments are allowed. +* Only values from the "root table" can be retrieved. + CircuitPython behavior ---------------------- -CircuitPython will also read the environment to configure its behavior. Some keys are read at -startup once and others are read on reload (ctrl-D in the REPL). If a reload doesn't change things, -then try a reset (a power cycle or pressing the reset button). Other keys are ignored by CircuitPython. -Here are the keys it uses: +On startup, CircuitPython looks for for certain key/value pairs to use as configuration values. +Some values are read only once, after a hard reset, and others are read on each reload (ctrl-D in the REPL). +If you edit ``settings.toml`` and a reload doesn't read your changes, +then try a hard reset (a power cycle or pressing the reset button). +You can also include any other key/value pairs in the file for use with your own code. -Core CircuitPython keys -^^^^^^^^^^^^^^^^^^^^^^^ +Keys that affect CircuitPython behavior +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CIRCUITPY_BLE_NAME ~~~~~~~~~~~~~~~~~~ @@ -83,24 +95,36 @@ Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoi CIRCUITPY_WEB_API_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~~~~ Password required to make modifications to the board from the Web Workflow. +If the password is not specified, the Web Workflow is not enabled. CIRCUITPY_WEB_API_PORT ~~~~~~~~~~~~~~~~~~~~~~ -TCP port number used for the web HTTP API. Defaults to 80 when omitted. +TCP port number used for the Web Workflow HTTP API. Defaults to 80 when omitted. CIRCUITPY_WEB_INSTANCE_NAME ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Name the board advertises as for the WEB workflow. Defaults to human readable board name if omitted. +Hostname the board advertises as, using mDNS, for the Web Workflow. +Defaults to a semi-unique name if omitted. +CIRCUITPY_WIFI_SSID +~~~~~~~~~~~~~~~~~~~ CIRCUITPY_WIFI_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~ -Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID. +If these values are specified, +CircuitPython will connect automatically to a local WiFi network using the supplied SSID +and password before ``boot.py`` and/or ``code.py`` are run. + +CIRCUITPY_SDCARD_USB +^^^^^^^^^^^^^^^^^^^^ +Present a mounted SD card as a USB MSC device. If the board has default pins for an SD card socket, +the card is mounted automatically on startup. +Only one card can be presented. +Defaults to ``true``. +SD card presentation can slow down board startup, +so set this to ``false`` if you don't need this feature. -CIRCUITPY_WIFI_SSID -~~~~~~~~~~~~~~~~~~~ -Wi-Fi SSID to auto-connect to even if user code is not running. -Additional board specific keys +Additional board-specific keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CIRCUITPY_DISPLAY_WIDTH (Sunton, MaTouch) diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 27277bc5ac52f..6f15b508095c4 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -18,6 +18,7 @@ #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" #include "supervisor/shared/reload.h" +#include "supervisor/shared/settings.h" #define MSC_FLASH_BLOCK_SIZE 512 @@ -365,6 +366,32 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 memcpy(product_rev, CFG_TUD_MSC_PRODUCT_REV, strlen(CFG_TUD_MSC_PRODUCT_REV)); } +#ifdef SDCARD_LUN +#if CIRCUITPY_SETTINGS_TOML +typedef enum { + SDCARD_USB_SETTING_NOT_YET_READ = 0, + SDCARD_USB_SETTING_TRUE, + SDCARD_USB_SETTING_FALSE, +} sdcard_usb_setting_state_t; + +static sdcard_usb_setting_state_t _sdcard_usb_setting_state = SDCARD_USB_SETTING_NOT_YET_READ; + +// Read only once to save file access time. +static bool sdcard_usb_enabled(void) { + if (_sdcard_usb_setting_state == SDCARD_USB_SETTING_NOT_YET_READ) { + bool setting = true; + (void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting); + _sdcard_usb_setting_state = setting ? SDCARD_USB_SETTING_TRUE : SDCARD_USB_SETTING_FALSE; + } + return _sdcard_usb_setting_state == SDCARD_USB_SETTING_TRUE; +} +#else +static bool sdcard_usb_enabled(void) { + return CIRCUITPY_SDCARD_USB; +} +#endif +#endif + // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted bool tud_msc_test_unit_ready_cb(uint8_t lun) { @@ -372,17 +399,16 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - #ifdef SDCARD_LUN - if (lun == SDCARD_LUN) { - automount_sd_card(); - } - #endif - fs_user_mount_t *current_mount = get_vfs(lun); if (current_mount == NULL) { return false; } - if (ejected[lun] || eject_once[lun]) { + + if (ejected[lun] || eject_once[lun] + #ifdef SDCARD_LUN + || (lun == SDCARD_LUN && !sdcard_usb_enabled()) + #endif + ) { eject_once[lun] = false; // Set 0x3a for media not present. tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00);