mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-31 13:00:49 +00:00
move vendors -> tutorials
This commit is contained in:
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)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
@@ -0,0 +1 @@
|
||||
../../../mongoose.c
|
||||
+1
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../mongoose.c
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../device-dashboard/net.c
|
||||
@@ -0,0 +1 @@
|
||||
../../device-dashboard/net.h
|
||||
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define SIZEOF_ETH_HDR 14
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../mongoose.c
|
||||
@@ -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 @@
|
||||
../../mqtt/mqtt-dashboard/device/net.c
|
||||
@@ -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})
|
||||
Symlink
+1
@@ -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/
|
||||
|
||||
Reference in new issue
Block a user