Goal here is to have a simple build environment and libraries to create your own TLS server. A simple 'hello world' is provided as example that can handle simple HTTPS requests and WebSocket clients. That can also receive UF2s over https/websockets for OTA upgrades
Establishing outbound TCP/TLS connections can be done via Session class directly, see https://github.com/AdrianCX/pico_https_example/blob/main/telegram_tone_detector/telegram_notification.cpp
A few sample projects are provided:
- Simple hello world to copy/paste and adjust: https://github.com/AdrianCX/pico_https_example/tree/main/hello_world
- Microphone streamed over https/websockets: https://github.com/AdrianCX/pico_https_example/tree/main/audio_stream
- Camera streamed over https/websockets: https://github.com/AdrianCX/pico_https_example/tree/main/arducam_test
- Simple RC Car over https/websockets that reuses camera code: https://github.com/AdrianCX/pico_https_example/tree/main/rcbot
- detect washing machine jingle and notify over telegram: https://github.com/AdrianCX/pico_https_example/tree/main/telegram_tone_detector/
- Create certificates or insert your own.
cd hello_world/config/certificate
Either RSA or EC
./create_cert_rsa.sh
./create_cert_ec.sh
This generates a self signed certificate in key.h/cert.h. Alternative is to create a 'certificate' folder with same file format anywhere else in include path.
- Configure wifi in example (otherwise it won't connect):
hello_world/config/wifi.h
- Fetch submodules
git submodule update --init --recursive
- Build
For raspberry pi pico 1 w (rp2040)
./build_via_docker.sh pico_w
For raspberry pi pico 2 w (rp2350)
./build_via_docker.sh pico2_w
For pimoroni pico 2 w
./build_via_docker.sh pimoroni_pico_plus2_w_rp2350
Result is: build/pico_w/docker/hello_world/hello_world_https.uf2 or build/pico2_w/docker/hello_world/hello_world_https.uf2
There are two different types of logs.
- Application logs
These are sent over UDP. Configure a host in "config/logging_config.h"
#define LOGGING_SERVER "192.168.100.150"
#define LOGGING_SERVER_PORT 21000
and on the remote remote host run the provided log receiver:
python3 util/log_receiver.py
OR:
netcat -ukl 21000
If it crashes you will see something like this
50 11912 192.168.100.109 trace RequestHandler::onWebSocketData: this=20007920, len=20, data=[hello from websocket]
51 11912 192.168.100.109 trace
52 11912 192.168.100.109 trace Firmware name: build/pico_w/docker/hello_world/hello_world_https, hardware version: pico_w, software version: 1.0
53 11912 192.168.100.109 trace Fault on interrupt or bare metal(no OS) environment
54 11913 192.168.100.109 trace =================== Registers information ====================
55 11913 192.168.100.109 trace R0 : 00000001 R1 : 20007a18 R2 : 00000380 R3 : 10000619
56 11913 192.168.100.109 trace R12: 0000e080 LR : 1002f647 PC : 10000618 PSR: 21000000
57 11913 192.168.100.109 trace ==============================================================
58 11913 192.168.100.109 trace Print call stack: addr2line -e build/pico_w/docker/hello_world/hello_world_https.elf -afpiC 10000618 1002f646 1002c396 1002bd14 1002c822 10003b26 10006192 1000a6fc 1000abbe 1000d59c 1000c2f0 1000d6b0 1000e266 100008aa 1000e4e2 1000ae3c 10000404 1002e524 1002e07c 10027f2c 1002d354 10000226
59 11914 192.168.100.109 trace force_restart: waiting for 5 seconds
60 12914 192.168.100.109 trace force_restart: waiting for 4 seconds
61 13914 192.168.100.109 trace force_restart: waiting for 3 seconds
62 14914 192.168.100.109 trace force_restart: waiting for 2 seconds
63 15914 192.168.100.109 trace force_restart: waiting for 1 seconds
If it hangs or crashes, it will result in a restart. Call stack will be reported on next boots, similar to below:
488 876294 192.168.100.109 trace meminfo[arena=63592, hblkhd=0, uordblks=58568, usmblks=0, fordblks=5024, fsmblks=0, keepcost=752], numSessions=2, lwip[avail=0, used=3128, max=7756, err=0, illegal=0] tcp[xmit=347, recv=683, fw=0, drop=0, chkerr=0, lenerr=0, memerr=0, rterr=0, proterr=0, opterr=0, err=0, cachehit=678] udp[xmit=491, recv=339, fw=0, drop=0, chkerr=0, lenerr=0, memerr=0, rterr=0, proterr=0, opterr=0, err=0, cachehit=2]
489 876294 192.168.100.109 trace report_saved_crash: watchdog info: 1/0, last_command: 0xdeadbeef, cur_depth: 29
490 876295 192.168.100.109 trace Print call stack: addr2line -e build/pico_w/docker/hello_world/hello_world_https.elf -afpiC 1000ebba 1000eae8 1000c4e2 1000c9a0 1000e15c 1000dad8 1000b32a 100099e8 10009ef6 1000af00 1000af8a 10002e66 10007978 100068ae 1000adf4 1000b2b6 1000dc94 1000c9e8 1000dda8 1000e95e 100008ea 1000ebda 1000b534 10000406 1002f188 1002ece0 100286c8 1002dfb8 10000226
You can use addr2line for more info:
$ addr2line -e build/pico_w/docker/hello_world/hello_world_https.elf -afpiC 10000618 1002f646 1002c396 1002bd14 1002c822 10003b26 10006192 1000a6fc 1000abbe 1000d59c 1000c2f0 1000d6b0 1000e266 100008aa 1000e4e2 1000ae3c 10000404 1002e524 1002e07c 10027f2c 1002d354 10000226
0x10000618: RequestHandler::onWebSocketData(unsigned char*, unsigned int) at /source/hello_world/request_handler.cpp:81
0x1002f646: _free_r at /build/newlib-pB30de/newlib-3.3.0/build/arm-none-eabi/thumb/v6-m/nofp/newlib/libc/stdlib/../../../../../../../../newlib/libc/stdlib/mallocr.c:2730
0x1002c396: WebSocketHandler::decodeData(unsigned char*, unsigned int, WebSocketInterface*) at /source/pico_https/pico_http/websocket_handler.cpp:112
0x1002bd14: HTTPSession::on_recv(unsigned char*, unsigned int) at /source/pico_https/pico_http/http_session.cpp:81
0x1002c822: Session::http_recv(void*, altcp_pcb*, pbuf*, signed char) at /source/pico_https/pico_tls/session.cpp:204
0x10003b26: altcp_tcp_recv at /source/pico_https/pico-sdk/lib/lwip/src/core/altcp_tcp.c:110
0x10006192: tcp_input at /source/pico_https/pico-sdk/lib/lwip/src/core/tcp_in.c:502 (discriminator 4)
0x1000a6fc: ip4_input at /source/pico_https/pico-sdk/lib/lwip/src/core/ipv4/ip4.c:744
0x1000abbe: ethernet_input at /source/pico_https/pico-sdk/lib/lwip/src/netif/ethernet.c:188
0x1000d59c: cyw43_cb_process_ethernet at /source/pico_https/pico-sdk/lib/cyw43-driver/src/cyw43_lwip.c:278
0x1000c2f0: cyw43_ll_process_packets at /source/pico_https/pico-sdk/lib/cyw43-driver/src/cyw43_ll.c:1157
0x1000d6b0: cyw43_poll_func at /source/pico_https/pico-sdk/lib/cyw43-driver/src/cyw43_ctrl.c:233
(inlined by) cyw43_poll_func at /source/pico_https/pico-sdk/lib/cyw43-driver/src/cyw43_ctrl.c:211
0x1000e266: cyw43_do_poll at /source/pico_https/pico-sdk/src/rp2_common/pico_cyw43_driver/cyw43_driver.c:92
0x100008aa: async_context_base_execute_once at /source/pico_https/pico-sdk/src/rp2_common/pico_async_context/async_context_base.c:98 (discriminator 2)
0x1000e4e2: async_context_poll_poll at /source/pico_https/pico-sdk/src/rp2_common/pico_async_context/async_context_poll.c:36
0x1000ae3c: cyw43_arch_poll at /source/pico_https/pico-sdk/src/rp2_common/pico_cyw43_arch/cyw43_arch.c:184
0x10000404: main at /source/hello_world/main.cpp:90
0x1002e524: malloc_extend_top at /build/newlib-pB30de/newlib-3.3.0/build/arm-none-eabi/thumb/v6-m/nofp/newlib/libc/stdlib/../../../../../../../../newlib/libc/stdlib/mallocr.c:2206
(inlined by) _malloc_r at /build/newlib-pB30de/newlib-3.3.0/build/arm-none-eabi/thumb/v6-m/nofp/newlib/libc/stdlib/../../../../../../../../newlib/libc/stdlib/mallocr.c:2580
0x1002e07c: malloc at /build/newlib-pB30de/newlib-3.3.0/build/arm-none-eabi/thumb/v6-m/nofp/newlib/libc/stdlib/../../../../../../../../newlib/libc/stdlib/malloc.c:165
0x10027f2c: check_alloc at /source/pico_https/pico-sdk/src/rp2_common/pico_malloc/malloc.c:62
(inlined by) __wrap_malloc at /source/pico_https/pico-sdk/src/rp2_common/pico_malloc/malloc.c:79
0x1002d354: _GLOBAL__sub_I__ZN9__gnu_cxx9__freeresEv at /build/libstdc++-arm-none-eabi-gDiE7C/libstdc++-arm-none-eabi-17/build/thumb/v6-m/nofp/libstdc++/libsupc++/../../../../../../src/libstdc++-v3/libsupc++/eh_alloc.cc:123
(inlined by) __static_initialization_and_destruction_0 at /build/libstdc++-arm-none-eabi-gDiE7C/libstdc++-arm-none-eabi-17/build/thumb/v6-m/nofp/libstdc++/libsupc++/../../../../../../src/libstdc++-v3/libsupc++/eh_alloc.cc:262
(inlined by) _GLOBAL__sub_I__ZN9__gnu_cxx9__freeresEv at /build/libstdc++-arm-none-eabi-gDiE7C/libstdc++-arm-none-eabi-17/build/thumb/v6-m/nofp/libstdc++/libsupc++/../../../../../../src/libstdc++-v3/libsupc++/eh_alloc.cc:338
0x10000226: platform_entry at /source/pico_https/pico-sdk/src/rp2_common/pico_crt0/crt0.S:456
- LWIP/mbedtls logs
Go to: 'hello_world/config/lwipopts_common.h'
Select which include you want (or make your own file / edit existing ones)
// 1. Full TCP/mbedtls debug logs
// #include "lwipopts_fulltcpdebug.h"
// 2. No LWIP/mbedtls debug logs.
#include "lwipopts_debug_off.h"
And use a build that doesn't have NDEBUG defined.
If full TCP logs enabled then LWIP/mbedtls traces will be sent over UDP to configured host in "logging_config.h".
You will see items like:
326 16416 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:2053 ssl->f_send() returned 1421 (-0xfffffa73)
327 16416 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:2080 <= flush output
328 16416 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:2755 <= write record
329 16417 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:5525 <= adrian ret ret: 0, max_len: 4096, len: 1392, out_left: 0
330 16417 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:5601 <= adrian 1392
331 16417 192.168.100.109 trace adrian: mbedtls_ssl_write return 1392, len: 1392
333 16418 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:3791 => read record
334 16418 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:1834 => fetch input
335 16418 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:1974 in_left: 0, nb_want: 5
336 16418 192.168.100.109 trace /source/pico_https/pico-sdk/lib/mbedtls/library/ssl_msg.c:1994 in_left: 0, nb_want: 5
337 16419 192.168.100.109 trace tcp_output: snd_wnd 62898, cwnd 1670, wnd 1670, effwnd 1460, seq 7853, ack 7853
338 16419 192.168.100.109 trace tcp_output: snd_wnd 62898, cwnd 1670, wnd 1670, effwnd 1460, seq 7853, ack 7853, i 0
339 16419 192.168.100.109 trace tcp_output_segment: rtseq 7853
340 16419 192.168.100.109 trace tcp_output_segment: 7853:9313
341 16420 192.168.100.109 trace State: ESTABLISHED
342 16445 192.168.100.109 trace tcp_slowtmr: processing active pcb
343 16445 192.168.100.109 trace tcp_slowtmr: polling application
344 16445 192.168.100.109 trace tcp_output: snd_wnd 62898, cwnd 1670, wnd 1670, effwnd 2920, seq 9313, ack 7853