Skip to content

Commit 28c93ca

Browse files
authored
Merge pull request #6742 from tannewt/c3_short_send
Retry send if only some bytes sent
2 parents 50be223 + 5823bcc commit 28c93ca

File tree

6 files changed

+52
-31
lines changed

6 files changed

+52
-31
lines changed

ports/espressif/supervisor/port.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,6 @@ void reset_port(void) {
345345

346346
reset_all_pins();
347347

348-
// A larger delay so the idle task can run and do any IDF cleanup needed.
349-
vTaskDelay(4);
350-
351348
#if CIRCUITPY_ANALOGIO
352349
analogout_reset();
353350
#endif
@@ -402,6 +399,9 @@ void reset_port(void) {
402399
#if CIRCUITPY_WATCHDOG
403400
watchdog_reset();
404401
#endif
402+
403+
// Yield so the idle task can run and do any IDF cleanup needed.
404+
port_yield();
405405
}
406406

407407
void reset_to_bootloader(void) {
@@ -492,6 +492,10 @@ void port_wake_main_task_from_isr() {
492492
}
493493
}
494494

495+
void port_yield() {
496+
vTaskDelay(4);
497+
}
498+
495499
void sleep_timer_cb(void *arg) {
496500
port_wake_main_task();
497501
}

supervisor/port.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ void port_wake_main_task(void);
109109
// default weak implementation is provided that does nothing.
110110
void port_wake_main_task_from_isr(void);
111111

112+
// Some ports may use real RTOS tasks besides the background task framework of
113+
// CircuitPython. Calling this will yield to other tasks and then return to the
114+
// CircuitPython task when others are done.
115+
void port_yield(void);
116+
112117
// Some ports need special handling just after completing boot.py execution.
113118
// This function is called once while boot.py's VM is still valid, and
114119
// then a second time after the VM is finalized.

supervisor/shared/port.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ MP_WEAK void port_wake_main_task(void) {
3131

3232
MP_WEAK void port_wake_main_task_from_isr(void) {
3333
}
34+
35+
MP_WEAK void port_yield(void) {
36+
}

supervisor/shared/web_workflow/web_workflow.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "shared/timeutils/timeutils.h"
3838
#include "supervisor/fatfs_port.h"
3939
#include "supervisor/filesystem.h"
40+
#include "supervisor/port.h"
4041
#include "supervisor/shared/reload.h"
4142
#include "supervisor/shared/translate/translate.h"
4243
#include "supervisor/shared/web_workflow/web_workflow.h"
@@ -323,22 +324,31 @@ void supervisor_start_web_workflow(void) {
323324
#endif
324325
}
325326

326-
static void _send_raw(socketpool_socket_obj_t *socket, const uint8_t *buf, int len) {
327+
void web_workflow_send_raw(socketpool_socket_obj_t *socket, const uint8_t *buf, int len) {
328+
int total_sent = 0;
327329
int sent = -EAGAIN;
328-
while (sent == -EAGAIN && common_hal_socketpool_socket_get_connected(socket)) {
329-
sent = socketpool_socket_send(socket, buf, len);
330+
while ((sent == -EAGAIN || (sent > 0 && total_sent < len)) &&
331+
common_hal_socketpool_socket_get_connected(socket)) {
332+
sent = socketpool_socket_send(socket, buf + total_sent, len - total_sent);
333+
if (sent > 0) {
334+
total_sent += sent;
335+
if (total_sent < len) {
336+
// Yield so that network code can run.
337+
port_yield();
338+
}
339+
}
330340
}
331-
if (sent < len) {
341+
if (total_sent < len) {
332342
ESP_LOGE(TAG, "short send %d %d", sent, len);
333343
}
334344
}
335345

336346
STATIC void _print_raw(void *env, const char *str, size_t len) {
337-
_send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)str, (size_t)len);
347+
web_workflow_send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)str, (size_t)len);
338348
}
339349

340350
static void _send_str(socketpool_socket_obj_t *socket, const char *str) {
341-
_send_raw(socket, (const uint8_t *)str, strlen(str));
351+
web_workflow_send_raw(socket, (const uint8_t *)str, strlen(str));
342352
}
343353

344354
// The last argument must be NULL! Otherwise, it won't stop.
@@ -357,15 +367,15 @@ static void _send_strs(socketpool_socket_obj_t *socket, ...) {
357367
static void _send_chunk(socketpool_socket_obj_t *socket, const char *chunk) {
358368
mp_print_t _socket_print = {socket, _print_raw};
359369
mp_printf(&_socket_print, "%X\r\n", strlen(chunk));
360-
_send_raw(socket, (const uint8_t *)chunk, strlen(chunk));
361-
_send_raw(socket, (const uint8_t *)"\r\n", 2);
370+
web_workflow_send_raw(socket, (const uint8_t *)chunk, strlen(chunk));
371+
web_workflow_send_raw(socket, (const uint8_t *)"\r\n", 2);
362372
}
363373

364374
STATIC void _print_chunk(void *env, const char *str, size_t len) {
365375
mp_print_t _socket_print = {env, _print_raw};
366376
mp_printf(&_socket_print, "%X\r\n", len);
367-
_send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)str, len);
368-
_send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)"\r\n", 2);
377+
web_workflow_send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)str, len);
378+
web_workflow_send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)"\r\n", 2);
369379
}
370380

371381
// A bit of a misnomer because it sends all arguments as one chunk.
@@ -938,7 +948,7 @@ static void _reply_static(socketpool_socket_obj_t *socket, _request *request, co
938948
"Content-Length: ", encoded_len, "\r\n",
939949
"Content-Type: ", content_type, "\r\n",
940950
"\r\n", NULL);
941-
_send_raw(socket, response, response_len);
951+
web_workflow_send_raw(socket, response, response_len);
942952
}
943953

944954
#define _REPLY_STATIC(socket, request, filename) _reply_static(socket, request, filename, filename##_length, filename##_content_type)

supervisor/shared/web_workflow/web_workflow.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@
2828

2929
#include <stdbool.h>
3030

31+
#include "shared-bindings/socketpool/Socket.h"
32+
3133
// This background function should be called repeatedly. It cannot be done based
3234
// on events.
3335
void supervisor_web_workflow_background(void);
3436
bool supervisor_web_workflow_status_dirty(void);
3537
void supervisor_web_workflow_status(void);
3638
void supervisor_start_web_workflow(void);
3739
void supervisor_stop_web_workflow(void);
40+
41+
// To share with websocket.
42+
void web_workflow_send_raw(socketpool_socket_obj_t *socket, const uint8_t *buf, int len);

supervisor/shared/web_workflow/websocket.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "py/runtime.h"
3131
#include "shared/runtime/interrupt_char.h"
3232
#include "supervisor/shared/title_bar.h"
33+
#include "supervisor/shared/web_workflow/web_workflow.h"
3334

3435
// TODO: Remove ESP specific stuff. For now, it is useful as we refine the server.
3536
#include "esp_log.h"
@@ -91,16 +92,6 @@ static bool _read_byte(uint8_t *c) {
9192
return true;
9293
}
9394

94-
static void _send_raw(socketpool_socket_obj_t *socket, const uint8_t *buf, int len) {
95-
int sent = -EAGAIN;
96-
while (sent == -EAGAIN) {
97-
sent = socketpool_socket_send(socket, buf, len);
98-
}
99-
if (sent < len) {
100-
ESP_LOGE(TAG, "short send on %d err %d len %d", socket->num, sent, len);
101-
}
102-
}
103-
10495
static void _read_next_frame_header(void) {
10596
uint8_t h;
10697
if (cp_serial.frame_index == 0 && _read_byte(&h)) {
@@ -159,14 +150,14 @@ static void _read_next_frame_header(void) {
159150
ESP_LOGE(TAG, "CLOSE or PING has long payload");
160151
}
161152
frame_header[1] = cp_serial.payload_remaining;
162-
_send_raw(&cp_serial.socket, (const uint8_t *)frame_header, 2);
153+
web_workflow_send_raw(&cp_serial.socket, (const uint8_t *)frame_header, 2);
163154
}
164155

165156
if (cp_serial.payload_remaining > 0 && _read_byte(&h)) {
166157
// Send the payload back to the client.
167158
cp_serial.frame_index++;
168159
cp_serial.payload_remaining--;
169-
_send_raw(&cp_serial.socket, &h, 1);
160+
web_workflow_send_raw(&cp_serial.socket, &h, 1);
170161
}
171162

172163
if (cp_serial.payload_remaining == 0) {
@@ -231,30 +222,33 @@ static void _websocket_send(_websocket *ws, const char *text, size_t len) {
231222
payload_len = 127;
232223
}
233224
frame_header[1] = payload_len;
234-
_send_raw(&ws->socket, (const uint8_t *)frame_header, 2);
225+
web_workflow_send_raw(&ws->socket, (const uint8_t *)frame_header, 2);
235226
uint8_t extended_len[4];
236227
if (payload_len == 126) {
237228
extended_len[0] = (len >> 8) & 0xff;
238229
extended_len[1] = len & 0xff;
239-
_send_raw(&ws->socket, extended_len, 2);
230+
web_workflow_send_raw(&ws->socket, extended_len, 2);
240231
} else if (payload_len == 127) {
241232
uint32_t zero = 0;
242233
// 64 bits where top four bytes are zero.
243-
_send_raw(&ws->socket, (const uint8_t *)&zero, 4);
234+
web_workflow_send_raw(&ws->socket, (const uint8_t *)&zero, 4);
244235
extended_len[0] = (len >> 24) & 0xff;
245236
extended_len[1] = (len >> 16) & 0xff;
246237
extended_len[2] = (len >> 8) & 0xff;
247238
extended_len[3] = len & 0xff;
248-
_send_raw(&ws->socket, extended_len, 4);
239+
web_workflow_send_raw(&ws->socket, extended_len, 4);
249240
}
250-
_send_raw(&ws->socket, (const uint8_t *)text, len);
241+
web_workflow_send_raw(&ws->socket, (const uint8_t *)text, len);
251242
}
252243

253244
void websocket_write(const char *text, size_t len) {
254245
_websocket_send(&cp_serial, text, len);
255246
}
256247

257248
void websocket_background(void) {
249+
if (!websocket_connected()) {
250+
return;
251+
}
258252
uint8_t c;
259253
while (ringbuf_num_empty(&_incoming_ringbuf) > 0 &&
260254
_read_next_payload_byte(&c)) {

0 commit comments

Comments
 (0)