Skip to content

Commit 1d4dbfe

Browse files
authored
Merge pull request #10996 from dhalbert/settings.toml-sdcard-usb-setting
support CIRCUITPY_SDCARD_USB in settings.toml
2 parents a7050c0 + 32f5224 commit 1d4dbfe

2 files changed

Lines changed: 107 additions & 57 deletions

File tree

docs/environment.rst

Lines changed: 74 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,77 @@
11
Environment Variables
22
=====================
33

4-
CircuitPython 8.0.0 introduces support for environment variables. Environment
5-
variables are commonly used to store "secrets" such as Wi-Fi passwords and API
6-
keys. This method *does not* make them secure. It only separates them from the
7-
code.
4+
CircuitPython provides support for environment variables. These values
5+
can be examined by user code, and are also used as settings by CircuitPython during startup.
86

9-
CircuitPython uses a file called ``settings.toml`` at the drive root (no
10-
folder) as the environment. User code can access the values from the file
11-
using `os.getenv()`. It is recommended to save any values used repeatedly in a
12-
variable because `os.getenv()` will parse the ``settings.toml`` file contents
13-
on every access.
7+
CircuitPython looks for a file called ``settings.toml`` at the ``CIRCUITPY`` drive root
8+
to find the values of environment variables,
9+
The file format is a subset of the `TOML config file language <https://toml.io>`__.
1410

15-
CircuitPython only supports a subset of the full toml specification, see below
16-
for more details. The subset is very "Python-like", which is a key reason we
17-
selected the format.
11+
User code can access the values from the file using either `os.getenv()` or `supervisor.get_setting()`
12+
The value returned by `os.getenv()` is always a string, but `supervisor.get_setting()`
13+
will parse a value into a Python object: a string, an integer, a float, or a boolean.
1814

19-
Due to technical limitations it probably also accepts some files that are
20-
not valid TOML files; bugs of this nature are subject to change (i.e., be
21-
fixed) without the usual deprecation period for incompatible changes.
15+
Both `os.getenv()` and `supervisor.get_setting()`
16+
read and parse the ``settings.toml`` file on every access.
17+
It will save time to copy any values you use repeatedly into variables.
2218

23-
File format example:
19+
Environment variables are sometimes used to store "secrets" such as Wi-Fi passwords and API
20+
keys. The ``settings.toml`` file *does not* make the secrets secure. It only separates them from the
21+
code.
2422

25-
.. code-block::
23+
CircuitPython supports only a subset of the full TOML specification; see below for more details.
24+
The subset is very "Python-like", which is a key reason the format was selected.
25+
To make the code simpler, the implementation accepts some files that are
26+
not valid TOML, but do not depend on this.
2627

27-
str_key="Hello world" # with trailing comment
28-
int_key = 7
29-
unicode_key="œuvre"
30-
unicode_key2="\\u0153uvre" # same as above
31-
unicode_key3="\\U00000153uvre" # same as above
32-
escape_codes="supported, including \\r\\n\\"\\\\"
33-
# comment
34-
[subtable]
35-
subvalue="cannot retrieve this using getenv"
28+
The full TOML specification provides for tables labeled with table names in brackets, like
29+
``[table_name]``.
30+
CircuitPython does not support this and ignores any explicit inline TOML tables.
3631

32+
Here is an example ``settings.toml`` file.
33+
Entries consist of a key and value, separated by an ``=`` sign.
34+
Upper and lower case may both be used in the key name.
3735

38-
Details of the toml language subset
36+
.. code-block::
37+
38+
# Comment.
39+
CIRCUITPY_WIFI_PASSWORD = "mypassword"
40+
GREETING="Hello world" # trailing comments are ok
41+
REPEAT_COUNT = 7 # an integer
42+
CIRCUITPY_SDCARD_USB = false # a boolean
43+
delay = 0.75 # a float
44+
FRENCH="œuvre" # unicode can be used
45+
FRENCH2="\\u0153uvre" # same unicode string, using a 16-bit escape code
46+
FRENCH3="\\U00000153uvre" # same unicode string, using a 32-bit escape code
47+
STRING_WITH_ESCAPE_CODES="supported, including \\r\\n\\"\\\\"
48+
49+
Details of the TOML language subset
3950
-----------------------------------
4051

41-
* The content is required to be in UTF-8 encoding
42-
* The supported data types are string and integer
43-
* Only basic strings are supported, not triple-quoted strings
44-
* Only integers supported by strtol. (no 0o, no 0b, no underscores 1_000, 011
45-
is 9, not 11)
46-
* Only bare keys are supported
52+
* The content must be in UTF-8 encoding
53+
* The supported data types are strings, integers, floats, and booleans.
54+
* Whitespace is allowed.
55+
* Only basic strings are supported, not triple-quoted strings.
56+
* Only integers supported by ``strtol()`` can be parsed:
57+
no ``0o``, no ``0b``, no underscores ``1_000``, ``011`` is 9, not 11.
58+
* Only bare keys are supported.
4759
* Duplicate keys are not diagnosed.
48-
* Comments are supported
49-
* Only values from the "root table" can be retrieved
50-
* due to technical limitations, the content of multi-line
51-
strings can erroneously be parsed as a value.
60+
* Comments are allowed.
61+
* Only values from the "root table" can be retrieved.
62+
5263

5364
CircuitPython behavior
5465
----------------------
5566

56-
CircuitPython will also read the environment to configure its behavior. Some keys are read at
57-
startup once and others are read on reload (ctrl-D in the REPL). If a reload doesn't change things,
58-
then try a reset (a power cycle or pressing the reset button). Other keys are ignored by CircuitPython.
59-
Here are the keys it uses:
67+
On startup, CircuitPython looks for for certain key/value pairs to use as configuration values.
68+
Some values are read only once, after a hard reset, and others are read on each reload (ctrl-D in the REPL).
69+
If you edit ``settings.toml`` and a reload doesn't read your changes,
70+
then try a hard reset (a power cycle or pressing the reset button).
71+
You can also include any other key/value pairs in the file for use with your own code.
6072

61-
Core CircuitPython keys
62-
^^^^^^^^^^^^^^^^^^^^^^^
73+
Keys that affect CircuitPython behavior
74+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6375

6476
CIRCUITPY_BLE_NAME
6577
~~~~~~~~~~~~~~~~~~
@@ -83,24 +95,36 @@ Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoi
8395
CIRCUITPY_WEB_API_PASSWORD
8496
~~~~~~~~~~~~~~~~~~~~~~~~~~
8597
Password required to make modifications to the board from the Web Workflow.
98+
If the password is not specified, the Web Workflow is not enabled.
8699

87100
CIRCUITPY_WEB_API_PORT
88101
~~~~~~~~~~~~~~~~~~~~~~
89-
TCP port number used for the web HTTP API. Defaults to 80 when omitted.
102+
TCP port number used for the Web Workflow HTTP API. Defaults to 80 when omitted.
90103

91104
CIRCUITPY_WEB_INSTANCE_NAME
92105
~~~~~~~~~~~~~~~~~~~~~~~~~~~
93-
Name the board advertises as for the WEB workflow. Defaults to human readable board name if omitted.
106+
Hostname the board advertises as, using mDNS, for the Web Workflow.
107+
Defaults to a semi-unique name if omitted.
94108

109+
CIRCUITPY_WIFI_SSID
110+
~~~~~~~~~~~~~~~~~~~
95111
CIRCUITPY_WIFI_PASSWORD
96112
~~~~~~~~~~~~~~~~~~~~~~~
97-
Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID.
113+
If these values are specified,
114+
CircuitPython will connect automatically to a local WiFi network using the supplied SSID
115+
and password before ``boot.py`` and/or ``code.py`` are run.
116+
117+
CIRCUITPY_SDCARD_USB
118+
^^^^^^^^^^^^^^^^^^^^
119+
Present a mounted SD card as a USB MSC device. If the board has default pins for an SD card socket,
120+
the card is mounted automatically on startup.
121+
Only one card can be presented.
122+
Defaults to ``true``.
123+
SD card presentation can slow down board startup,
124+
so set this to ``false`` if you don't need this feature.
98125

99-
CIRCUITPY_WIFI_SSID
100-
~~~~~~~~~~~~~~~~~~~
101-
Wi-Fi SSID to auto-connect to even if user code is not running.
102126

103-
Additional board specific keys
127+
Additional board-specific keys
104128
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
105129

106130
CIRCUITPY_DISPLAY_WIDTH (Sunton, MaTouch)

supervisor/shared/usb/usb_msc_flash.c

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "shared-module/storage/__init__.h"
1919
#include "supervisor/filesystem.h"
2020
#include "supervisor/shared/reload.h"
21+
#include "supervisor/shared/settings.h"
2122

2223
#define MSC_FLASH_BLOCK_SIZE 512
2324

@@ -365,24 +366,49 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
365366
memcpy(product_rev, CFG_TUD_MSC_PRODUCT_REV, strlen(CFG_TUD_MSC_PRODUCT_REV));
366367
}
367368

369+
#ifdef SDCARD_LUN
370+
#if CIRCUITPY_SETTINGS_TOML
371+
typedef enum {
372+
SDCARD_USB_SETTING_NOT_YET_READ = 0,
373+
SDCARD_USB_SETTING_TRUE,
374+
SDCARD_USB_SETTING_FALSE,
375+
} sdcard_usb_setting_state_t;
376+
377+
static sdcard_usb_setting_state_t _sdcard_usb_setting_state = SDCARD_USB_SETTING_NOT_YET_READ;
378+
379+
// Read only once to save file access time.
380+
static bool sdcard_usb_enabled(void) {
381+
if (_sdcard_usb_setting_state == SDCARD_USB_SETTING_NOT_YET_READ) {
382+
bool setting = true;
383+
(void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting);
384+
_sdcard_usb_setting_state = setting ? SDCARD_USB_SETTING_TRUE : SDCARD_USB_SETTING_FALSE;
385+
}
386+
return _sdcard_usb_setting_state == SDCARD_USB_SETTING_TRUE;
387+
}
388+
#else
389+
static bool sdcard_usb_enabled(void) {
390+
return CIRCUITPY_SDCARD_USB;
391+
}
392+
#endif
393+
#endif
394+
368395
// Invoked when received Test Unit Ready command.
369396
// return true allowing host to read/write this LUN e.g SD card inserted
370397
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
371398
if (lun >= LUN_COUNT) {
372399
return false;
373400
}
374401

375-
#ifdef SDCARD_LUN
376-
if (lun == SDCARD_LUN) {
377-
automount_sd_card();
378-
}
379-
#endif
380-
381402
fs_user_mount_t *current_mount = get_vfs(lun);
382403
if (current_mount == NULL) {
383404
return false;
384405
}
385-
if (ejected[lun] || eject_once[lun]) {
406+
407+
if (ejected[lun] || eject_once[lun]
408+
#ifdef SDCARD_LUN
409+
|| (lun == SDCARD_LUN && !sdcard_usb_enabled())
410+
#endif
411+
) {
386412
eject_once[lun] = false;
387413
// Set 0x3a for media not present.
388414
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00);

0 commit comments

Comments
 (0)