move vendors -> tutorials

This commit is contained in:
Sergio R. Caprile committed 2025-02-28 10:01:51 -03:00
1 parent 1db90cafd1
commit b5a9ba8390
1661 files changed
+156 -156

No files matched your search

@@ -0,0 +1,35 @@
BOARD = pico2-w
IDE = Pico-SDK
RTOS = baremetal
WIZARD_URL ?= http://mongoose.ws/wizard
all build example: firmware.uf2
firmware.uf2: wizard
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
wizard:
hash=$$(curl -s -X POST -H "Content-Type: application/json" -d '{"build":{"board":"$(BOARD)","ide":"$(IDE)","rtos":"$(RTOS)"}}' $(WIZARD_URL)/api/hash | jq -r '.hash') \
&& curl -s $(WIZARD_URL)/api/zip/$(BOARD)/$(IDE)/$(RTOS)/$$hash -o wizard.zip
unzip wizard.zip
cd wizard ; rm mongoose.[ch] ; ln -s ../../../../mongoose.c ; ln -s ../../../../mongoose.h
flash: firmware.uf2
picotool load $< -f
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/??
# stdio has to be changed from USB to UART in CMakeLists.txt
update: wizard
sed -i -e 's/pico_enable_stdio_usb(firmware 1)/pico_enable_stdio_usb(firmware 0)/' wizard/CMakeLists.txt
(test `grep -c "pico_enable_stdio_uart(firmware 1)" wizard/CMakeLists.txt` -eq 0 && echo "pico_enable_stdio_uart(firmware 1)" >> wizard/CMakeLists.txt) || true
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @firmware.uf2
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=15 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
clean:
rm -rf firmware.* wizard* pico-sdk
@@ -0,0 +1 @@
See [Wizard](https://mongoose.ws/wizard/#/output?board=pico2-w&ide=Pico-SDK&rtos=baremetal&file=README.md)
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
include(FreeRTOS_Kernel_import.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
main.c
mongoose.c
net.c
packed_fs.c
)
target_include_directories(firmware PUBLIC
.
)
target_link_libraries(firmware
pico_stdlib
pico_rand
pico_cyw43_arch_lwip_sys_freertos
FreeRTOS-Kernel-Heap4
)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 1) # Route stdio
pico_enable_stdio_uart(firmware 0) # to USB
# Prevent extreme optimization from breaking OTA
target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns)
# Mongoose build flags in mongoose_config.h
# Example build options
add_definitions(-DHTTP_URL="http://0.0.0.0/")
@@ -0,0 +1,156 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_EXAMPLES_COMMON_H
#define FREERTOS_CONFIG_EXAMPLES_COMMON_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 512
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#define configNUMBER_OF_CORES 2
/* SMP (configNUMBER_OF_CORES > 1) only */
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#if configNUMBER_OF_CORES > 1
#define configUSE_CORE_AFFINITY 1
#endif
#define configUSE_PASSIVE_IDLE_HOOK 0
/* Armv8-M */
/* Not currently supported */
#define configENABLE_MPU 0
//#define configSYSTEM_CALL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 512
#define configENABLE_FPU 1
/* Not currently supported */
#define configENABLE_TRUSTZONE 0
#define configRUN_FREERTOS_SECURE_ONLY 1
// see https://www.freertos.org/RTOS-Cortex-M3-M4.html
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16
/* RP2xxx specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */
@@ -0,0 +1,91 @@
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
# This can be dropped into an external project to help locate the FreeRTOS kernel
# It should be include()ed prior to project(). Alternatively this file may
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory
# respectively.
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
endif ()
# first pass we look in old tree; second pass we look in new tree
foreach(SEARCH_PASS RANGE 0 1)
if (SEARCH_PASS)
# ports may be moving to submodule in the future
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/Community-Supported-Ports/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../../..")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
endif()
if(PICO_PLATFORM STREQUAL "rp2040")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2040")
else()
if (PICO_PLATFORM STREQUAL "rp2350-riscv")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_RISC-V")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_ARM_NTZ")
endif()
endif()
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
break()
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
break()
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
break()
endif()
endforeach()
if (FREERTOS_KERNEL_PATH)
break()
endif()
endif()
# user must have specified
if (FREERTOS_KERNEL_PATH)
if (EXISTS "${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
break()
endif()
endif()
endforeach ()
if (NOT FREERTOS_KERNEL_PATH)
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
endif()
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel")
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
endif()
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain a '${PICO_PLATFORM}' port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
endif()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)
@@ -0,0 +1,27 @@
RM = rm -rf
MKBUILD = rm -rf build && mkdir -p build # test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk FreeRTOS-Kernel build/firmware.uf2
build/firmware.uf2:
$(MKBUILD)
cd build && cmake -DPICO_BOARD="pico2_w" -G "Unix Makefiles" .. && make
pico-sdk:
#git clone --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@
#cd $@ && git submodule update --init
# Temporary fix until 2.1.1 is released, see #3027
git clone -b develop https://github.com/raspberrypi/pico-sdk $@
cd $@ && git reset --hard --quiet b51fa1b && git submodule update --quiet --init
FreeRTOS-Kernel: # FreeRTOS sources
git clone --depth 1 -b main https://github.com/raspberrypi/FreeRTOS-Kernel $@
clean:
$(RM) pico-sdk build FreeRTOS-Kernel
@@ -0,0 +1,5 @@
# Mongoose on PICO 2 W
See detailed tutorial at https://mongoose.ws/tutorials/rp2040/pico-w/
@@ -0,0 +1,55 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
#define TCPIP_THREAD_STACKSIZE 1024
#define DEFAULT_THREAD_STACKSIZE 2048
#define DEFAULT_RAW_RECVMBOX_SIZE 8
#define TCPIP_MBOX_SIZE 16
#define DEFAULT_UDP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
#define DEFAULT_TCP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
#define DEFAULT_ACCEPTMBOX_SIZE TCPIP_MBOX_SIZE
#define LWIP_TIMEVAL_PRIVATE 0
// not necessary, can be done either way
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#define LWIP_SOCKET 1
#define LWIP_COMPAT_SOCKETS 1
#define LWIP_POSIX_SOCKETS_IO_NAMES 1
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4
#define MEM_SIZE 20000
#define MEMP_NUM_TCP_PCB 10
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 1
#define MEMP_NUM_NETCONN 10
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 0
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#endif
@@ -0,0 +1,46 @@
// Copyright (c) 2024 Cesanta Software Limited
// All rights reserved
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "FreeRTOS.h"
#include <task.h>
#include "mongoose.h"
#include "net.h"
#define WIFI_SSID "yourWiFiSSID"
#define WIFI_PASS "yourWiFiPassword"
static void mongoose(void *args) {
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_log_set(MG_LL_DEBUG); // Set log level
cyw43_arch_init();
cyw43_arch_enable_sta_mode();
cyw43_arch_wifi_connect_blocking(WIFI_SSID, WIFI_PASS, CYW43_AUTH_WPA2_AES_PSK);
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 10);
}
(void) args;
}
int main(void) {
// initialize stdio
stdio_init_all();
xTaskCreate(mongoose, "mongoose", 2048, 0, configMAX_PRIORITIES - 1, NULL);
vTaskStartScheduler(); // This blocks
return 0;
}
@@ -0,0 +1 @@
../../../mongoose.c
@@ -0,0 +1 @@
../../../mongoose.h
@@ -0,0 +1,4 @@
#define MG_ARCH MG_ARCH_PICOSDK
#define MG_ENABLE_LWIP 1
#define MG_ENABLE_PACKED_FS 1
@@ -0,0 +1 @@
../../device-dashboard/net.c
@@ -0,0 +1 @@
../../device-dashboard/net.h
@@ -0,0 +1 @@
../../device-dashboard/packed_fs.c
@@ -0,0 +1,84 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
endif ()
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
endif()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
)
endif ()
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})
@@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
driver_rp2040_rmii.c
main.c
mongoose.c)
target_include_directories(firmware PUBLIC
.)
target_link_libraries(firmware hardware_pio hardware_dma pico_stdlib pico_rand)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 1) # Route stdio
pico_enable_stdio_uart(firmware 0) # to USB
# Prevent extreme optimization from breaking OTA
target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns)
+20
View File
@@ -0,0 +1,20 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 2.1.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
+1
View File
@@ -0,0 +1 @@
See detailed tutorial (including hardware connections) at https://mongoose.ws/tutorials/rp2040/pico-rmii/
@@ -0,0 +1,336 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "hardware/dma.h"
#include "hardware/pio.h"
#include "pico/stdlib.h"
#include "driver_rp2040_rmii.h"
#include "mongoose.h"
#define RXSM 0
#define TXSM 1
#define SMITXSM 2
#define SMIRXSM 0 // pio1
static uint smi_wr_addr, smi_rd_addr;
static int dma_rx;
static int dma_tx;
static dma_channel_config dmacfg_rx;
static dma_channel_config dmacfg_tx;
// Max frame size with VLAN tag + CRC and excluding preamble
#define ETH_PKT_SIZE 1522
static uint8_t s_rxbuf[2][ETH_PKT_SIZE]; // ping-pong buffer
static uint8_t s_txbuf[ETH_PKT_SIZE];
static struct mg_tcpip_if *s_ifp; // MIP interface
#define rmii_tx_wrap_target 0
#define rmii_tx_wrap 7
static const uint16_t rmii_tx_program_instructions[] = {
// .wrap_target
0xe000, // 0: set pins, 0 side 0
0x80a0, // 1: pull block side 0
0xe03d, // 2: set x, 29 side 0
0xf101, // 3: set pins, 1 side 1 [1]
0x1144, // 4: jmp x--, 4 side 1 [1]
0xf103, // 5: set pins, 3 side 1 [1]
0x7002, // 6: out pins, 2 side 1
0x10e6, // 7: jmp !osre, 6 side 1
// .wrap
};
static const struct pio_program rmii_tx_program = {
.instructions = rmii_tx_program_instructions,
.length = 8,
.origin = -1,
};
static inline pio_sm_config rmii_tx_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + rmii_tx_wrap_target, addr + rmii_tx_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline void rmii_tx_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_sm_config c = rmii_tx_program_get_default_config(addr);
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_gpio_init(pio, gpio + 2);
sm_config_set_out_pins(&c, gpio, 2);
sm_config_set_set_pins(&c, gpio, 2);
sm_config_set_sideset_pins(&c, gpio + 2);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, true);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_out_shift(&c, true, true, 8); // pull bytes, LSB first, auto
sm_config_set_clkdiv(&c,
5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate)
pio_sm_init(pio, sm, addr, &c);
pio_sm_set_enabled(pio, sm, true);
}
#define rmii_rx_wrap_target 0
#define rmii_rx_wrap 10
static const uint16_t rmii_rx_program_instructions[] = {
// .wrap_target
0x2122, // 0: wait 0 pin, 2 [1]
0x21a2, // 1: wait 1 pin, 2 [1]
0x21a0, // 2: wait 1 pin, 0 [1]
0x2121, // 3: wait 0 pin, 1 [1]
0x21a1, // 4: wait 1 pin, 1 [1]
0x4002, // 5: in pins, 2
0x00c5, // 6: jmp pin, 5
0x4002, // 7: in pins, 2
0x00c5, // 8: jmp pin, 5
0xa0c3, // 9: mov isr, null
0xc020, // 10: irq wait 0
// .wrap
};
static const struct pio_program rmii_rx_program = {
.instructions = rmii_rx_program_instructions,
.length = 11,
.origin = -1,
};
static inline pio_sm_config rmii_rx_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + rmii_rx_wrap_target, addr + rmii_rx_wrap);
return c;
}
static inline void rmii_rx_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_sm_config c = rmii_rx_program_get_default_config(addr);
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_gpio_init(pio, gpio + 2);
sm_config_set_in_pins(&c, gpio);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, false);
sm_config_set_jmp_pin(&c, gpio + 2);
sm_config_set_in_shift(&c, true, true, 8); // push bytes, LSB first, auto
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
sm_config_set_clkdiv(&c,
5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate)
pio_sm_init(pio, sm, addr, &c);
pio_sm_set_enabled(pio, sm, true);
}
#define smi_wr_wrap_target 0
#define smi_wr_wrap 4
static const uint16_t smi_wr_program_instructions[] = {
// .wrap_target
0xe03f, // 0: set x, 31 side 0
0xe101, // 1: set pins, 1 side 0 [1]
0x1141, // 2: jmp x--, 1 side 1 [1]
0x6101, // 3: out pins, 1 side 0 [1]
0x1103, // 4: jmp 3 side 1 [1]
// .wrap
};
static const struct pio_program smi_wr_program = {
.instructions = smi_wr_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config smi_wr_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + smi_wr_wrap_target, addr + smi_wr_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
#define smi_rd_wrap_target 13
#define smi_rd_wrap 13
static const uint16_t smi_rd_program_instructions[] = {
0xe03f, // 0: set x, 31 side 0
0xe101, // 1: set pins, 1 side 0 [1]
0x1141, // 2: jmp x--, 1 side 1 [1]
0xf02d, // 3: set x, 13 side 1
0x6101, // 4: out pins, 1 side 0 [1]
0x1144, // 5: jmp x--, 4 side 1 [1]
0xe180, // 6: set pindirs, 0 side 0 [1]
0xf101, // 7: set pins, 1 side 1 [1]
0xa142, // 8: nop side 0 [1]
0xf12f, // 9: set x, 15 side 1 [1]
0xa042, // 10: nop side 0
0x4001, // 11: in pins, 1 side 0
0x114a, // 12: jmp x--, 10 side 1 [1]
// .wrap_target
0xf081, // 13: set pindirs, 1 side 1
// .wrap
};
static const struct pio_program smi_rd_program = {
.instructions = smi_rd_program_instructions,
.length = 14,
.origin = -1,
};
static inline pio_sm_config smi_rd_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + smi_rd_wrap_target, addr + smi_rd_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline void smi_wr_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_sm_config c = smi_wr_program_get_default_config(addr);
sm_config_set_out_pins(&c, gpio, 1);
sm_config_set_set_pins(&c, gpio, 1);
sm_config_set_sideset_pins(&c, gpio + 1);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true);
sm_config_set_out_shift(&c, false, true,
16); // pull half-words, MSB first, auto
sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate)
pio_sm_init(pio, sm, addr, &c);
}
static inline void smi_rd_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_sm_config c = smi_rd_program_get_default_config(addr);
sm_config_set_in_pins(&c, gpio);
sm_config_set_out_pins(&c, gpio, 1);
sm_config_set_set_pins(&c, gpio, 1);
sm_config_set_sideset_pins(&c, gpio + 1);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true);
sm_config_set_out_shift(&c, false, true,
16); // pull half-words, MSB first, auto
sm_config_set_in_shift(&c, false, true,
16); // push half-words, MSB first, auto
sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate)
pio_sm_init(pio, sm, addr, &c);
}
static void eth_write_phy(int addr, int reg, int val, uint8_t gpio) {
uint16_t op = 0x5002 | (addr << 7) | (reg << 2); // b0101aaaaarrrrr10
smi_wr_init(pio0, SMITXSM, smi_wr_addr, gpio);
pio_sm_put(pio0, SMITXSM, op << 16);
pio_sm_put(pio0, SMITXSM, (uint16_t) val << 16);
pio_sm_set_enabled(pio0, SMITXSM, true);
}
static uint16_t eth_read_phy(uint addr, uint reg, uint8_t gpio) {
uint16_t op = 0x6000 | (addr << 7) | (reg << 2); // b0110aaaaarrrrr00
smi_rd_init(pio1, SMIRXSM, smi_rd_addr, gpio);
pio_sm_put(pio1, SMIRXSM, op << 16);
pio_sm_set_enabled(pio1, SMIRXSM, true);
uint16_t val = (uint16_t) pio_sm_get_blocking(pio1, SMIRXSM);
pio_sm_set_enabled(pio1, SMIRXSM, false);
return val;
}
static void rx_irq(void);
static bool mg_tcpip_driver_rp2040_rmii_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_rp2040_rmii_data *d =
(struct mg_tcpip_driver_rp2040_rmii_data *) ifp->driver_data;
uint rx_sm_addr, tx_sm_addr;
s_ifp = ifp;
rx_sm_addr = pio_add_program(pio0, &rmii_rx_program);
tx_sm_addr = pio_add_program(pio0, &rmii_tx_program);
smi_wr_addr = pio_add_program(pio0, &smi_wr_program);
smi_rd_addr = pio_add_program(pio1, &smi_rd_program);
dma_tx = dma_claim_unused_channel(true);
dmacfg_tx = dma_channel_get_default_config(dma_tx);
channel_config_set_read_increment(&dmacfg_tx, true); // read from memory
channel_config_set_write_increment(&dmacfg_tx, false); // write to FIFO
channel_config_set_dreq(&dmacfg_tx, pio_get_dreq(pio0, TXSM, true));
channel_config_set_transfer_data_size(&dmacfg_tx,
DMA_SIZE_8); // transfer bytes
rmii_tx_init(pio0, TXSM, tx_sm_addr, d->tx0);
eth_write_phy(d->phy_addr, 4, 0x61,
d->mdio); // Auto Negotiation Advertisement Register: enable
// only 10BASE-T full and half duplex (two-pair), use
// IEEE 802.3 format
sleep_us(31); // give some time for PIO to work (64 bits @2.5MHz = 25.6 us)
eth_write_phy(d->phy_addr, 0, 0x1000,
d->mdio); // Basic Control Register: enable Auto-Negotiation
sleep_us(31);
dma_rx = dma_claim_unused_channel(true);
dmacfg_rx = dma_channel_get_default_config(dma_rx);
channel_config_set_read_increment(&dmacfg_rx, false); // read from FIFO
channel_config_set_write_increment(&dmacfg_rx,
true); // write to memory, increment
channel_config_set_dreq(&dmacfg_rx, pio_get_dreq(pio0, RXSM, false));
channel_config_set_transfer_data_size(&dmacfg_rx,
DMA_SIZE_8); // transfer bytes
dma_channel_configure(dma_rx, &dmacfg_rx, s_rxbuf[0],
((uint8_t *) &pio0->rxf[RXSM]) + 3, ETH_PKT_SIZE, true);
pio_set_irq0_source_enabled(pio0, pis_interrupt0,
true); // enable SM0 on PIO0_IRQ_0
irq_set_exclusive_handler(7, rx_irq); // set handler for PIO0_IRQ_0
irq_set_enabled(7, true); // enable it
rmii_rx_init(pio0, RXSM, rx_sm_addr, d->rx0);
return true;
}
static size_t mg_tcpip_driver_rp2040_rmii_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
dma_channel_wait_for_finish_blocking(dma_tx);
memset(s_txbuf, 0, 60); // pre-pad
memcpy(s_txbuf, buf, len);
if (len < 60) len = 60; // pad
uint32_t crc = mg_crc32(0, s_txbuf, len); // host is little-endian
memcpy(s_txbuf + len, (uint8_t *) &crc, 4);
len += 4;
sleep_us(10); // enforce IFG in case software has been lightning fast...
dma_channel_configure(dma_tx, &dmacfg_tx, ((uint8_t *) &pio0->txf[TXSM]) + 3,
s_txbuf, len, true);
return len;
}
static uint32_t s_rxno;
// The max amount of time we should keep the PIO state machine stopped is the
// IFG time (10us) and that includes irq latency
static void rx_irq(void) {
dma_channel_hw_t *hw = dma_channel_hw_addr(dma_rx);
uint32_t rxno =
(s_rxno + 1) &
1; // 2 buffers, switch to the available one as fast as possible
size_t len = ETH_PKT_SIZE - hw->transfer_count;
dma_channel_abort(dma_rx);
dma_channel_set_write_addr(dma_rx, s_rxbuf[rxno], true); // restart DMA
pio_interrupt_clear(pio0,
0); // ACK PIO IRQ so the state machine resumes receiving
// NOTE(scaprile) Here we could check addressing to avoid queuing frames not
// for us. The max amount of time we can linger here is what it takes for the
// other buffer to fill (<8us) and that includes irq chaining
if (len >= 64 && len <= ETH_PKT_SIZE)
mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp);
s_rxno = rxno;
}
static bool mg_tcpip_driver_rp2040_rmii_up(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_rp2040_rmii_data *d =
(struct mg_tcpip_driver_rp2040_rmii_data *) ifp->driver_data;
uint32_t bsr =
eth_read_phy(d->phy_addr, 1, d->mdio); // Basic Status Register
return (bsr & (1 << 2)) ? 1 : 0; // check Link Status flag
}
struct mg_tcpip_driver mg_tcpip_driver_rp2040_rmii = {
mg_tcpip_driver_rp2040_rmii_init,
mg_tcpip_driver_rp2040_rmii_tx,
NULL,
mg_tcpip_driver_rp2040_rmii_up,
};
@@ -0,0 +1,10 @@
#pragma once
struct mg_tcpip_driver_rp2040_rmii_data {
uint8_t rx0; // RX0, RX1, CRS_DV; consecutive GPIO pins
uint8_t tx0; // TX0, TX1, TX-EN; consecutive GPIO pins
uint8_t mdio; // MDIO, MDC; consecutive GPIO pins
uint8_t phy_addr; // PHY address
};
extern struct mg_tcpip_driver mg_tcpip_driver_rp2040_rmii;
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "mongoose.h"
#include "driver_rp2040_rmii.h"
#define CLKREFPIN 20 // either 20 or 22
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
mg_http_reply(c, 200, "", "ok\n");
}
}
int main(void) {
// use the RMII reference clock (50MHz) as our system clock
clock_configure_gpin(clk_sys, CLKREFPIN, 50 * MHZ, 50 * MHZ);
sleep_ms(100);
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_log_set(MG_LL_DEBUG); // Set log level
MG_INFO(("Init TCP/IP"));
// Initialise Mongoose network stack and specific driver
// Set consecutive GPIOs for RMII (tx and rx) and SMI function groups
struct mg_tcpip_driver_rp2040_rmii_data driver_data = {
// see driver_rp2040_rmii.h
.rx0 = 6, // 6, 7, 8 : RX0, RX1, CRS_DV
.tx0 = 10, // 10, 11, 12 : TX0, TX1, TX-EN
.mdio = 14, // 14, 15 : MDIO, MDC
.phy_addr = 1 // check your hardware, LAN8722 is 0 or 1
};
// Specify MAC address, either set use_dhcp or enter a static config.
// For static configuration, specify IP/mask/GW in network byte order
struct mg_tcpip_if mif = {
.mac = {2, 0, 1, 2, 3, 5},
.ip = 0,
.enable_mac_check = true,
.enable_crc32_check = true,
.driver = &mg_tcpip_driver_rp2040_rmii,
.driver_data = &driver_data,
};
mg_tcpip_init(&mgr, &mif);
mg_http_listen(&mgr, "http://0.0.0.0", fn, NULL); // HTTP listener
MG_INFO(("Init done, starting main loop"));
for (;;) mg_mgr_poll(&mgr, 0); // Infinite event loop
return 0;
}
+1
View File
@@ -0,0 +1 @@
../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../mongoose.h
@@ -0,0 +1,5 @@
#define MG_ARCH MG_ARCH_PICOSDK
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
main.c
msc_disk.c
usb_descriptors.c
mongoose.c
net.c
packed_fs.c
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
target_include_directories(firmware PUBLIC
.
pico-sdk/lib/tinyusb/lib/networking)
target_link_libraries(firmware pico_stdlib pico_rand hardware_spi tinyusb_device)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 0) # Route stdio
pico_enable_stdio_uart(firmware 1) # to the UART
# Mongoose build flags in mongoose_config.h
# Example build options
add_definitions(-DHTTP_URL="http://0.0.0.0/")
# Extra build flags (enable if needed)
add_definitions(-DDUAL_CONFIG=0)
# Prevent extreme optimization from breaking OTA
target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns)
@@ -0,0 +1,20 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build build/firmware.uf2: pico-sdk main.c net.c
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 2.1.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
@@ -0,0 +1,7 @@
# Device Dashboard via RNDIS on an RP2040
Your headless Raspberry Pi Pico-based hardware can also have a device dashboard on a web browser when you connect it to your computer via USB
- See detailed tutorial at https://mongoose.ws/tutorials/rp2040/pico-rndis-dashboard/
Note for Mac users: For this example to run on Mac, please set `DUAL_CONFIG=1` in `CMakeLists.txt` before building; this enables CDC-ECM. Please notice that Windows may not recognize the mass-storage device in that case.
@@ -0,0 +1,81 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#include "net.h"
#include "pico/stdlib.h"
#include "tusb.h"
static struct mg_tcpip_if *s_ifp;
uint8_t tud_network_mac_address[6] = {2, 2, 0x84, 0x6A, 0x96, 0};
static void blink_cb(void *arg) { // Blink periodically
gpio_put(PICO_DEFAULT_LED_PIN, !gpio_get_out_level(PICO_DEFAULT_LED_PIN));
(void) arg;
}
bool tud_network_recv_cb(const uint8_t *buf, uint16_t len) {
mg_tcpip_qwrite((void *) buf, len, s_ifp);
// MG_INFO(("RECV %hu", len));
// mg_hexdump(buf, len);
tud_network_recv_renew();
return true;
}
void tud_network_init_cb(void) {}
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
// MG_INFO(("SEND %hu", arg));
memcpy(dst, ref, arg);
return arg;
}
static size_t usb_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
if (!tud_ready()) return 0;
while (!tud_network_can_xmit(len)) tud_task();
tud_network_xmit((void *) buf, len);
(void) ifp;
return len;
}
static bool usb_up(struct mg_tcpip_if *ifp) {
(void) ifp;
return tud_inited() && tud_ready() && tud_connected();
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
}
int main(void) {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_timer_add(&mgr, 500, MG_TIMER_REPEAT, blink_cb, &mgr);
struct mg_tcpip_driver driver = {.tx = usb_tx, .up = usb_up};
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 0x77},
.ip = mg_htonl(MG_U32(192, 168, 3, 1)),
.mask = mg_htonl(MG_U32(255, 255, 255, 0)),
.enable_dhcp_server = true,
.driver = &driver,
.recv_queue.size = 4096};
s_ifp = &mif;
mg_tcpip_init(&mgr, &mif);
tusb_init();
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
tud_task();
}
return 0;
}
+1
View File
@@ -0,0 +1 @@
../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../mongoose.h
@@ -0,0 +1,5 @@
#define MG_ARCH MG_ARCH_PICOSDK
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
@@ -0,0 +1,252 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* 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.
*
*/
// Modified by Cesanta Software
#include "tusb.h"
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that Windows allows to mount
DISK_BLOCK_SIZE = 512
};
#define INDEX_CONTENTS \
"<head><meta http-equiv=\"Refresh\" content=\"0;url=http://192.168.3.1\"></head><body></body>"
// readonly
const uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
// fat_num = 1; fat12_root_entry_num = 16;
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB 0 ";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
'S' , 'B' , ' ' , 'C' , ' ' , ' ' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'M' , 'o' , 'n' , 'g' , 'o' , 'o' , 's' , 'e' , ' ' , ' ' , ' ' , 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is our file
'I' , 'N' , 'D' , 'E' , 'X' , ' ' , ' ' , ' ' , 'H' , 'T' , 'M' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(INDEX_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
},
//------------- Block3: file Content -------------//
INDEX_CONTENTS
};
// Invoked to determine max LUN
uint8_t tud_msc_get_maxlun_cb(void)
{
return 1; // single LUN
}
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
(void) lun; // use same ID for both LUNs
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
(void) lun;
return true; // Flash/RAM disks are always ready
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void) lun;
(void) power_condition;
if ( load_eject )
{
if (start)
{
// load disk storage
}else
{
// unload disk storage
}
}
return true;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
(void) lun;
uint8_t const* addr = msc_disk0[lba] + offset;
memcpy(buffer, addr, bufsize);
return (int32_t) bufsize;
}
bool tud_msc_is_writable_cb (uint8_t lun)
{
(void) lun;
// readonly
return false;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
#if 0
uint8_t* addr = (lun ? msc_disk1[lba] : msc_disk0[lba]) + offset;
memcpy(addr, buffer, bufsize);
#else // readonly
(void) lun; (void) lba; (void) offset; (void) buffer;
#endif
return (int32_t) bufsize;
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{
memcpy(buffer, response, (size_t) resplen);
}else
{
// SCSI output
}
}
return resplen;
}
+1
View File
@@ -0,0 +1 @@
../../device-dashboard/net.c
+1
View File
@@ -0,0 +1 @@
../../device-dashboard/net.h
@@ -0,0 +1,2 @@
#pragma once
#define SIZEOF_ETH_HDR 14
+1
View File
@@ -0,0 +1 @@
../../device-dashboard/packed_fs.c
@@ -0,0 +1,12 @@
#pragma once
// Windows only supports RNDIS, and apparently doesn't like composite devices with two configurations.
// Mac only supports CDC-ECM, which we present as the second config in a dual configuration device
// Linux supports either RNDIS, CDC-ECM or CDC-NCM
#define CFG_TUD_ECM_RNDIS 1
#define CFG_TUD_MSC 1 // This enables mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512 // Also Add msc_disk.c and descritors
#define CFG_TUD_NCM 0
#define BOARD_DEVICE_RHPORT_NUM 0
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
@@ -0,0 +1,271 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* 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.
*
*/
// Modified by Cesanta Software
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
// String Descriptor Index
enum
{
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRID_INTERFACE,
STRID_MAC
};
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
ITF_NUM_TOTAL
};
enum
{
#if CFG_TUD_ECM_RNDIS
CONFIG_ID_RNDIS = 0,
#if DUAL_CONFIG
CONFIG_ID_ECM = 1,
#endif
#else
CONFIG_ID_NCM = 0,
#endif
CONFIG_ID_COUNT
};
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) device class
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0101,
.iManufacturer = STRID_MANUFACTURER,
.iProduct = STRID_PRODUCT,
.iSerialNumber = STRID_SERIAL,
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN + TUD_RNDIS_DESC_LEN)
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#else
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#define EPNUM_MSC_OUT 0x03
#define EPNUM_MSC_IN 0x83
#endif
// Interface number, string index, EP Out & EP In address, EP size
# define MSCDESC TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64)
#if CFG_TUD_ECM_RNDIS
static uint8_t const rndis_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
MSCDESC
};
#if DUAL_CONFIG
static uint8_t const ecm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
MSCDESC
};
#endif
#else
static uint8_t const ncm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
MSCDESC
};
#endif
// Configuration array: RNDIS and CDC-ECM
// - Windows only works with RNDIS
// - MacOS only works with CDC-ECM
// - Linux will work on both
static uint8_t const * const configuration_arr[2] =
{
#if CFG_TUD_ECM_RNDIS
[CONFIG_ID_RNDIS] = rndis_configuration
#if DUAL_CONFIG
, [CONFIG_ID_ECM ] = ecm_configuration
#endif
#else
[CONFIG_ID_NCM ] = ncm_configuration
#endif
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
static char const* string_desc_arr [] =
{
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
[STRID_PRODUCT] = "TinyUSB Device", // Product
[STRID_SERIAL] = "123456", // Serial
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
// STRID_MAC index is handled separately
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
unsigned int chr_count = 0;
if (STRID_LANGID == index)
{
memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
chr_count = 1;
}
else if (STRID_MAC == index)
{
// Convert MAC address into UTF-16
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++)
{
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
}
}
else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
// Convert ASCII string into UTF-16
for (unsigned int i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
main.c
usb_descriptors.c
mongoose.c
net.c
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
target_include_directories(firmware PUBLIC
.
pico-sdk/lib/tinyusb/lib/networking)
target_link_libraries(firmware pico_stdlib pico_rand hardware_spi tinyusb_device)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 0) # Route stdio
pico_enable_stdio_uart(firmware 1) # to the UART
# Prevent extreme optimization from breaking OTA
target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns)
# Mongoose build flags in mongoose_config.h
# Example build options
@@ -0,0 +1,20 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build build/firmware.uf2: pico-sdk main.c net.c
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 2.1.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
@@ -0,0 +1,30 @@
# Remote MQTT Device on an RP2040
Your headless Raspberry Pi Pico-based hardware can also be a remote gadget when you connect it to your computer via USB
For the USB specifics, see this related tutorial at https://mongoose.ws/tutorials/rp2040/pico-rndis-dashboard/
See this tutorial to control your device: https://mongoose.ws/tutorials/mqtt-dashboard/
For this to work, you need your computer to act as a router (gateway) and NAT for your device.
## Linux setup
Enable "masquerading"; the quick and simple options are:
``` bash
sudo iptables --flush
sudo iptables --table nat --flush
sudo iptables --delete-chain
sudo iptables --table nat --delete-chain
# Do masquerading
sudo iptables -t nat -A POSTROUTING -o yourifc -j MASQUERADE
# enable routing
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
```
Where `yourifc` is the interface that is connected to your network
## MacOS setup
@@ -0,0 +1,11 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
#define LED PICO_DEFAULT_LED_PIN
static inline int gpio_read(uint16_t pin) {
return gpio_get_out_level(pin);
}
static inline void gpio_write(uint16_t pin, bool val) {
gpio_put(pin, val);
}
@@ -0,0 +1,94 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#include "net.h"
#include "pico/stdlib.h"
#include "tusb.h"
bool hal_gpio_read(int pin) {
return (pin >= 0 && pin <= 29) ? gpio_get_out_level((uint) pin) : false;
}
bool hal_gpio_write(int pin, bool val) {
if (pin >= 0 && pin <= 29) {
gpio_put((uint) pin, val);
return true;
} else {
return false;
}
}
int hal_led_pin(void) {
return PICO_DEFAULT_LED_PIN;
}
static struct mg_tcpip_if *s_ifp;
uint8_t tud_network_mac_address[6] = {2, 2, 0x84, 0x6A, 0x96, 0};
bool tud_network_recv_cb(const uint8_t *buf, uint16_t len) {
mg_tcpip_qwrite((void *) buf, len, s_ifp);
// MG_INFO(("RECV %hu", len));
// mg_hexdump(buf, len);
tud_network_recv_renew();
return true;
}
void tud_network_init_cb(void) {
}
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
// MG_INFO(("SEND %hu", arg));
memcpy(dst, ref, arg);
return arg;
}
static size_t usb_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
if (!tud_ready()) return 0;
while (!tud_network_can_xmit(len)) tud_task();
tud_network_xmit((void *) buf, len);
(void) ifp;
return len;
}
static bool usb_up(struct mg_tcpip_if *ifp) {
(void) ifp;
return tud_inited() && tud_ready() && tud_connected();
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
}
int main(void) {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
struct mg_tcpip_driver driver = {.tx = usb_tx, .up = usb_up};
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 0x77},
.ip = mg_htonl(MG_U32(192, 168, 3, 1)),
.mask = mg_htonl(MG_U32(255, 255, 255, 0)),
.enable_dhcp_server = true,
.enable_get_gateway = true,
.driver = &driver,
.recv_queue.size = 4096};
s_ifp = &mif;
mg_tcpip_init(&mgr, &mif);
tusb_init();
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
tud_task();
}
return 0;
}
+1
View File
@@ -0,0 +1 @@
../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../mongoose.h
@@ -0,0 +1,5 @@
#define MG_ARCH MG_ARCH_PICOSDK
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
+1
View File
@@ -0,0 +1 @@
../../mqtt/mqtt-dashboard/device/net.c
+1
View File
@@ -0,0 +1 @@
../../mqtt/mqtt-dashboard/device/net.h
@@ -0,0 +1,2 @@
#pragma once
#define SIZEOF_ETH_HDR 14
@@ -0,0 +1,9 @@
#pragma once
// Windows only supports RNDIS
// Mac only supports CDC-ECM
// Linux supports either RNDIS, CDC-ECM or CDC-NCM
#define CFG_TUD_ECM_RNDIS 1
#define BOARD_DEVICE_RHPORT_NUM 0
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
@@ -0,0 +1,248 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* 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.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
// String Descriptor Index
enum
{
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRID_INTERFACE,
STRID_MAC
};
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_TOTAL
};
enum
{
#if CFG_TUD_ECM_RNDIS
CONFIG_ID_RNDIS = 0,
CONFIG_ID_ECM = 1,
#else
CONFIG_ID_NCM = 0,
#endif
CONFIG_ID_COUNT
};
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) device class
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0101,
.iManufacturer = STRID_MANUFACTURER,
.iProduct = STRID_PRODUCT,
.iSerialNumber = STRID_SERIAL,
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x83
#else
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#endif
#if CFG_TUD_ECM_RNDIS
static uint8_t const rndis_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
};
static uint8_t const ecm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
};
#else
static uint8_t const ncm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
};
#endif
// Configuration array: RNDIS and CDC-ECM
// - Windows only works with RNDIS
// - MacOS only works with CDC-ECM
// - Linux will work on both
static uint8_t const * const configuration_arr[2] =
{
#if CFG_TUD_ECM_RNDIS
[CONFIG_ID_RNDIS] = rndis_configuration,
[CONFIG_ID_ECM ] = ecm_configuration
#else
[CONFIG_ID_NCM ] = ncm_configuration
#endif
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
static char const* string_desc_arr [] =
{
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
[STRID_PRODUCT] = "TinyUSB Device", // Product
[STRID_SERIAL] = "123456", // Serial
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
// STRID_MAC index is handled separately
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
unsigned int chr_count = 0;
if (STRID_LANGID == index)
{
memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
chr_count = 1;
}
else if (STRID_MAC == index)
{
// Convert MAC address into UTF-16
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++)
{
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
}
}
else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
// Convert ASCII string into UTF-16
for (unsigned int i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}
@@ -0,0 +1,35 @@
BOARD = pico-w
IDE = Pico-SDK
RTOS = baremetal
WIZARD_URL ?= http://mongoose.ws/wizard
all build example: firmware.uf2
firmware.uf2: wizard
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
wizard:
hash=$$(curl -s -X POST -H "Content-Type: application/json" -d '{"build":{"board":"$(BOARD)","ide":"$(IDE)","rtos":"$(RTOS)"}}' $(WIZARD_URL)/api/hash | jq -r '.hash') \
&& curl -s $(WIZARD_URL)/api/zip/$(BOARD)/$(IDE)/$(RTOS)/$$hash -o wizard.zip
unzip wizard.zip
cd wizard ; rm mongoose.[ch] ; ln -s ../../../../mongoose.c ; ln -s ../../../../mongoose.h
flash: firmware.uf2
picotool load $< -f
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/??
# stdio has to be changed from USB to UART in CMakeLists.txt
update: wizard
sed -i -e 's/pico_enable_stdio_usb(firmware 1)/pico_enable_stdio_usb(firmware 0)/' wizard/CMakeLists.txt
(test `grep -c "pico_enable_stdio_uart(firmware 1)" wizard/CMakeLists.txt` -eq 0 && echo "pico_enable_stdio_uart(firmware 1)" >> wizard/CMakeLists.txt) || true
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @firmware.uf2
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=15 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
clean:
rm -rf firmware.* wizard* pico-sdk
@@ -0,0 +1 @@
See [Wizard](https://mongoose.ws/wizard/#/output?board=pico-w&ide=Pico-SDK&rtos=baremetal&file=README.md)
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
include(FreeRTOS_Kernel_import.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
main.c
mongoose.c
net.c
packed_fs.c
)
target_include_directories(firmware PUBLIC
.
)
target_link_libraries(firmware
pico_stdlib
pico_rand
pico_cyw43_arch_lwip_sys_freertos
FreeRTOS-Kernel-Heap4
)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 1) # Route stdio
pico_enable_stdio_uart(firmware 0) # to USB
# Prevent extreme optimization from breaking OTA
target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns)
# Mongoose build flags in mongoose_config.h
# Example build options
add_definitions(-DHTTP_URL="http://0.0.0.0/")
@@ -0,0 +1,156 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_EXAMPLES_COMMON_H
#define FREERTOS_CONFIG_EXAMPLES_COMMON_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 512
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#define configNUMBER_OF_CORES 2
/* SMP (configNUMBER_OF_CORES > 1) only */
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#if configNUMBER_OF_CORES > 1
#define configUSE_CORE_AFFINITY 1
#endif
#define configUSE_PASSIVE_IDLE_HOOK 0
/* Armv8-M */
/* Not currently supported */
#define configENABLE_MPU 0
//#define configSYSTEM_CALL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 512
#define configENABLE_FPU 1
/* Not currently supported */
#define configENABLE_TRUSTZONE 0
#define configRUN_FREERTOS_SECURE_ONLY 1
// see https://www.freertos.org/RTOS-Cortex-M3-M4.html
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16
/* RP2xxx specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */
@@ -0,0 +1,91 @@
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
# This can be dropped into an external project to help locate the FreeRTOS kernel
# It should be include()ed prior to project(). Alternatively this file may
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory
# respectively.
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
endif ()
# first pass we look in old tree; second pass we look in new tree
foreach(SEARCH_PASS RANGE 0 1)
if (SEARCH_PASS)
# ports may be moving to submodule in the future
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/Community-Supported-Ports/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../../..")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
endif()
if(PICO_PLATFORM STREQUAL "rp2040")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2040")
else()
if (PICO_PLATFORM STREQUAL "rp2350-riscv")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_RISC-V")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_ARM_NTZ")
endif()
endif()
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
break()
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
break()
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
break()
endif()
endforeach()
if (FREERTOS_KERNEL_PATH)
break()
endif()
endif()
# user must have specified
if (FREERTOS_KERNEL_PATH)
if (EXISTS "${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
break()
endif()
endif()
endforeach ()
if (NOT FREERTOS_KERNEL_PATH)
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
endif()
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel")
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
endif()
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain a '${PICO_PLATFORM}' port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
endif()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)
@@ -0,0 +1,24 @@
RM = rm -rf
MKBUILD = rm -rf build && mkdir -p build # test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk FreeRTOS-Kernel build/firmware.uf2
build/firmware.uf2:
$(MKBUILD)
cd build && cmake -DPICO_BOARD="pico_w" -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 2.0.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
FreeRTOS-Kernel: # FreeRTOS sources
git clone --depth 1 -b main https://github.com/raspberrypi/FreeRTOS-Kernel $@
clean:
$(RM) pico-sdk build FreeRTOS-Kernel
@@ -0,0 +1,5 @@
# Mongoose on PICO W
See detailed tutorial at https://mongoose.ws/tutorials/rp2040/pico-w/
@@ -0,0 +1,55 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
#define TCPIP_THREAD_STACKSIZE 1024
#define DEFAULT_THREAD_STACKSIZE 2048
#define DEFAULT_RAW_RECVMBOX_SIZE 8
#define TCPIP_MBOX_SIZE 16
#define DEFAULT_UDP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
#define DEFAULT_TCP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
#define DEFAULT_ACCEPTMBOX_SIZE TCPIP_MBOX_SIZE
#define LWIP_TIMEVAL_PRIVATE 0
// not necessary, can be done either way
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#define LWIP_SOCKET 1
#define LWIP_COMPAT_SOCKETS 1
#define LWIP_POSIX_SOCKETS_IO_NAMES 1
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4
#define MEM_SIZE 20000
#define MEMP_NUM_TCP_PCB 10
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 1
#define MEMP_NUM_NETCONN 10
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 0
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#endif
@@ -0,0 +1,46 @@
// Copyright (c) 2024 Cesanta Software Limited
// All rights reserved
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "FreeRTOS.h"
#include <task.h>
#include "mongoose.h"
#include "net.h"
#define WIFI_SSID "yourWiFiSSID"
#define WIFI_PASS "yourWiFiPassword"
static void mongoose(void *args) {
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_log_set(MG_LL_DEBUG); // Set log level
cyw43_arch_init();
cyw43_arch_enable_sta_mode();
cyw43_arch_wifi_connect_blocking(WIFI_SSID, WIFI_PASS, CYW43_AUTH_WPA2_AES_PSK);
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 10);
}
(void) args;
}
int main(void) {
// initialize stdio
stdio_init_all();
xTaskCreate(mongoose, "mongoose", 2048, 0, configMAX_PRIORITIES - 1, NULL);
vTaskStartScheduler(); // This blocks
return 0;
}
@@ -0,0 +1 @@
../../../mongoose.c
@@ -0,0 +1 @@
../../../mongoose.h
@@ -0,0 +1,4 @@
#define MG_ARCH MG_ARCH_PICOSDK
#define MG_ENABLE_LWIP 1
#define MG_ENABLE_PACKED_FS 1
@@ -0,0 +1 @@
../../device-dashboard/net.c
@@ -0,0 +1 @@
../../device-dashboard/net.h
@@ -0,0 +1 @@
../../device-dashboard/packed_fs.c
@@ -0,0 +1,84 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
endif ()
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
endif()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
)
endif ()
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})
+1
View File
@@ -0,0 +1 @@
w5500-evb-pico-picosdk-baremetal-builtin
@@ -0,0 +1,35 @@
BOARD = evb-pico
IDE = Pico-SDK
RTOS = baremetal
WIZARD_URL ?= http://mongoose.ws/wizard
all build example: firmware.uf2
firmware.uf2: wizard
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
wizard:
hash=$$(curl -s -X POST -H "Content-Type: application/json" -d '{"build":{"board":"$(BOARD)","ide":"$(IDE)","rtos":"$(RTOS)"}}' $(WIZARD_URL)/api/hash | jq -r '.hash') \
&& curl -s $(WIZARD_URL)/api/zip/$(BOARD)/$(IDE)/$(RTOS)/$$hash -o wizard.zip
unzip wizard.zip
cd wizard ; rm mongoose.[ch] ; ln -s ../../../../mongoose.c ; ln -s ../../../../mongoose.h
flash: firmware.uf2
picotool load $< -f
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/3
# stdio has to be changed from USB to UART in CMakeLists.txt
update: wizard
sed -i -e 's/pico_enable_stdio_usb(firmware 1)/pico_enable_stdio_usb(firmware 0)/' wizard/CMakeLists.txt
(test `grep -c "pico_enable_stdio_uart(firmware 1)" wizard/CMakeLists.txt` -eq 0 && echo "pico_enable_stdio_uart(firmware 1)" >> wizard/CMakeLists.txt) || true
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @firmware.uf2
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=15 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
clean:
rm -rf firmware.* wizard* pico-sdk
@@ -0,0 +1,5 @@
# RP2040 + W5500 Ethernet chip
- See [Wizard](https://mongoose.ws/wizard/#/output?board=evb-pico&ide=Pico-SDK&rtos=baremetal&file=README.md)
- See detailed tutorial (including hardware connections) at https://mongoose.ws/tutorials/rp2040/pico-w5500/
@@ -0,0 +1,35 @@
BOARD = evb-pico2
IDE = Pico-SDK
RTOS = baremetal
WIZARD_URL ?= http://mongoose.ws/wizard
all build example: firmware.uf2
firmware.uf2: wizard
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
wizard:
hash=$$(curl -s -X POST -H "Content-Type: application/json" -d '{"build":{"board":"$(BOARD)","ide":"$(IDE)","rtos":"$(RTOS)"}}' $(WIZARD_URL)/api/hash | jq -r '.hash') \
&& curl -s $(WIZARD_URL)/api/zip/$(BOARD)/$(IDE)/$(RTOS)/$$hash -o wizard.zip
unzip wizard.zip
cd wizard ; rm mongoose.[ch] ; ln -s ../../../../mongoose.c ; ln -s ../../../../mongoose.h
flash: firmware.uf2
picotool load $< -f
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/??
# stdio has to be changed from USB to UART in CMakeLists.txt
update: wizard
sed -i -e 's/pico_enable_stdio_usb(firmware 1)/pico_enable_stdio_usb(firmware 0)/' wizard/CMakeLists.txt
(test `grep -c "pico_enable_stdio_uart(firmware 1)" wizard/CMakeLists.txt` -eq 0 && echo "pico_enable_stdio_uart(firmware 1)" >> wizard/CMakeLists.txt) || true
make -C wizard CFLAGS_EXTRA=$(CFLAGS_EXTRA) && mv wizard/build/firmware.uf2 ./
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @firmware.uf2
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=15 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
clean:
rm -rf firmware.* wizard* pico-sdk
@@ -0,0 +1,5 @@
# RP2350 + W5500 Ethernet chip
- See [Wizard](https://mongoose.ws/wizard/#/output?board=evb-pico2&ide=Pico-SDK&rtos=baremetal&file=README.md)
- See detailed tutorial (including hardware connections) at https://mongoose.ws/tutorials/rp2040/pico-w5500/