9 Commits

Author SHA1 Message Date
cd5515ddad feat: new micropython variant with support for microdot
Some checks failed
Build RPi Pico firmware image / Build-Firmware (push) Successful in 3m36s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Failing after 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 9s
Run pytests / Check-Pytest (push) Successful in 12s
2025-11-11 22:32:00 +01:00
99ad8582f0 Defined the two endpoints we need for webapi version 1
Some checks failed
Build RPi Pico firmware image / Build-Firmware (push) Successful in 3m28s
Check code formatting / Check-C-Format (push) Successful in 8s
Check code formatting / Check-Python-Flake8 (push) Failing after 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 8s
Run pytests / Check-Pytest (push) Successful in 11s
2025-11-11 22:30:23 +01:00
ae875950cd Enabled --update flag for differential flashing 2025-11-11 22:30:23 +01:00
340aea6be6 Factored out webserver sample into dedicated module 2025-11-11 22:30:18 +01:00
f64bbc27fd basic webserver works 2025-11-11 22:28:55 +01:00
abb880baca print network interface info 2025-11-11 22:28:49 +01:00
a59f00ad60 disabled wifi power management for now 2025-11-11 22:26:04 +01:00
135ad11de9 Minimal example for api endpoint 2025-11-11 22:26:04 +01:00
ff52e989a2 Forumlated potentially useful json schema.
Note that this is based on an earlier state of the project, and the
terms used in this schema may differ from the current state of the project.
2025-11-11 22:26:04 +01:00
10 changed files with 276 additions and 39 deletions

View File

@@ -0,0 +1,5 @@
include("$(PORT_DIR)/variants/manifest.py")
include("$(MPY_DIR)/extmod/asyncio")
module("microdot.py", "../../lib/microdot/src/microdot/")

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Set base feature level.
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
// Enable extra Unix features.
#include "mpconfigvariant_common.h"

View File

@@ -0,0 +1,3 @@
# This is the default variant when you `make` the Unix port.
FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py

View File

@@ -0,0 +1,126 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2022 Jim Mussared
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// This file enables and configures features common to all variants
// other than "minimal".
// Send raise KeyboardInterrupt directly from the signal handler rather than
// scheduling it into the VM.
#define MICROPY_ASYNC_KBD_INTR (!MICROPY_PY_THREAD_GIL)
// Enable helpers for printing debugging information.
#ifndef MICROPY_DEBUG_PRINTERS
#define MICROPY_DEBUG_PRINTERS (1)
#endif
// Enable floating point by default.
#ifndef MICROPY_FLOAT_IMPL
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
#endif
// Don't use native _Float16 because it increases code size by a lot.
#ifndef MICROPY_FLOAT_USE_NATIVE_FLT16
#define MICROPY_FLOAT_USE_NATIVE_FLT16 (0)
#endif
// Enable arbitrary precision long-int by default.
#ifndef MICROPY_LONGINT_IMPL
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#endif
// Enable use of C libraries that need read/write/lseek/fsync, e.g. axtls.
#define MICROPY_STREAMS_POSIX_API (1)
// REPL conveniences.
#define MICROPY_REPL_EMACS_WORDS_MOVE (1)
#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE (1)
#define MICROPY_USE_READLINE_HISTORY (1)
#ifndef MICROPY_READLINE_HISTORY_SIZE
#define MICROPY_READLINE_HISTORY_SIZE (50)
#endif
// Seed random on import.
#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (mp_random_seed_init())
// Allow exception details in low-memory conditions.
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256)
// Allow loading of .mpy files.
#define MICROPY_PERSISTENT_CODE_LOAD (1)
// Extra memory debugging.
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
#define MICROPY_MEM_STATS (1)
// Enable a small performance boost for the VM.
#define MICROPY_OPT_COMPUTED_GOTO (1)
// Return number of collected objects from gc.collect().
#define MICROPY_PY_GC_COLLECT_RETVAL (1)
// Enable detailed error messages and warnings.
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
#define MICROPY_WARNINGS (1)
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
// Configure the "sys" module with features not usually enabled on bare-metal.
#define MICROPY_PY_SYS_ATEXIT (1)
#define MICROPY_PY_SYS_EXC_INFO (1)
// Configure the "os" module with extra unix features.
#define MICROPY_PY_OS_INCLUDEFILE "ports/unix/modos.c"
#define MICROPY_PY_OS_ERRNO (1)
#define MICROPY_PY_OS_GETENV_PUTENV_UNSETENV (1)
#define MICROPY_PY_OS_SYSTEM (1)
#define MICROPY_PY_OS_URANDOM (1)
// Enable the unix-specific "time" module.
#define MICROPY_PY_TIME (1)
#define MICROPY_PY_TIME_TIME_TIME_NS (1)
#define MICROPY_PY_TIME_CUSTOM_SLEEP (1)
#define MICROPY_PY_TIME_INCLUDEFILE "ports/unix/modtime.c"
#if MICROPY_PY_SSL
#define MICROPY_PY_HASHLIB_MD5 (1)
#define MICROPY_PY_HASHLIB_SHA1 (1)
#define MICROPY_PY_CRYPTOLIB (1)
#endif
// The "select" module is enabled by default, but disable select.select().
#define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (1)
#define MICROPY_PY_SELECT_SELECT (0)
// Enable the "websocket" module.
#define MICROPY_PY_WEBSOCKET (1)
// Enable the "machine" module, mostly for machine.mem*.
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PIN_BASE (1)
#define MICROPY_VFS_ROM (1)
#define MICROPY_VFS_ROM_IOCTL (0)

View File

@@ -9,6 +9,10 @@ set -eu
make -C ports/rp2 BOARD=TONBERRY_RPI_PICO_W BOARD_DIR="$TOPDIR"/boards/RPI_PICO_W clean
make -C ports/rp2 BOARD=TONBERRY_RPI_PICO_W BOARD_DIR="$TOPDIR"/boards/RPI_PICO_W \
USER_C_MODULES="$TOPDIR"/modules/micropython.cmake -j "$(nproc)"
# build tonberry specific unix port of micropython
make -C ports/unix VARIANT_DIR="$TOPDIR"/boards/tonberry_unix clean
make -C ports/unix VARIANT_DIR="$TOPDIR"/boards/tonberry_unix -j "$(nproc)"
)
( cd tools/mklittlefs

View File

@@ -41,7 +41,7 @@ flash_via_picotool()
local device="${bus_device[1]//[!0-9]/}"
echo "Found RP2 with serial $serial on Bus $bus Device $device"
picotool load --bus "$bus" --address "$device" "$IMAGEFILE"
picotool load --update --bus "$bus" --address "$device" "$IMAGEFILE"
}
FLASH_VIA_MOUNTPOINT=0

View File

@@ -9,6 +9,9 @@ import micropython
import network
import os
import time
from math import pi, sin, pow
import ubinascii
from microdot import Microdot
# Own modules
import app
@@ -18,6 +21,7 @@ from mp3player import MP3Player
from nfc import Nfc
from rp2_neopixel import NeoPixel
from utils import BTreeFileManager, Buttons, SDContext, TimerManager, LedManager
from webserver import start_webserver
try:
import hwconfig
@@ -40,6 +44,16 @@ def setup_wifi():
wlan.config(ssid=f"TonberryPicoAP_{machine.unique_id().hex()}", security=wlan.SEC_OPEN)
wlan.active(True)
# disable power management
wlan.config(pm=network.WLAN.PM_NONE)
mac = ubinascii.hexlify(network.WLAN().config('mac'), ':').decode()
print(f" mac: {mac}")
print(f" channel: {wlan.config('channel')}")
print(f" essid: {wlan.config('essid')}")
print(f" txpower: {wlan.config('txpower')}")
print(f"ifconfig: {wlan.ifconfig()}")
DB_PATH = '/sd/tonberry.db'
@@ -51,6 +65,7 @@ def run():
# Wifi with default config
setup_wifi()
start_webserver()
# Setup MP3 player
with SDContext(mosi=hwconfig.SD_DI, miso=hwconfig.SD_DO, sck=hwconfig.SD_SCK, ss=hwconfig.SD_CS,

View File

@@ -1,38 +0,0 @@
import rp2
import network
import ubinascii
from microdot import Microdot
rp2.country('DE')
wlan = network.WLAN(network.AP_IF)
wlan.config(ssid='TonberryPico', security=network.WLAN.SEC_OPEN)
# Important: we cannot change the ip in station mode, otherwise dhcp won't work!
# wlan.ipconfig(addr4='10.0.0.1')
wlan.active(True) # loads the firmware
while wlan.active() is False:
pass
wlan.config(pm=network.WLAN.PM_NONE)
mac = ubinascii.hexlify(network.WLAN().config('mac'), ':').decode()
print(f" mac: {mac}")
print(f" channel: {wlan.config('channel')}")
print(f" essid: {wlan.config('essid')}")
print(f" txpower: {wlan.config('txpower')}")
print(f"ifconfig: {wlan.ifconfig()}")
app = Microdot()
@app.route('/')
async def index(request):
print("wohoo, a guest :)")
print(f" app: {request.app}")
print(f" client: {request.client_addr}")
print(f" method: {request.method}")
print(f" url: {request.url}")
print(f" headers: {request.headers}")
print(f" cookies: {request.cookies}")
return "TonberryPico says 'Hello World!'"
app.run(port=80)

View File

@@ -0,0 +1,53 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"PlaybackPosition": {
"type": "object",
"properties": {
"position_seconds": { "type": "number" },
"device_uptime": { "type": "number" }
},
"required": ["position_seconds"]
},
"AudioFile": {
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"filename": { "type": "string" },
"size_bytes": { "type": "integer" },
"duration_seconds": { "type": "number" },
"last_played_uptime": { "type": "number" },
"playback_position": { "$ref": "#/definitions/PlaybackPosition" }
},
"required": ["id", "filename"]
},
"Playlist": {
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"name": { "type": "string" },
"audio_files": {
"type": "array",
"items": { "$ref": "#/definitions/AudioFile" }
},
"current_track_index": { "type": "integer", "minimum": 0 },
"last_played_uptime": { "type": "number" },
"playback_position": { "$ref": "#/definitions/PlaybackPosition" }
},
"required": ["id", "name", "audio_files"]
},
"NfcTag": {
"type": "object",
"properties": {
"uid": { "type": "string" },
"name": { "type": "string" },
"linked_type": {
"type": "string",
"enum": ["audio_file", "playlist"]
},
"linked_id": { "type": "string", "format": "uuid" }
},
"required": ["uid", "linked_type", "linked_id"]
}
}
}

38
software/src/webserver.py Normal file
View File

@@ -0,0 +1,38 @@
'''
SPDX-License-Identifier: MIT
Copyright (c) 2024-2025 Stefan Kratochwil <Kratochwil-LA@gmx.de>
'''
import asyncio
from microdot import Microdot
webapp = Microdot()
server = None
def start_webserver():
server = asyncio.create_task(webapp.start_server(port=80))
@webapp.route('/')
async def index(request):
print("wohoo, a guest :)")
print(f" app: {request.app}")
print(f" client: {request.client_addr}")
print(f" method: {request.method}")
print(f" url: {request.url}")
print(f" headers: {request.headers}")
print(f" cookies: {request.cookies}")
return "TonberryPico says 'Hello World!'"
@webapp.route('/api/v1/filesystem', methods=['POST'])
async def filesystem_post(request):
# curl -X POST -d "burp" http://192.168.4.1/api/v1/filesystem
print(request)
return {'success': False}
@webapp.route('/api/v1/playlist', methods=['POST'])
async def playlist_post(request):
print(request)
return {'success': False}