10000 Clean up and add docs · crackmonkey/circuitpython@4103944 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4103944

Browse files
committed
Clean up and add docs
1 parent 7acc5eb commit 4103944

File tree

11 files changed

+296
-36
lines changed

11 files changed

+296
-36
lines changed

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Full Table of Contents
2222
supported_ports.rst
2323
troubleshooting.rst
2424
drivers.rst
25+
workflows
2526
environment.rst
2627

2728
.. toctree::

docs/workflows.md

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
# Workflows
2+
3+
Workflows are the process used to 1) manipulate files on the CircuitPython device and 2) interact
4+
with the serial connection to CircuitPython. The serial connection is usually used to access the
5+
REPL.
6+
7+
Starting with CircuitPython 3.x we moved to a USB-only workflow. Prior to that, we used the serial
8+
connection alone to do the whole workflow. In CircuitPython 7.x, a BLE workflow was added with the
9+
advantage of working with mobile devices. CircuitPython 8.x added a web workflow that works over the
10+
local network (usually Wi-Fi) and a web browser. Other clients can also use the Web REST API. Boards
11+
should clearly document which workflows are supported.
12+
13+
Code for workflows lives in `supervisor/shared`.
14+
15+
The workflow APIs are documented here.
16+
17+
## USB
18+
19+
These USB interfaces are enabled by default on boards with USB support. They are usable once the
20+
device has been plugged into a host.
21+
22+
### CIRCUITPY drive
23+
CircuitPython exposes a standard mass storage (MSC) interface to enable file manipulation over a
24+
standard interface. This interface works underneath the file system at the block level so using it
25+
excludes other types of workflows from manipulating the file system at the same time.
26+
27+
### CDC serial
28+
CircuitPython exposes one CDC USB interface for CircuitPython serial. This is a standard serial
29+
USB interface.
30+
31+
TODO: Document how it designates itself from the user CDC.
32+
33+
Setting baudrate 1200 and disconnecting will reboot into a bootloader. (Used by Arduino to trigger
34+
a reset into bootloader.)
35+
36+
## BLE
37+
38+
The BLE workflow is enabled for nRF boards. By default, to prevent malicious access, it is disabled.
39+
To connect to the BLE workflow, press the reset button while the status led blinks blue quickly
40+
after the safe mode blinks. The board will restart and broadcast the file transfer service UUID
41+
(`0xfebb`) along with the board's [Creation IDs](https://github.com/creationid/creators). This
42+
public broadcast is done at a lower transmit level so the devices must be closer. On connection, the
43+
device will need to pair and bond. Once bonded, the device will broadcast whenever disconnected
44+
using a rotating key rather than a static one. Non-bonded devices won't be able to resolve it. After
45+
connection, the central device can discover two default services. One for file transfer and one for
46+
CircuitPython specifically that includes serial characteristics.
47+
48+
### File Transfer API
49+
50+
CircuitPython uses [an open File Transfer API](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer)
51+
to enable file system access.
52+
53+
### CircuitPython Service
54+
55+
The base UUID for the CircuitPython service is `ADAFXXXX-4369-7263-7569-7450794686e`. The `XXXX` is
56+
replaced by the four specific digits below. The service itself is `0001`.
57+
58+
#### TX - `0002` / RX - `0003`
59+
60+
These characteristic work just like the Nordic Uart Service (NUS) but have different UUIDs to prevent
61+
conflicts with user created NUS services.
62+
63+
#### Version - `0100`
64+
Read-only characteristic that returns the UTF-8 encoded version string.
65+
66+
## Web
67+
68+
The web workflow is depends on adding Wi-Fi credentials into the `/.env` file. The keys are
69+
`CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD`. Once these are defined, CircuitPython will
70+
automatically connect to the network and start the webserver used for the workflow. The webserver
71+
is on port 80. It also enables MDNS.
72+
73+
MDNS is used to resolve [`circuitpython.local`](http://circuitpython.local) to a device specific
74+
hostname of the form `cpy-XXXXXX.local`. The `XXXXXX` is based on network MAC address. The device
75+
also provides the MDNS service with service type `_circuitpython` and protocol `_tcp`.
76+
77+
The web server is HTTP 1.1 and may use chunked responses so that it doesn't need to precompute
78+
content length.
79+
80+
### `/`
81+
The root welcome page links to the file system page and also displays other CircuitPython devices
82+
found using MDNS service discovery. This allows web browsers to find other devices from one. (All
83+
devices will respond to `circuitpython.local` so the device redirected to may vary.)
84+
85+
### CORS
86+
The web server will allow requests from `cpy-XXXXXX.local`, `127.0.0.1`, the device's IP and
87+
`code.circuitpython.org`. (`circuitpython.local` requests will be redirected to `cpy-XXXXXX.local`.)
88+
89+
### File REST API
90+
All file system related APIs are protected by HTTP basic authentication. It is *NOT* secure but will
91+
hopefully prevent some griefing in shared settings. The password is sent unencrypted so do not reuse
92+
a password with something important.
93+
94+
The password is taken from `/.env` with the key `CIRCUITPY_WEB_API_PASSWORD`. If this is unset, the
95+
server will respond with `403 Forbidden`. When a password is set, but not provided in a request, it
96+
will respond `401 Unauthorized`.
97+
98+
#### `/fs/`
99+
100+
The `/fs/` page will respond with a directory browsing HTML once authenticated. This page is always
101+
gzipped. If the `Accept: application/json` header is provided, then the JSON representation of the
102+
root will be returned.
103+
104+
#### OPTIONS
105+
When requested with the `OPTIONS` method, the server will respond with .
106+
107+
#### `/fs/<directory path>/`
108+
Directory paths must end with a /. Otherwise, the path is assumed to be a file.
109+
110+
##### GET
111+
Returns a JSON representation of the directory.
112+
113+
* `200 OK` - Directory exists and JSON returned
114+
* `404 Not Found` - Missing directory
115+
116+
##### PUT
117+
Tries to make a directory at the given path. Request body is ignored. Returns:
118+
119+
* `204 No Content` - Directory exists
120+
* `201 Created` - Directory created
121+
* `409 Conflict` - USB is active and preventing file system modification
122+
* `404 Not Found` - Missing parent directory
123+
* `500 Server Error` - Other, unhandled error
124+
125+
Example:
126+
127+
``sh
128+
curl -v -u :passw0rd -X PUT -L --location-trusted http://circuitpython.local/fs/lib/hello/world/
129+
``
130+
131+
##### DELETE
132+
Deletes the directory and all of its contents.
133+
134+
135+
* `404 Not Found` - No directory
136+
* `409 Conflict` - USB is active and preventing file system modification
137+
138+
Example:
139+
140+
``sh
141+
curl -v -u :passw0rd -X DELETE -L --location-trusted http://circuitpython.local/fs/lib/hello/world/
142+
``
143+
144+
145+
#### `/fs/<file path>`
146+
147+
##### GET
148+
Returns the raw file contents. `Content-Type` will be set based on extension:
149+
150+
* `text/plain` - `.py`, `.txt`
151+
* `text/javascript` - `.js`
152+
* `text/html` - `.html`
153+
* `application/json` - `.json`
154+
* `application/octet-stream` - Everything else
155+
156+
Will return:
157+
* `200 OK` - File exists and file returned
158+
* `404 Not Found` - Missing file
159+
160+
##### PUT
161+
Stores the provided content to the file path. Returns:
162+
163+
* `201 Created` - File created and saved
164+
* `204 No Content` - File existed and overwritten
165+
* `404 Not Found` - Missing parent directory
166+
* `409 Conflict` - USB is active and preventing file system modification
167+
* `413 Payload Too Large` - `Expect` header not sent and file is too large
168+
* `417 Expectation Failed` - `Expect` header sent and file is too large
169+
* `500 Server Error` - Other, unhandled error
170+
171+
If the client sends the `Expect` header, the server will reply with `100 Continue` when ok.
172+
173+
##### DELETE
174+
Deletes the file.
175+
176+
* `404 Not Found` - File not found
177+
* `409 Conflict` - USB is active and preventing file system modification
178+
179+
Example:
180+
181+
``sh
182+
curl -v -u :passw0rd -X DELETE -L --location-trusted http://circuitpython.local/fs/lib/hello/world.txt
183+
``
184+
185+
### `/cp/`
186+
187+
`/cp/` serves basic info about the CircuitPython device and others discovered through MDNS. It is
188+
not protected by basic auth in case the device is someone elses.
189+
190+
Only `GET` requests are supported and will return `XXX Method Not Allowed` otherwise.
191+
192+
#### `/cp/version.json`
193+
194+
Returns information about the device.
195+
196+
* `web_api_version`: Always `1`. This versions the rest of the API and new versions may not be backwards compatible.
197+
* `version`: CircuitPython build version.
198+
* `build_date`: CircuitPython build date.
199+
* `board_name`: Human readable name of the board.
200+
* `mcu_name`: Human readable name of the microcontroller.
201+
* `board_id`: Board id used in code and on circuitpython.org.
202+
* `creator_id`: Creator ID for the board.
203+
* `creation_id`: Creation ID for the board, set by the creator.
204+
* `hostname`: MDNS hostname.
205+
* `port`: Port of CircuitPython Web Service.
206+
* `ip`: IP address of the device.
207+
208+
Example:
209+
```sh
210+
curl -v -L http://circuitpython.local/cp/version.json
211+
```
212+
213+
```json
214+
{
215+
"web_api_version": 1,
216+
"version": "8.0.0-alpha.1-20-ge1d4518a9-dirty",
217+
"build_date": "2022-06-24",
218+
"board_name": "ESP32-S3-USB-OTG-N8",
219+
"mcu_name": "ESP32S3",
220+
"board_id": "espressif_esp32s3_usb_otg_n8",
221+
"creator_id": 12346,
222+
"creation_id": 28683,
223+
"hostname": "cpy-f57ce8",
224+
"port": 80,
225+
"ip": "192.168.1.94"
226+
}
227+
```
228+
229+
#### `/cp/devices.json`
230+
231+
Returns information about other devices found on the network using MDNS.
232+
233+
* `total`: Total MDNS response count. May be more than in `devices` if internal limits were hit.
234+
* `devices`: List of discovered devices.
235+
* `hostname`: MDNS hostname
236+
* `instance_name`: MDNS instance name. Defaults to human readable board name.
237+
* `port`: Port of CircuitPython Web API
238+
* `ip`: IP address
239+
240+
Example:
241+
```sh
242+
curl -v -L http://circuitpython.local/cp/devices.json
243+
```
244+
245+
```json
246+
{
247+
"total": 1,
248+
"devices": [
249+
{
250+
"hostname": "cpy-951032",
251+
"instance_name": "Adafruit Feather ESP32-S2 TFT",
252+
"port": 80,
253+
"ip": "192.168.1.235"
254+
}
255+
]
256+
}
257+
```
258+
259+
### Static files
260+
261+
* `/favicon.ico` - Blinka
262+
* `/directory.js` - JavaScript for `/fs/`
263+
* `/welcome.js` - JavaScript for `/`
264+
265+
### WebSocket
266+
267+
Coming soon!

ports/espressif/common-hal/mdns/RemoteService.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self)
6363
return self->result->port;
6464
}
6565

66-
uint32_t mdns_remoteservice_get_ipv4(mdns_remoteservice_obj_t *self) {
66+
uint32_t mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self) {
6767
if (self->result == NULL ||
6868
self->result->ip_protocol != MDNS_IP_PROTOCOL_V4 ||
6969
self->result->addr == NULL) {
@@ -81,8 +81,8 @@ uint32_t mdns_remoteservice_get_ipv4(mdns_remoteservice_obj_t *self) {
8181
return 0;
8282
}
8383

84-
mp_obj_t common_hal_mdns_remoteservice_get_ipv4(mdns_remoteservice_obj_t *self) {
85-
uint32_t addr = mdns_remoteservice_get_ipv4(self);
84+
mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self) {
85+
uint32_t addr = mdns_remoteservice_get_ipv4_address(self);
8686
if (addr == 0) {
8787
return mp_const_none;
8888
}

ports/espressif/common-hal/mdns/Server.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) {
4949
if (workflow) {
5050
// Set a delegated entry to ourselves. This allows us to respond to "circuitpython.local"
5151
// queries as well.
52-
// TODO: Allow for disabling this with `supervisor.disable_web_workflow()`.
5352
mdns_ip_addr_t our_ip;
5453
esp_netif_get_ip_info(common_hal_wifi_radio_obj.netif, &common_hal_wifi_radio_obj.ip_info);
5554
our_ip.next = NULL;

ports/espressif/common-hal/socketpool/Socket.c

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,9 @@
3737
#include "components/lwip/lwip/src/include/lwip/sys.h"
3838
#include "components/lwip/lwip/src/include/lwip/netdb.h"
3939

40-
#include "esp_log.h"
41-
42-
static const char *TAG = "socket";
43-
4440
STATIC socketpool_socket_obj_t *open_socket_handles[CONFIG_LWIP_MAX_SOCKETS];
4541

4642
void socket_user_reset(void) {
47-
ESP_LOGW(TAG, "Reset sockets");
4843
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
4944
if (open_socket_handles[i]) {
5045
if (open_socket_handles[i]->num > 0) {
@@ -83,9 +78,6 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
8378
newsoc = lwip_accept(self->num, (struct sockaddr *)&accept_addr, &socklen);
8479
// In non-blocking mode, fail instead of timing out
8580
if (newsoc == -1 && (self->timeout_ms == 0 || mp_hal_is_interrupted())) {
86-
if (errno != EAGAIN) {
87-
ESP_LOGE(TAG, "accept failed %d", errno);
88-
}
8981
return -MP_EAGAIN;
9082
}
9183
}
@@ -227,9 +219,7 @@ bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *self) {
227219
}
228220

229221
bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog) {
230-
int result = lwip_listen(self->num, backlog);
231-
ESP_LOGE(TAG, "listen result %d", result);
232-
return result == 0;
222+
return lwip_listen(self->num, backlog);
233223
}
234224

235225
mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *self,
@@ -294,8 +284,6 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *self,
294284
if (errno == ENOTCONN) {
295285
self->connected = false;
296286
return -MP_ENOTCONN;
297-
} else if (errno != EAGAIN) {
298-
ESP_LOGE(TAG, "recv %d", errno);
299287
}
300288
return -MP_EAGAIN;
301289
}

0 commit comments

Comments
 (0)
0