doc: renamed project
This commit is contained in:
committed by
Sylvan Arnold
parent
244e516bd8
commit
32618389d1
79
pico-sensor/src/CMakeLists.txt
Normal file
79
pico-sensor/src/CMakeLists.txt
Normal file
@@ -0,0 +1,79 @@
|
||||
# file: Collect all files that need to be compiled.
|
||||
# You can use a GLOB function as shown here, or explicitly mention the specific files
|
||||
#file(GLOB FILES *.c *.h)
|
||||
|
||||
# Need to include CTest on every CMakeLists.txt which is going to use tests
|
||||
include(CTest)
|
||||
|
||||
set(THIS_LIBRARY_NAME srcLib)
|
||||
|
||||
file(GLOB FILES
|
||||
*.c
|
||||
)
|
||||
|
||||
if (ENABLE_UNIT_TESTING)
|
||||
message(STATUS "Adding src tests")
|
||||
add_subdirectory(./tests tests)
|
||||
endif()
|
||||
|
||||
# Set coverage option only for some files, otherwise use add_compile_options(--coverage)
|
||||
#add_compile_options(--coverage) # all files
|
||||
|
||||
set_source_files_properties(
|
||||
main.c
|
||||
application.c
|
||||
blinky.c
|
||||
buttons.c
|
||||
debounce.c
|
||||
leds.c
|
||||
platform.c
|
||||
oled.c
|
||||
sensor.c
|
||||
timer.c
|
||||
PROPERTIES COMPILE_FLAGS --coverage
|
||||
)
|
||||
|
||||
# add_library: With this declaration, you express the intent to build a library.
|
||||
# The first argument is the name of the library,
|
||||
# the second argument are the files that will be compiled to create your library.
|
||||
add_library(${THIS_LIBRARY_NAME} ${FILES})
|
||||
|
||||
add_subdirectory(${MCULIB_DIR} McuLib)
|
||||
add_subdirectory(${MCULIB_DIR}/rdimon rdimon)
|
||||
|
||||
# target_link_libraries: If you link with other libraries, list them here
|
||||
target_link_libraries(
|
||||
${THIS_LIBRARY_NAME}
|
||||
PRIVATE McuLib
|
||||
PRIVATE tinyusb_device
|
||||
|
||||
PRIVATE pico_stdlib
|
||||
PRIVATE pico_stdio_semihosting
|
||||
|
||||
PUBLIC rdimonLib # file I/O with semihosting
|
||||
PUBLIC gcov # GNU gcov library
|
||||
|
||||
# pico_cyw43_arch_none # we need CYW43 to access the GPIO, but we don't need anything else
|
||||
# PRIVATE pico_cyw43_arch_lwip_poll
|
||||
# PRIVATE pico_cyw43_arch_lwip_threadsafe_background # RAW lwIP with NO_SYS=1 in lwipopts.h
|
||||
PRIVATE pico_cyw43_arch_lwip_sys_freertos # full lwIP including blocking sockets, with NO_SYS=0 in lwipopts.h
|
||||
# PRIVATE pico_cyw43_arch_lwip_threadsafe_background # with NO_SYS=1
|
||||
# PRIVATE pico_cyw43_arch_lwip_poll #(NO_SYS=1)
|
||||
)
|
||||
|
||||
if (ENABLE_UNIT_TESTING)
|
||||
message(STATUS "Adding src tests library")
|
||||
target_link_libraries(
|
||||
${THIS_LIBRARY_NAME}
|
||||
PUBLIC srcTestsLib
|
||||
)
|
||||
endif()
|
||||
|
||||
# target_include_directories: Libraries need to publish their header files
|
||||
# so that you can import them in source code. This statement expresses where to find the files
|
||||
# - typically in an include directory of your projects.
|
||||
target_include_directories(
|
||||
${THIS_LIBRARY_NAME}
|
||||
PUBLIC
|
||||
.
|
||||
)
|
||||
166
pico-sensor/src/FreeRTOShooks.c
Normal file
166
pico-sensor/src/FreeRTOShooks.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* FreeRTOShooks.c
|
||||
*
|
||||
* Copyright (c) 2019, 2020, Erich Styger
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* This is a default FreeRTOS hooks file you can use in your application.
|
||||
*/
|
||||
|
||||
#include "McuLibconfig.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "McuTimeDate.h"
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Event : McuRTOS_vApplicationStackOverflowHook (module Events)
|
||||
**
|
||||
** Component : McuRTOS [McuRTOS]
|
||||
** Description :
|
||||
** if enabled, this hook will be called in case of a stack
|
||||
** overflow.
|
||||
** Parameters :
|
||||
** NAME - DESCRIPTION
|
||||
** pxTask - Task handle
|
||||
** * pcTaskName - Pointer to task name
|
||||
** Returns : Nothing
|
||||
** ===================================================================
|
||||
*/
|
||||
void McuRTOS_vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName)
|
||||
{
|
||||
/* This will get called if a stack overflow is detected during the context
|
||||
switch. Set configCHECK_FOR_STACK_OVERFLOWS to 2 to also check for stack
|
||||
problems within nested interrupts, but only do this for debug purposes as
|
||||
it will increase the context switch time. */
|
||||
(void)pxTask;
|
||||
(void)pcTaskName;
|
||||
taskDISABLE_INTERRUPTS();
|
||||
/* Write your code here ... */
|
||||
#if McuLib_CONFIG_CPU_IS_ARM_CORTEX_M
|
||||
__asm volatile("bkpt #0");
|
||||
#elif McuLib_CONFIG_CPU_IS_RISC_V
|
||||
__asm volatile( "ebreak" );
|
||||
#endif
|
||||
for(;;) {}
|
||||
}
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Event : McuRTOS_vApplicationMallocFailedHook (module Events)
|
||||
**
|
||||
** Component : McuRTOS [McuRTOS]
|
||||
** Description :
|
||||
** If enabled, the McuRTOS will call this hook in case memory
|
||||
** allocation failed.
|
||||
** Parameters : None
|
||||
** Returns : Nothing
|
||||
** ===================================================================
|
||||
*/
|
||||
void McuRTOS_vApplicationMallocFailedHook(void)
|
||||
{
|
||||
/* Called if a call to pvPortMalloc() fails because there is insufficient
|
||||
free memory available in the McuRTOS heap. pvPortMalloc() is called
|
||||
internally by McuRTOS API functions that create tasks, queues, software
|
||||
timers, and semaphores. The size of the McuRTOS heap is set by the
|
||||
configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
|
||||
taskDISABLE_INTERRUPTS();
|
||||
/* Write your code here ... */
|
||||
#if McuLib_CONFIG_CPU_IS_ARM_CORTEX_M
|
||||
__asm volatile("bkpt #0");
|
||||
#elif McuLib_CONFIG_CPU_IS_RISC_V
|
||||
__asm volatile( "ebreak" );
|
||||
#endif
|
||||
for(;;) {}
|
||||
}
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Event : McuRTOS_vApplicationTickHook (module Events)
|
||||
**
|
||||
** Component : McuRTOS [FreeRTOS]
|
||||
** Description :
|
||||
** If enabled, this hook will be called by the RTOS for every
|
||||
** tick increment.
|
||||
** Parameters : None
|
||||
** Returns : Nothing
|
||||
** ===================================================================
|
||||
*/
|
||||
void McuRTOS_vApplicationTickHook(void)
|
||||
{
|
||||
McuTimeDate_AddTick();
|
||||
}
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Event : McuRTOS_vApplicationIdleHook (module Events)
|
||||
**
|
||||
** Component : McuRTOS [FreeRTOS]
|
||||
** Description :
|
||||
** If enabled, this hook will be called when the RTOS is idle.
|
||||
** This might be a good place to go into low power mode.
|
||||
** Parameters : None
|
||||
** Returns : Nothing
|
||||
** ===================================================================
|
||||
*/
|
||||
void McuRTOS_vApplicationIdleHook(void)
|
||||
{
|
||||
/* Called whenever the RTOS is idle (from the IDLE task).
|
||||
Here would be a good place to put the CPU into low power mode. */
|
||||
__asm volatile("wfi");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Description :
|
||||
** Used in tickless idle mode only, but required in this mode.
|
||||
** Hook for the application to enter low power mode.
|
||||
** Parameters :
|
||||
** NAME - DESCRIPTION
|
||||
** expectedIdleTicks - expected idle
|
||||
** time, in ticks
|
||||
** Returns : Nothing
|
||||
** ===================================================================
|
||||
*/
|
||||
void McuRTOS_vOnPreSleepProcessing(TickType_t expectedIdleTicks)
|
||||
{
|
||||
(void)expectedIdleTicks; /* not used */
|
||||
#if McuLib_CONFIG_CPU_IS_ARM_CORTEX_M
|
||||
/* example for ARM Cortex-M (enable SetOperationMode() in CPU component): */
|
||||
/* Cpu_SetOperationMode(DOM_WAIT, NULL, NULL); */ /* Processor Expert way to get into WAIT mode */
|
||||
/* or to wait for interrupt: */
|
||||
__asm volatile("dsb");
|
||||
__asm volatile("wfi");
|
||||
__asm volatile("isb");
|
||||
#elif McuLib_CONFIG_CPU_IS_RISC_V
|
||||
#warning "NYI"
|
||||
#elif 0
|
||||
/* example for S08/S12/ColdFire V1 (enable SetWaitMode() in CPU): */
|
||||
Cpu_SetWaitMode();
|
||||
#elif 0
|
||||
/* example for ColdFire V2: */
|
||||
__asm("stop #0x2000"); */
|
||||
#else
|
||||
#error "you *must* enter low power mode (wait for interrupt) here!"
|
||||
#endif
|
||||
/* Write your code here ... */
|
||||
}
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Description :
|
||||
** Event called after the CPU woke up after low power mode.
|
||||
** This event is optional.
|
||||
** Parameters :
|
||||
** NAME - DESCRIPTION
|
||||
** expectedIdleTicks - expected idle
|
||||
** time, in ticks
|
||||
** Returns : Nothing
|
||||
** ===================================================================
|
||||
*/
|
||||
void McuRTOS_vOnPostSleepProcessing(TickType_t expectedIdleTicks)
|
||||
{
|
||||
(void)expectedIdleTicks; /* not used (yet?) */
|
||||
/* Write your code here ... */
|
||||
}
|
||||
187
pico-sensor/src/IncludeMcuLibConfig.h
Normal file
187
pico-sensor/src/IncludeMcuLibConfig.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/* header file is included with -include compiler option */
|
||||
|
||||
#ifndef MCULIB_CONFIG_CONFIG_H_
|
||||
#define MCULIB_CONFIG_CONFIG_H_
|
||||
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* different HW/PCB versions: */
|
||||
#define PL_CONFIG_HW_ADIS_ESP_ROBO_SHIELD (1) /* ESP32 shield on K22FX512 robot */
|
||||
#define PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_1 (2) /* Pico-W console board with OLED, sensor, nav switch, 1-Jul-2023 */
|
||||
#define PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_2 (3) /* same as PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_1, but with added nRF */
|
||||
#define PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V0_1 (4) /* ESP32 DevKitC-32E with OLED, wired PCB, sensor, nav switch and RS-485, 5-Jul-2023, obsolete */
|
||||
#define PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V0_2 (5) /* ESP32 DevKitC-32E with OLED, green PCB, sensor, nav switch, RS-485, nRF, 14-Jul-2023 */
|
||||
#define PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V1_0 (6) /* ESP32 DevKitC-32E with OLED, black PCB, sensor, nav switch, RS-485, nRF, 07-Aug-2023 */
|
||||
|
||||
/* active PCB/Hardware version */
|
||||
#define PL_CONFIG_HW_VERSION (PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_2)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* SDK */
|
||||
#define McuLib_CONFIG_CPU_IS_KINETIS (0)
|
||||
#define McuLib_CONFIG_CORTEX_M (0) /* RP2040 is a Cortex-M0+ */
|
||||
#define McuLib_CONFIG_CPU_IS_RPxxxx (1)
|
||||
#define McuLib_CONFIG_CPU_VARIANT McuLib_CONFIG_CPU_VARIANT_RP2040
|
||||
#define McuLib_CONFIG_SDK_VERSION_USED McuLib_CONFIG_SDK_RPI_PICO
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* FreeRTOS */
|
||||
#define McuLib_CONFIG_SDK_USE_FREERTOS (1)
|
||||
#define configMINIMAL_STACK_SIZE (500/sizeof(StackType_t))
|
||||
#define configTOTAL_HEAP_SIZE (48*1024)
|
||||
#define configUSE_TIMERS (1) /* needed for debouncing and TimeDate (timer.c)*/
|
||||
#define INCLUDE_xTimerPendFunctionCall (1 && configUSE_TIMERS)
|
||||
#define configTIMER_TASK_STACK_DEPTH (1024/sizeof(StackType_t)) /* stack size for Timer Service task */
|
||||
#define configTIMER_QUEUE_LENGTH (24)
|
||||
#define configUSE_SEGGER_SYSTEM_VIEWER_HOOKS (1)
|
||||
#define INCLUDE_vTaskEndScheduler (1)
|
||||
#define configUSE_IDLE_HOOK (1)
|
||||
#define configUSE_TICK_HOOK (1)
|
||||
#define configUSE_MALLOC_FAILED_HOOK (1)
|
||||
#define configCHECK_FOR_STACK_OVERFLOW (1)
|
||||
/* -------------------------------------------------*/
|
||||
/* I2C */
|
||||
#define CONFIG_USE_HW_I2C (1) /* if using HW I2C, otherwise use software bit banging */
|
||||
#define MCUI2CLIB_CONFIG_I2C_DEVICE i2c0
|
||||
#define MCUI2CLIB_CONFIG_SDA_GPIO_PIN 16u
|
||||
#define MCUI2CLIB_CONFIG_SCL_GPIO_PIN 17u
|
||||
#define MCUI2CLIB_CONFIG_ADD_DELAY_US (0)
|
||||
#define MCUI2CLIB_CONFIG_TIMEOUT_BYTE_US (1000)
|
||||
/* -------------------------------------------------*/
|
||||
/* McuGenericI2C */
|
||||
#define McuGenericI2C_CONFIG_USE_ON_ERROR_EVENT (0)
|
||||
#define McuGenericI2C_CONFIG_USE_ON_RELEASE_BUS_EVENT (0)
|
||||
#define McuGenericI2C_CONFIG_USE_ON_REQUEST_BUS_EVENT (0)
|
||||
#define McuGenericI2C_CONFIG_USE_MUTEX (1 && McuLib_CONFIG_SDK_USE_FREERTOS)
|
||||
|
||||
#if CONFIG_USE_HW_I2C /* implementation in McuI2cLib.c */
|
||||
#define McuLib_CONFIG_MCUI2CLIB_ENABLED (1)
|
||||
#define McuGenericI2C_CONFIG_INTERFACE_HEADER_FILE "McuI2cLib.h"
|
||||
#define McuGenericI2C_CONFIG_RECV_BLOCK McuI2cLib_RecvBlock
|
||||
#define McuGenericI2C_CONFIG_SEND_BLOCK McuI2cLib_SendBlock
|
||||
#if McuGenericI2C_CONFIG_SUPPORT_STOP_NO_START
|
||||
#define McuGenericI2C_CONFIG_SEND_BLOCK_CONTINUE McuI2cLib_SendBlockContinue
|
||||
#endif
|
||||
#define McuGenericI2C_CONFIG_SEND_STOP McuI2cLib_SendStop
|
||||
#define McuGenericI2C_CONFIG_SELECT_SLAVE McuI2cLib_SelectSlave
|
||||
#define McuGenericI2C_CONFIG_RECV_BLOCK_CUSTOM_AVAILABLE (0)
|
||||
#define McuGenericI2C_CONFIG_RECV_BLOCK_CUSTOM McuI2cLib_RecvBlockCustom
|
||||
|
||||
#define MCUI2CLIB_CONFIG_ADD_DELAY (0)
|
||||
#else
|
||||
/* settings for McuGenericSWI2C */
|
||||
#define SDA1_CONFIG_PIN_NUMBER (16)
|
||||
#define SCL1_CONFIG_PIN_NUMBER (17)
|
||||
|
||||
#define McuGenericSWI2C_CONFIG_DO_YIELD (0 && McuLib_CONFIG_SDK_USE_FREERTOS) /* because of Yield in GenericSWI2C */
|
||||
#define McuGenericSWI2C_CONFIG_DELAY_NS (0)
|
||||
#endif
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuSSD1306 */
|
||||
#define McuSSD1306_CONFIG_SSD1306_DRIVER_TYPE (1106)
|
||||
#define McuSSD1306_CONFIG_DYNAMIC_DISPLAY_ORIENTATION (0)
|
||||
#define McuSSD1306_CONFIG_FIXED_DISPLAY_ORIENTATION McuSSD1306_CONFIG_ORIENTATION_LANDSCAPE
|
||||
/* -------------------------------------------------*/
|
||||
/* RTT */
|
||||
#define McuRTT_CONFIG_RTT_BUFFER_SIZE_DOWN (128)
|
||||
#define McuRTT_CONFIG_BLOCKING_SEND (1) /* 0: do not block if buffer full */
|
||||
#define McuRTT_CONFIG_BLOCKING_SEND_TIMEOUT_MS (5)
|
||||
#define McuRTT_CONFIG_BLOCKING_SEND_WAIT_MS (1)
|
||||
#define McuRTT_CONFIG_RTT_BUFFER_SIZE_UP (2*1024)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* McuTimeDate */
|
||||
#define McuTimeDate_CONFIG_TICK_TIME_MS (100) /* less timer ticks, default is RTOS tick rate */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* McuShell */
|
||||
#define McuShell_CONFIG_PROJECT_NAME_STRING "TSM"
|
||||
#define McuShell_CONFIG_PROMPT_STRING "TSM> "
|
||||
#define McuShell_CONFIG_MULTI_CMD_ENABLED (1)
|
||||
#define McuShell_CONFIG_MULTI_CMD_SIZE (96)
|
||||
#define McuShell_CONFIG_DEFAULT_SHELL_BUFFER_SIZE (128)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* McuTimeDate */
|
||||
#define McuTimeDate_CONFIG_TICK_TIME_MS (100)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* McuFlash */
|
||||
#define McuFlash_CONFIG_IS_ENABLED (1) /* enable for MinINI with Flash FS */
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* MinINI */
|
||||
#define McuMinINI_CONFIG_FS (McuMinINI_CONFIG_FS_TYPE_FLASH_FS)
|
||||
#define McuMinINI_CONFIG_FLASH_NVM_ADDR_START ((XIP_BASE+2048*1024)-(McuMinINI_CONFIG_FLASH_NVM_NOF_BLOCKS*McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE)) /* pico has 2 MB Flash, starting from XIP_BASE */
|
||||
#define McuMinINI_CONFIG_FLASH_NVM_NOF_BLOCKS (1)
|
||||
#define McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE (0x1000) /* just use a single block */
|
||||
#define McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE (0x1000) /* must be multiple of 4K */
|
||||
#define McuMinINI_CONFIG_BUFFER_SIZE (128) /* maximum line and path length */
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuUart485 */
|
||||
#define McuUart485_CONFIG_USE_RS_485 (1)
|
||||
#define McuUart485_CONFIG_USE_MODBUS (McuModbus_CONFIG_IS_ENABLED)
|
||||
#define McuUart485_CONFIG_UART_BAUDRATE (115200)
|
||||
#define McuUart485_CONFIG_USE_LOGGER (1)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuSPI */
|
||||
/* RP2040: nRF24L01+ on SPI1, GP12 (MISO), GP11 (MOSI), GP10 (CLK) */
|
||||
#define MCUSPI_CONFIG_HW_TEMPLATE MCUSPI_CONFIG_HW_TEMPLATE_RP2040_SPI1
|
||||
#define MCUSPI_CONFIG_USE_CS (0) /* do not initialize CS pin */
|
||||
#define MCUSPI_CONFIG_TRANSFER_BAUDRATE (8*500000U)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuRNF24L01 */
|
||||
#define McuNRF24L01_CONFIG_IS_ENABLED (1)
|
||||
#define McuNRF24L01_CONFIG_CE_PIN_NUMBER (9)
|
||||
#define McuNRF24L01_CONFIG_CSN_PIN_NUMBER (13)
|
||||
#define McuNRF24L01_CONFIG_USE_MUTEX (0)
|
||||
#define McuNRF24L01_CONFIG_IRQ_PIN_NUMBER (8)
|
||||
#define McuNRF24L01_CONFIG_IRQ_PIN_ENABLED (1)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuRNET */
|
||||
#define McuRNET_CONFIG_IS_ENABLED (1)
|
||||
#define RNet_App_CONFIG_DO_SANITY_CHECK (0)
|
||||
#define McuRNet_CONFIG_APPLICATION_HEADER_FILE "RNet_AppConfig.h"
|
||||
#define RNET_CONFIG_TRANSCEIVER_CHANNEL (120) /* channel, default 81 */
|
||||
#define RNET_CONFIG_NRF24_DATA_RATE McuNRF24L01_RF_SETUP_RF_DR_2000
|
||||
#define RSTDIO_CONFIG_QUEUE_LENGTH (5*48) /* default is 48 */
|
||||
#define RNET_CONFIG_MSG_QUEUE_NOF_RX_ITEMS (32) /* default is 15 */
|
||||
#define RNET_CONFIG_MSG_QUEUE_NOF_TX_ITEMS (32) /* default is 15 */
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* Unity */
|
||||
#if ENABLE_UNIT_TESTS
|
||||
#if !__ASSEMBLER__ /* set if file is included by GNU as (assembler). Do not include normal C header files if running the assembler for example to assemble the pico startup code */
|
||||
#include "McuUnity.h"
|
||||
#define UNITY_OUTPUT_CHAR(a) McuUnity_putc(a)
|
||||
#define UNITY_OUTPUT_FLUSH() McuUnity_flush()
|
||||
#define UNITY_OUTPUT_START() McuUnity_start()
|
||||
#define UNITY_OUTPUT_COMPLETE() McuUnity_complete()
|
||||
#define UNITY_OUTPUT_COLOR /* use colored output */
|
||||
#endif
|
||||
#endif
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuSemihost */
|
||||
#define McuSemihost_CONFIG_IS_ENABLED (1)
|
||||
#define McuSemihost_CONFIG_DEBUG_CONNECTION McuSemihost_DEBUG_CONNECTION_SEGGER
|
||||
#define McuSemihost_CONFIG_LOG_ENABLED (0)
|
||||
#define McuSemihost_CONFIG_RETARGET_STDLIB (0)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuRdimon */
|
||||
#define McuRdimon_CONFIG_IS_ENABLED (1) /* 1: RdiMon is enabled; 0: RdiMon is disabled*/
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuCoverage */
|
||||
#define McuCoverage_CONFIG_IS_ENABLED (1)
|
||||
#define McuCoverage_CONFIG_USE_FREESTANDING (0 && McuCoverage_CONFIG_IS_ENABLED)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuLog */
|
||||
#define McuLog_CONFIG_IS_ENABLED (1)
|
||||
#define McuLog_CONFIG_USE_FILE (0)
|
||||
#define McuLog_CONFIG_USE_RTT_CONSOLE (1)
|
||||
#define McuLog_CONFIG_NOF_CONSOLE_LOGGER (2) /* RTT and USB CDC */
|
||||
#define McuLog_CONFIG_USE_COLOR (0)
|
||||
#define McuLog_CONFIG_LOG_TIMESTAMP_DATE (0)
|
||||
#define McuLog_CONFIG_LOG_TIMESTAMP_TIME (1)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
/* McuShellCdcDevice with tinyUSB */
|
||||
#define McuShellCdcDevice_CONFIG_IS_ENABLED (1)
|
||||
/* ---------------------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* MCULIB_CONFIG_CONFIG_H_ */
|
||||
45
pico-sensor/src/MinIniKeys.h
Normal file
45
pico-sensor/src/MinIniKeys.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MININIKEYS_H_
|
||||
#define MININIKEYS_H_
|
||||
|
||||
/* strings and names used in minINI configuration file */
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#define NVMC_MININI_FILE_NAME "settings.ini" /* 'file' name used */
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
/* section for WiFi settings
|
||||
* configure them using the shell and the following commands:
|
||||
* McuMinINI write settings.ini WiFi ssid YOUR_SSID
|
||||
* McuMinINI write settings.ini WiFi pass YOUR_PASSWORD
|
||||
*/
|
||||
#define NVMC_MININI_SECTION_WIFI "WiFi"
|
||||
#define NVMC_MININI_KEY_WIFI_SSID "ssid" /* string, SSID of network */
|
||||
#define NVMC_MININI_KEY_WIFI_PASS "pass" /* string, password */
|
||||
#define NVMC_MININI_KEY_WIFI_HOSTNAME "hostname" /* string, hostname to be used */
|
||||
#define NVMC_MININI_KEY_WIFI_ENABLE "enable" /* bool, if WiFi is enabled */
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
/* section for MQTT client settings */
|
||||
#define NVMC_MININI_SECTION_MQTT "MQTT"
|
||||
#define NVMC_MININI_KEY_MQTT_BROKER "broker" /* string, broker name or IP */
|
||||
#define NVMC_MININI_KEY_MQTT_CLIENT "client" /* string, client ID */
|
||||
#define NVMC_MININI_KEY_MQTT_USER "user" /* string, username */
|
||||
#define NVMC_MININI_KEY_MQTT_PASS "pass" /* string, password */
|
||||
#define NVMC_MININI_KEY_MQTT_PUBLISH "publish" /* bool, if publishing */
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
/* section for NTP client settings */
|
||||
#define NVMC_MININI_SECTION_NTP "NTP"
|
||||
#define NVMC_MININI_KEY_NTP_START "start" /* bool, if start ntp or not after reset */
|
||||
#endif
|
||||
|
||||
#endif /* MININIKEYS_H_ */
|
||||
480
pico-sensor/src/PicoWiFi.c
Normal file
480
pico-sensor/src/PicoWiFi.c
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
#include "pico/cyw43_arch.h"
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
#include "lwip/ip4_addr.h"
|
||||
#endif
|
||||
#include "PicoWiFi.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
#if PL_CONFIG_USE_PING
|
||||
#include "ping.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
#include "ntp_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
#include "mqtt_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MINI
|
||||
#include "minIni/McuMinINI.h"
|
||||
#include "MinIniKeys.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_WATCHDOG
|
||||
#include "McuWatchdog.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_BLE
|
||||
#include "ble_client.h"
|
||||
#include "ble_server.h"
|
||||
#endif
|
||||
#include "application.h"
|
||||
|
||||
#define EAP_PEAP 1 /* WPA2 Enterprise with password and no certificate */
|
||||
#define EAP_TTLS 2 /* TLS method */
|
||||
|
||||
typedef enum WiFi_PasswordMethod_e {
|
||||
WIFI_PASSWORD_METHOD_PSK,
|
||||
WIFI_PASSWORD_METHOD_WPA2, /* not supported yet */
|
||||
} WiFi_PasswordMethod_e;
|
||||
|
||||
#define CONFIG_USE_EEE (0) /* EDUROAM does not yet work with the Pico W! */
|
||||
|
||||
#if CONFIG_USE_EEE
|
||||
static const WiFi_PasswordMethod_e networkMode = WIFI_PASSWORD_METHOD_WPA2;
|
||||
#else
|
||||
static const WiFi_PasswordMethod_e networkMode = WIFI_PASSWORD_METHOD_PSK;
|
||||
#endif
|
||||
|
||||
/* default values for network */
|
||||
#define WIFI_DEFAULT_HOSTNAME "pico"
|
||||
#define WIFI_DEFAULT_SSID "ssid"
|
||||
#define WIFI_DEFAULT_PASS "password"
|
||||
|
||||
static struct wifi {
|
||||
bool isInitialized; /* if WiFi stack is initialized */
|
||||
bool isConnected; /* if we are connected to the network */
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
bool isEnabled; /* if true, it tries to connect to the network */
|
||||
unsigned char hostname[32];
|
||||
unsigned char ssid[32];
|
||||
unsigned char pass[64];
|
||||
#endif
|
||||
TaskHandle_t taskHandle;
|
||||
} wifi;
|
||||
|
||||
static uint8_t GetMAC(uint8_t mac[6], uint8_t *macStr, size_t macStrSize) {
|
||||
if (cyw43_wifi_get_mac(&cyw43_state, 0, mac)!=0) {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
macStr[0] = '\0';
|
||||
for(int i=0; i<6; i++) {
|
||||
McuUtility_strcatNum8Hex(macStr, macStrSize, mac[i]);
|
||||
if (i<6-1) {
|
||||
McuUtility_chcat(macStr, macStrSize, ':');
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_PING
|
||||
static void ping_setup(const char *host) {
|
||||
static ip_addr_t ping_addr; /* has to be global! */
|
||||
|
||||
if (wifi.isConnected) {
|
||||
ip4_addr_set_u32(&ping_addr, ipaddr_addr(host));
|
||||
Ping_InitAddress(&ping_addr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool PicoWiFi_ArchIsInit(void) {
|
||||
return wifi.isInitialized;
|
||||
}
|
||||
|
||||
void PicoWiFi_SetArchIsInitialized(bool isInitialized) {
|
||||
wifi.isInitialized = isInitialized;
|
||||
}
|
||||
|
||||
static const unsigned char *getTcpIpLinkStatusString(int linkStatus) {
|
||||
/* return a string for the value returned by cyw43_tcpip_link_status() */
|
||||
const unsigned char *statusStr;
|
||||
|
||||
switch(linkStatus) {
|
||||
case CYW43_LINK_DOWN: statusStr = "LINK_DOWN, WiFi down"; break;
|
||||
case CYW43_LINK_JOIN: statusStr = "LINK_JOIN, connected to WiFi"; break;
|
||||
case CYW43_LINK_NOIP: statusStr = "LINK_NOIP, connected to WiFi, but no IP address "; break;
|
||||
case CYW43_LINK_UP: statusStr = "LINK_UP, connect to WiFi with an IP address "; break;
|
||||
case CYW43_LINK_FAIL: statusStr = "LINK_FAIL, connection failed "; break;
|
||||
case CYW43_LINK_NONET: statusStr = "LINK_NONET, no matching SSID found "; break;
|
||||
case CYW43_LINK_BADAUTH: statusStr = "LINK_BADAUTH, authentication failure"; break;
|
||||
default: statusStr = "<unknown>"; break;
|
||||
} /* switch */
|
||||
return statusStr;
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static void initWiFi(void) {
|
||||
#if PL_CONFIG_USE_BLE && PL_CONFIG_STANDALONE_BLE_SERVER
|
||||
BleServer_SetupBLE();
|
||||
#elif PL_CONFIG_USE_BLE && PL_CONFIG_STANDALONE_BLE_CLIENT
|
||||
BleClient_SetupBLE();
|
||||
#endif
|
||||
PicoWiFi_SetArchIsInitialized(true);
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
McuLog_info("enabling STA mode");
|
||||
cyw43_arch_enable_sta_mode();
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_HOSTNAME, WIFI_DEFAULT_HOSTNAME, wifi.hostname, sizeof(wifi.hostname), NVMC_MININI_FILE_NAME);
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_SSID, WIFI_DEFAULT_SSID, wifi.ssid, sizeof(wifi.ssid), NVMC_MININI_FILE_NAME);
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_PASS, WIFI_DEFAULT_PASS, wifi.pass, sizeof(wifi.pass), NVMC_MININI_FILE_NAME);
|
||||
#else
|
||||
McuUtility_strcpy(wifi.hostname, sizeof(wifi.hostname), WIFI_DEFAULT_HOSTNAME);
|
||||
McuUtility_strcpy(wifi.ssid, sizeof(wifi.ssid), WIFI_DEFAULT_SSID);
|
||||
McuUtility_strcpy(wifi.pass, sizeof(wifi.pass), WIFI_DEFAULT_PASS);
|
||||
#endif
|
||||
McuLog_info("setting hostname: %s", wifi.hostname);
|
||||
netif_set_hostname(&cyw43_state.netif[0], wifi.hostname);
|
||||
#if PL_CONFIG_USE_WATCHDOG
|
||||
McuWatchdog_DelayAndReport(McuWatchdog_REPORT_ID_TASK_WIFI, 10, 100);
|
||||
#else
|
||||
vTaskDelay(pdMS_TO_TICKS(10*100)); /* give network tasks time to start up */
|
||||
#endif
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_WIFI */
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static bool connectToWiFi(void) {
|
||||
bool isConnected = false;
|
||||
|
||||
for(;;) { /* retries connection if it failed, breaks loop if success */
|
||||
if (!wifi.isEnabled) {
|
||||
break;
|
||||
}
|
||||
McuLog_info("connecting to SSID '%s'...", wifi.ssid);
|
||||
#if PL_CONFIG_USE_WATCHDOG
|
||||
TickType_t tickCount = McuWatchdog_ReportTimeStart();
|
||||
McuWatchdog_SuspendCheck(McuWatchdog_REPORT_ID_TASK_WIFI);
|
||||
#endif
|
||||
int res = cyw43_arch_wifi_connect_timeout_ms(wifi.ssid, wifi.pass, CYW43_AUTH_WPA2_AES_PSK, 10000); /* can take 1000-3500 ms */
|
||||
#if PL_CONFIG_USE_WATCHDOG
|
||||
McuWatchdog_ResumeCheck(McuWatchdog_REPORT_ID_TASK_WIFI);
|
||||
McuWatchdog_ReportTimeEnd(McuWatchdog_REPORT_ID_TASK_WIFI, tickCount);
|
||||
#endif
|
||||
if (res!=0) {
|
||||
McuLog_error("connection failed after timeout! code %d", res);
|
||||
vTaskDelay(pdMS_TO_TICKS(5000)); /* limit message output */
|
||||
} else {
|
||||
McuLog_info("success!");
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
if (NtpClient_GetDefaultStart()) {
|
||||
NtpClient_TaskResume();
|
||||
}
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
MqttClient_Connect();
|
||||
App_MqttTaskResume();
|
||||
#endif
|
||||
isConnected = true;
|
||||
break; /* break for loop */
|
||||
}
|
||||
} /* for */
|
||||
return isConnected;
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_WIFI */
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static bool disconnectWiFi(void) {
|
||||
if (wifi.isConnected) {
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
NtpClient_TaskSuspend();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
App_MqttTaskSuspend();
|
||||
MqttClient_Disconnect();
|
||||
#endif
|
||||
if (cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA )!=0) {
|
||||
McuLog_fatal("leaving WiFi failed");
|
||||
}
|
||||
}
|
||||
return false; /* not connected any more */
|
||||
}
|
||||
#endif
|
||||
|
||||
static void WiFiTask(void *pv) {
|
||||
int res;
|
||||
bool ledIsOn = false;
|
||||
|
||||
#if CONFIG_USE_EEE
|
||||
if (networkMode == WIFI_PASSWORD_METHOD_WPA2) {
|
||||
McuLog_info("using WPA2");
|
||||
}
|
||||
#endif
|
||||
#define WIFI_DEFAULT_ENABLE true
|
||||
#if PL_CONFIG_USE_MINI
|
||||
wifi.isEnabled = McuMinINI_ini_getbool(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_ENABLE, WIFI_DEFAULT_ENABLE, NVMC_MININI_FILE_NAME);
|
||||
#else
|
||||
wifi.isEnabled = WIFI_DEFAULT_ENABLE;
|
||||
#endif
|
||||
McuLog_info("starting WiFi task");
|
||||
/* initialize CYW43 architecture
|
||||
- will enable BT if CYW43_ENABLE_BLUETOOTH == 1
|
||||
- will enable lwIP if CYW43_LWIP == 1
|
||||
*/
|
||||
if (cyw43_arch_init_with_country(CYW43_COUNTRY_SWITZERLAND)!=0) {
|
||||
for(;;) {
|
||||
McuLog_error("failed setting country code");
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
}
|
||||
}
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
for(;;) {
|
||||
if (!wifi.isConnected && wifi.isEnabled) { /* connect to the network */
|
||||
initWiFi(); /* initialize connection and WiFi settings */
|
||||
wifi.isConnected = connectToWiFi();
|
||||
} else if (wifi.isConnected && !wifi.isEnabled) { /* request to disconnect from network */
|
||||
wifi.isConnected = disconnectWiFi();
|
||||
}
|
||||
{
|
||||
// see https://forums.raspberrypi.com/viewtopic.php?t=347706
|
||||
int linkStatus;
|
||||
static int oldLinkStatus = -1;
|
||||
const unsigned char *statusStr;
|
||||
|
||||
linkStatus = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||
if (linkStatus!=oldLinkStatus) {
|
||||
oldLinkStatus = linkStatus;
|
||||
McuLog_trace("new TCP/IP link status: %s", getTcpIpLinkStatusString(linkStatus));
|
||||
}
|
||||
}
|
||||
/* blink LED */
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, ledIsOn);
|
||||
ledIsOn = !ledIsOn;
|
||||
if (wifi.isConnected) {
|
||||
#if PL_CONFIG_USE_WATCHDOG
|
||||
McuWatchdog_DelayAndReport(McuWatchdog_REPORT_ID_TASK_WIFI, 10, 100);
|
||||
#else
|
||||
vTaskDelay(pdMS_TO_TICKS(10*100));
|
||||
#endif
|
||||
} else {
|
||||
#if PL_CONFIG_USE_WATCHDOG
|
||||
McuWatchdog_DelayAndReport(McuWatchdog_REPORT_ID_TASK_WIFI, 1, 50);
|
||||
#else
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else /* not using WiFi: blink LED */
|
||||
for(;;) {
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, ledIsOn);
|
||||
ledIsOn = !ledIsOn;
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
#endif
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_WIFI */
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static uint8_t SetSSID(const unsigned char *ssid) {
|
||||
unsigned char buf[64];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&ssid, buf, sizeof(buf));
|
||||
McuUtility_strcpy(wifi.ssid, sizeof(wifi.ssid), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_SSID, wifi.ssid, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static uint8_t SetPwd(const unsigned char *pwd) {
|
||||
unsigned char buf[64];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&pwd, buf, sizeof(buf));
|
||||
McuUtility_strcpy(wifi.pass, sizeof(wifi.pass), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_PASS, wifi.pass, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static uint8_t SetHostname(const unsigned char *pwd) {
|
||||
unsigned char buf[64];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&pwd, buf, sizeof(buf));
|
||||
McuUtility_strcpy(wifi.hostname, sizeof(wifi.hostname), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_HOSTNAME, wifi.hostname, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void WiFi_TaskSuspend(void) {
|
||||
if (wifi.taskHandle!=NULL) {
|
||||
vTaskSuspend(wifi.taskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
static void WiFi_TaskResume(void) {
|
||||
if (wifi.taskHandle!=NULL) {
|
||||
vTaskResume(wifi.taskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
static uint8_t WiFi_Enable(bool enable) {
|
||||
#if PL_CONFIG_USE_MINI
|
||||
if (McuMinINI_ini_putl(NVMC_MININI_SECTION_WIFI, NVMC_MININI_KEY_WIFI_ENABLE, enable, NVMC_MININI_FILE_NAME)!=1) { /* 1: success */
|
||||
return ERR_FAILED;
|
||||
}
|
||||
#endif
|
||||
wifi.isEnabled = enable;
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint8_t PrintStatus(McuShell_ConstStdIOType *io) {
|
||||
uint8_t mac[6];
|
||||
uint8_t macStr[] = "00:00:00:00:00:00\r\n";
|
||||
uint8_t buf[64];
|
||||
int val;
|
||||
|
||||
McuShell_SendStatusStr((unsigned char*)"wifi", (const unsigned char*)"Status of WiFi\r\n", io->stdOut);
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
McuShell_SendStatusStr((uint8_t*)" enabled", wifi.isEnabled?(unsigned char*)"yes\r\n":(unsigned char*)"no\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((uint8_t*)" connected", wifi.isConnected?(unsigned char*)"yes\r\n":(unsigned char*)"no\r\n", io->stdOut);
|
||||
McuUtility_strcpy(buf, sizeof(buf), wifi.ssid);
|
||||
McuUtility_strcat(buf, sizeof(buf), "\r\n");
|
||||
McuShell_SendStatusStr((uint8_t*)" SSID", buf, io->stdOut);
|
||||
|
||||
McuUtility_strcpy(buf, sizeof(buf), wifi.pass);
|
||||
McuUtility_strcat(buf, sizeof(buf), "\r\n");
|
||||
McuShell_SendStatusStr((uint8_t*)" pass", buf, io->stdOut);
|
||||
|
||||
val = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||
if (val<0) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), "ERROR\r\n");
|
||||
} else {
|
||||
switch(val) {
|
||||
case CYW43_LINK_JOIN: McuUtility_strcpy(buf, sizeof(buf), "joined\r\n"); break;
|
||||
case CYW43_LINK_FAIL: McuUtility_strcpy(buf, sizeof(buf), "failed\r\n"); break;
|
||||
case CYW43_LINK_NONET: McuUtility_strcpy(buf, sizeof(buf), "no network\r\n"); break;
|
||||
case CYW43_LINK_BADAUTH: McuUtility_strcpy(buf, sizeof(buf), "bad authentication\r\n"); break;
|
||||
default: McuUtility_strcpy(buf, sizeof(buf), "ERR\r\n"); break;
|
||||
}
|
||||
}
|
||||
McuShell_SendStatusStr((uint8_t*)" wifi link", buf, io->stdOut);
|
||||
|
||||
McuUtility_strcpy(buf, sizeof(buf), getTcpIpLinkStatusString(cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA)));
|
||||
McuUtility_strcat(buf, sizeof(buf), "\r\n");
|
||||
McuShell_SendStatusStr((uint8_t*)" tcp link", buf, io->stdOut);
|
||||
#endif
|
||||
if (GetMAC(mac, macStr, sizeof(macStr))==ERR_OK) {
|
||||
McuUtility_strcat(macStr, sizeof(macStr), "\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(macStr, sizeof(macStr), "ERROR\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((uint8_t*)" MAC", macStr, io->stdOut);
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
McuUtility_strcpy(buf, sizeof(buf), ip4addr_ntoa(netif_ip4_addr(netif_list)));
|
||||
McuUtility_strcat(buf, sizeof(buf), "\r\n");
|
||||
McuShell_SendStatusStr((uint8_t*)" IP", buf, io->stdOut);
|
||||
|
||||
McuUtility_strcpy(buf, sizeof(buf), netif_get_hostname(&cyw43_state.netif[0]));
|
||||
McuUtility_strcat(buf, sizeof(buf), "\r\n");
|
||||
McuShell_SendStatusStr((uint8_t*)" hostname", buf, io->stdOut);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t PicoWiFi_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
const unsigned char *p;
|
||||
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "wifi help")==0) {
|
||||
McuShell_SendHelpStr((unsigned char*)"wifi", (const unsigned char*)"Group of WiFi application commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (const unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
McuShell_SendHelpStr((unsigned char*)" enable|disable", (const unsigned char*)"Enable or disable WiFi connection\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set ssid \"<ssid>\"", (const unsigned char*)"Set the SSID\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set pwd \"<password>\"", (const unsigned char*)"Set the password\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set hostname \"<name>\"", (const unsigned char*)"Set the hostname\r\n", io->stdOut);
|
||||
#endif
|
||||
#if PL_CONFIG_USE_PING
|
||||
McuShell_SendHelpStr((unsigned char*)" ping <host>", (const unsigned char*)"Ping host\r\n", io->stdOut);
|
||||
#endif
|
||||
*handled = TRUE;
|
||||
return ERR_OK;
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "wifi status")==0)) {
|
||||
*handled = TRUE;
|
||||
return PrintStatus(io);
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
} else if (McuUtility_strncmp((char*)cmd, "wifi set ssid ", sizeof("wifi set ssid ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("wifi set ssid ")-1;
|
||||
return SetSSID(p);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "wifi set pwd ", sizeof("wifi set pwd ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("wifi set pwd ")-1;
|
||||
return SetPwd(p);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "wifi set hostname ", sizeof("wifi set hostname ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("wifi set hostname ")-1;
|
||||
return SetHostname(p);
|
||||
#endif
|
||||
#if PL_CONFIG_USE_PING
|
||||
} else if (McuUtility_strncmp((char*)cmd, "wifi ping ", sizeof("wifi ping ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("wifi ping ")-1;
|
||||
ping_setup(p);
|
||||
return ERR_OK;
|
||||
#endif
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
} else if (McuUtility_strcmp((char*)cmd, "wifi enable")==0) {
|
||||
*handled = TRUE;
|
||||
return WiFi_Enable(true);
|
||||
} else if (McuUtility_strcmp((char*)cmd, "wifi disable")==0) {
|
||||
*handled = TRUE;
|
||||
return WiFi_Enable(false);
|
||||
#endif
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void PicoWiFi_Deinit(void) {
|
||||
cyw43_arch_deinit();
|
||||
wifi.isConnected = false;
|
||||
wifi.isInitialized = false;
|
||||
}
|
||||
|
||||
void PicoWiFi_Init(void) {
|
||||
wifi.isInitialized = false;
|
||||
wifi.isConnected = false;
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
wifi.isEnabled = true;
|
||||
if (xTaskCreate(
|
||||
WiFiTask, /* pointer to the task */
|
||||
"WiFi", /* task name for kernel awareness debugging */
|
||||
4096/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+2, /* initial priority */
|
||||
&wifi.taskHandle
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("failed creating task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_WIFI */
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_PICO_W */
|
||||
36
pico-sensor/src/PicoWiFi.h
Normal file
36
pico-sensor/src/PicoWiFi.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef PICO_WIFI_H_
|
||||
#define PICO_WIFI_H_
|
||||
|
||||
#include "McuShell.h"
|
||||
|
||||
uint8_t PicoWiFi_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
|
||||
/*!
|
||||
* \brief Sets the initialized status of the CYW43 architecture
|
||||
* \param isInitialized If initialized or not
|
||||
*/
|
||||
void PicoWiFi_SetArchIsInitialized(bool isInitialized);
|
||||
|
||||
/*!
|
||||
* \brief Determine if the Cygwin WiFi chip has been initialized, because only afterwards calls to the lwIP or Cygwin device can be used.
|
||||
* \return true if cyw43_arch_init has been called, false otherwise
|
||||
*/
|
||||
bool PicoWiFi_ArchIsInit(void);
|
||||
|
||||
/*!
|
||||
* \brief Module de-initialization
|
||||
*/
|
||||
void PicoWiFi_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Module initialization
|
||||
*/
|
||||
void PicoWiFi_Init(void);
|
||||
|
||||
#endif /* PICO_WIFI_H_ */
|
||||
264
pico-sensor/src/RNet_App.c
Normal file
264
pico-sensor/src/RNet_App.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief This is main application file
|
||||
* \author (c) 2016 Erich Styger, http://mcuoneclipse.com/
|
||||
* \note MIT License (http://opensource.org/licenses/mit-license.html)
|
||||
*
|
||||
* This module implements the application part of the program.
|
||||
*/
|
||||
|
||||
#include "RNet/McuRNetConfig.h"
|
||||
#if McuRNET_CONFIG_IS_ENABLED
|
||||
#include "platform.h"
|
||||
#if PL_HAS_RADIO
|
||||
#include "RNet_App.h"
|
||||
#include "application.h"
|
||||
#include "RNet/Radio.h"
|
||||
#include "RNet/RStack.h"
|
||||
#include "RNet/RApp.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuLog.h"
|
||||
#include "RNet/RPHY.h"
|
||||
#if RNET_CONFIG_REMOTE_STDIO
|
||||
#include "RNet/RStdIO.h"
|
||||
#endif
|
||||
#if PL_HAS_REMOTE
|
||||
#include "Remote.h"
|
||||
#endif
|
||||
#if PL_HAS_MINT
|
||||
#include "MintRobot.h"
|
||||
#endif
|
||||
#if PL_CONFIG_HAS_LCD
|
||||
#include "LCD.h"
|
||||
#endif
|
||||
#include "shell.h"
|
||||
#if PL_HAS_MINT_REMOTE
|
||||
#include "MintRemote.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
#include "leds.h"
|
||||
#include "McuLED.h"
|
||||
#endif
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
#include "McuSystemView.h"
|
||||
#endif
|
||||
|
||||
static RNWK_ShortAddrType APP_dstAddr = RNWK_ADDR_BROADCAST; /* destination node address */
|
||||
|
||||
RNWK_ShortAddrType RNETA_GetDestAddr(void) {
|
||||
return APP_dstAddr;
|
||||
}
|
||||
|
||||
uint8_t RNETA_SendIdValuePairMessage(uint8_t msgType, uint16_t id, uint32_t value, RAPP_ShortAddrType addr, RAPP_FlagsType flags) {
|
||||
uint8_t dataBuf[6]; /* 2 byte ID followed by 4 byte data */
|
||||
|
||||
if (msgType==RAPP_MSG_TYPE_QUERY_VALUE) { /* only sending query with the ID, no value needed */
|
||||
McuUtility_SetValue16LE(id, &dataBuf[0]);
|
||||
return RAPP_SendPayloadDataBlock(dataBuf, sizeof(id), msgType, addr, flags);
|
||||
} else {
|
||||
McuUtility_SetValue16LE(id, &dataBuf[0]);
|
||||
McuUtility_SetValue32LE(value, &dataBuf[2]);
|
||||
return RAPP_SendPayloadDataBlock(dataBuf, sizeof(dataBuf), msgType, addr, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t HandleDataRxMessage(RAPP_MSG_Type type, uint8_t size, uint8_t *data, RNWK_ShortAddrType srcAddr, bool *handled, RPHY_PacketDesc *packet) {
|
||||
uint8_t val;
|
||||
|
||||
(void)size;
|
||||
(void)packet;
|
||||
switch(type) {
|
||||
case RAPP_MSG_TYPE_DATA: /* generic data message */
|
||||
*handled = TRUE;
|
||||
val = *data; /* get data value */
|
||||
McuLog_info("Data %d from addr 0x%x", val, srcAddr);
|
||||
return ERR_OK;
|
||||
default:
|
||||
break;
|
||||
} /* switch */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static const RAPP_MsgHandler handlerTable[] =
|
||||
{
|
||||
#if RNET_CONFIG_REMOTE_STDIO
|
||||
RSTDIO_HandleStdioRxMessage,
|
||||
#endif
|
||||
#if PL_HAS_REMOTE
|
||||
REMOTE_HandleRemoteRxMessage,
|
||||
#endif
|
||||
#if PL_HAS_MINT
|
||||
MINT_HandleRemoteRxMessage,
|
||||
#endif
|
||||
#if PL_CONFIG_HAS_LCD
|
||||
LCD_HandleRemoteRxMessage,
|
||||
#endif
|
||||
HandleDataRxMessage,
|
||||
#if PL_HAS_MINT_REMOTE
|
||||
MINTREMOTE_HandleRemoteRxMessage,
|
||||
#endif
|
||||
NULL /* sentinel */
|
||||
};
|
||||
|
||||
static void Init(void) {
|
||||
if (RAPP_SetThisNodeAddr(RNWK_ADDR_BROADCAST)!=ERR_OK) { /* set a default address */
|
||||
McuLog_fatal("Failed setting node address");
|
||||
}
|
||||
}
|
||||
|
||||
void RNETA_Deinit(void) {
|
||||
McuRNet_Deinit();
|
||||
}
|
||||
|
||||
void RNETA_Init(void) {
|
||||
Init();
|
||||
McuRNet_Init(); /* initialize stack */
|
||||
if (RAPP_SetMessageHandlerTable(handlerTable)!=ERR_OK) { /* assign application message handler */
|
||||
McuLog_fatal("failed setting message handler!");
|
||||
}
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
||||
uint8_t buf[32];
|
||||
|
||||
McuShell_SendStatusStr((unsigned char*)"rapp", (unsigned char*)"Remote App RF status\r\n", io->stdOut);
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
|
||||
#if RNWK_SHORT_ADDR_SIZE==1
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), APP_dstAddr);
|
||||
#else
|
||||
McuUtility_strcatNum16Hex(buf, sizeof(buf), APP_dstAddr);
|
||||
#endif
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((unsigned char*)" dest addr", buf, io->stdOut);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void PrintHelp(const McuShell_StdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"rapp", (unsigned char*)"Group of application commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Shows rapp help or status\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" saddr 0x<addr>", (unsigned char*)"Set source node address\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" daddr 0x<addr>", (unsigned char*)"Set destination node address\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" send val <val>", (unsigned char*)"Send a value to the destination node\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" nsend val <val>", (unsigned char*)"Send a value to the destination node, with no_ack\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set <id> <val>", (unsigned char*)"Send request to set value for an ID\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" notify <id> <val>", (unsigned char*)"Send notification value for an ID\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" query <id>", (unsigned char*)"Send a query for an ID\r\n", io->stdOut);
|
||||
#if RNET_CONFIG_REMOTE_STDIO
|
||||
McuShell_SendHelpStr((unsigned char*)" send (in/out/err)", (unsigned char*)"Send a string to stdio using the wireless transceiver\r\n", io->stdOut);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t RNETA_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
uint8_t res = ERR_OK;
|
||||
const uint8_t *p;
|
||||
uint16_t val16;
|
||||
uint8_t val8;
|
||||
|
||||
if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, (char*)"rapp help")==0) {
|
||||
*handled = TRUE;
|
||||
PrintHelp(io);
|
||||
} else if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_STATUS)==0 || McuUtility_strcmp((char*)cmd, (char*)"rapp status")==0) {
|
||||
*handled = TRUE;
|
||||
return PrintStatus(io);
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp saddr", sizeof("rapp saddr")-1)==0) {
|
||||
p = cmd + sizeof("rapp saddr")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanHex16uNumber(&p, &val16)==ERR_OK) {
|
||||
(void)RNWK_SetThisNodeAddr((RNWK_ShortAddrType)val16);
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong address\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp send val", sizeof("rapp send val")-1)==0) {
|
||||
p = cmd + sizeof("rapp send val")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanDecimal8uNumber(&p, &val8)==ERR_OK) {
|
||||
(void)RAPP_SendPayloadDataBlock(&val8, sizeof(val8), (uint8_t)RAPP_MSG_TYPE_DATA, APP_dstAddr, RPHY_PACKET_FLAGS_NONE); /* only send low byte */
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong number format\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp nsend val", sizeof("rapp nsend val")-1)==0) {
|
||||
p = cmd + sizeof("rapp nsend val")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanDecimal8uNumber(&p, &val8)==ERR_OK) {
|
||||
(void)RAPP_SendPayloadDataBlock(&val8, sizeof(val8), (uint8_t)RAPP_MSG_TYPE_DATA, APP_dstAddr, RPHY_PACKET_FLAGS_NO_ACK); /* only send low byte */
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong number format\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp notify ", sizeof("rapp notify ")-1)==0) {
|
||||
uint32_t val32u;
|
||||
|
||||
p = cmd + sizeof("rapp notify ")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanDecimal16uNumber(&p, &val16)==ERR_OK && McuUtility_ScanDecimal32uNumber(&p, &val32u)==ERR_OK) {
|
||||
RNETA_SendIdValuePairMessage(RAPP_MSG_TYPE_NOTIFY_VALUE, val16, val32u, RNETA_GetDestAddr(), RPHY_PACKET_FLAGS_NONE);
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong id format\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp set ", sizeof("rapp set ")-1)==0) {
|
||||
uint32_t val32u;
|
||||
|
||||
p = cmd + sizeof("rapp set ")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanDecimal16uNumber(&p, &val16)==ERR_OK && McuUtility_ScanDecimal32uNumber(&p, &val32u)==ERR_OK) {
|
||||
RNETA_SendIdValuePairMessage(RAPP_MSG_TYPE_REQUEST_SET_VALUE, val16, val32u, RNETA_GetDestAddr(), RPHY_PACKET_FLAGS_NONE);
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong id format\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp query ", sizeof("rapp query ")-1)==0) {
|
||||
p = cmd + sizeof("rapp query ")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanDecimal16uNumber(&p, &val16)==ERR_OK) {
|
||||
RNETA_SendIdValuePairMessage(RAPP_MSG_TYPE_QUERY_VALUE, val16, 0, RNETA_GetDestAddr(), RPHY_PACKET_FLAGS_NONE);
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong id format\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp daddr", sizeof("rapp daddr")-1)==0) {
|
||||
p = cmd + sizeof("rapp daddr")-1;
|
||||
*handled = TRUE;
|
||||
if (McuUtility_ScanHex16uNumber(&p, &val16)==ERR_OK) {
|
||||
APP_dstAddr = val16;
|
||||
} else {
|
||||
McuShell_SendStr((unsigned char*)"ERR: wrong address\r\n", io->stdErr);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
#if RNET_CONFIG_REMOTE_STDIO
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp send", sizeof("rapp send")-1)==0) {
|
||||
unsigned char buf[32];
|
||||
RSTDIO_QueueType queue;
|
||||
|
||||
if (McuUtility_strncmp((char*)cmd, (char*)"rapp send in", sizeof("rapp send in")-1)==0) {
|
||||
queue = RSTDIO_QUEUE_TX_IN;
|
||||
cmd += sizeof("rapp send in");
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp send out", sizeof("rapp send out")-1)==0) {
|
||||
queue = RSTDIO_QUEUE_TX_OUT;
|
||||
cmd += sizeof("rapp send out");
|
||||
} else if (McuUtility_strncmp((char*)cmd, (char*)"rapp send err", sizeof("rapp send err")-1)==0) {
|
||||
queue = RSTDIO_QUEUE_TX_ERR;
|
||||
cmd += sizeof("rapp send err");
|
||||
} else {
|
||||
return ERR_OK; /* not handled */
|
||||
}
|
||||
McuUtility_strcpy(buf, sizeof(buf), cmd);
|
||||
McuUtility_chcat(buf, sizeof(buf), '\n');
|
||||
buf[sizeof(buf)-2] = '\n'; /* have a '\n' in any case */
|
||||
if (RSTDIO_SendToTxStdio(queue, buf, McuUtility_strlen((char*)buf))!=ERR_OK) {
|
||||
McuShell_SendStr((unsigned char*)"failed!\r\n", io->stdErr);
|
||||
}
|
||||
*handled = TRUE;
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_SHELL */
|
||||
|
||||
#endif /* McuRNET_CONFIG_IS_ENABLED */
|
||||
|
||||
#endif /* PL_HAS_RADIO */
|
||||
49
pico-sensor/src/RNet_App.h
Normal file
49
pico-sensor/src/RNet_App.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief This is the interface to the application entry point.
|
||||
* \author (c) 2016 Erich Styger, http://mcuoneclipse.com/
|
||||
* \note MIT License (http://opensource.org/licenses/mit-license.html)
|
||||
*/
|
||||
|
||||
#ifndef RNETAPP_H_
|
||||
#define RNETAPP_H_
|
||||
|
||||
#include "RNet/McuRNetConfig.h"
|
||||
#if McuRNET_CONFIG_IS_ENABLED
|
||||
|
||||
#include "platform.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "RNet/RNWK.h"
|
||||
#include "RNet/RApp.h"
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
uint8_t RNETA_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Sends a 16bit ID plus 32bit value pair
|
||||
* \param msgType Message type
|
||||
* \param id Message ID
|
||||
* \param value Message value
|
||||
* \param addr Remote node address
|
||||
* \param flags Network flags, like request for acknowledge
|
||||
* \return Error code, ERR_OK if no failure.
|
||||
*/
|
||||
uint8_t RNETA_SendIdValuePairMessage(uint8_t msgType, uint16_t id, uint32_t value, RAPP_ShortAddrType addr, RAPP_FlagsType flags);
|
||||
|
||||
/*!
|
||||
* \brief Return the current remote node address.
|
||||
* \return Remote node address
|
||||
*/
|
||||
RNWK_ShortAddrType RNETA_GetDestAddr(void);
|
||||
|
||||
/*! \brief Driver de-initialization */
|
||||
void RNETA_Deinit(void);
|
||||
|
||||
/*! \brief Driver initialization */
|
||||
void RNETA_Init(void);
|
||||
|
||||
#endif /* McuRNET_CONFIG_IS_ENABLED */
|
||||
|
||||
#endif /* RNETAPP_H_ */
|
||||
71
pico-sensor/src/RNet_AppConfig.h
Normal file
71
pico-sensor/src/RNet_AppConfig.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief This is a configuration file for the RNet stack
|
||||
* \author (c) 2013 Erich Styger, http://mcuoneclipse.com/
|
||||
* \note MIT License (http://opensource.org/licenses/mit-license.html)
|
||||
*
|
||||
* Here the stack can be configured using macros.
|
||||
*/
|
||||
|
||||
#ifndef __RNET_APP_CONFIG__
|
||||
#define __RNET_APP_CONFIG__
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/*! type ID's for application messages */
|
||||
typedef enum {
|
||||
RAPP_MSG_TYPE_STDIN = 0x00, /* remote shell standard in channel */
|
||||
RAPP_MSG_TYPE_STDOUT = 0x01, /* remote shell standard out channel */
|
||||
RAPP_MSG_TYPE_STDERR = 0x02, /* remote shell standard error channel */
|
||||
RAPP_MSG_TYPE_ACCEL = 0x03, /* accelerometer data */
|
||||
RAPP_MSG_TYPE_DATA = 0x04, /* generic data message */
|
||||
RAPP_MSG_TYPE_JOYSTICK_XY = 0x05, /* Joystick xy message: data is x,y (two signed bytes) from -128...127 */
|
||||
RAPP_MSG_TYPE_JOYSTICK_BTN = 0x54, /* Joystick button message (data is one byte: 'A', 'B', ... 'F' and 'K') */
|
||||
/* message types for key-value pairs. IDs are of RAPP_MSG_DataIDType (16bit) and data is always 32bit */
|
||||
RAPP_MSG_TYPE_REQUEST_SET_VALUE = 0x55, /* Request to set a value for 16bit RAPP_MSG_DataIDType ID, followed by 32bit value */
|
||||
RAPP_MSG_TYPE_NOTIFY_VALUE = 0x56, /* notify value for 16bit RAPP_MSG_DataIDType, followed by 32bit value */
|
||||
RAPP_MSG_TYPE_QUERY_VALUE = 0x57, /* query value for 16bit RAPP_MSG_DataIDType */
|
||||
RAPP_MSG_TYPE_QUERY_VALUE_RESPONSE = 0x58, /* response for RAPP_MSG_TYPE_QUERY_VALUE request: 16bit RAPP_MSG_DataIDType followed by 32bit data value */
|
||||
} RAPP_MSG_Type;
|
||||
|
||||
/* IDs for RAPP_MSG_TYPE_REQUEST_SET_VALUE, RAPP_MSG_TYPE_NOTIFY_VALUE, RAPP_MSG_TYPE_QUERY_VALUE and RAPP_MSG_TYPE_QUERY_VALUE_RESPONSE */
|
||||
typedef enum {
|
||||
RAPP_MSG_TYPE_DATA_ID_NONE = 0, /* dummy ID */
|
||||
RAPP_MSG_TYPE_DATA_ID_MINT_BALL = 1, /* ball presence status: 0: not present, 1: present */
|
||||
RAPP_MSG_TYPE_DATA_ID_MINT_MODE = 2, /* mint mode: 0: manual, 1: automatic */
|
||||
RAPP_MSG_TYPE_DATA_ID_MINT_GOTO = 3, /* goto command: 0 (line), 1 (start), 2 (finish) */
|
||||
RAPP_MSG_TYPE_DATA_ID_TOF_VALUES = 4, /* ToF values: four 8bit values */
|
||||
RAPP_MSG_TYPE_DATA_ID_POSITION = 5, /* Position information: 0: no position, 1: start position, 2: finish position */
|
||||
RAPP_MSG_TYPE_DATA_ID_REED_CONTACT = 6, /* Reed contact position: 0: no position, 1: start position, 2: finish position */
|
||||
RAPP_MSG_TYPE_DATA_ID_BATTERY_V = 7, /* Battery voltage, in mV */
|
||||
RAPP_MSG_TYPE_DATA_ID_PID_FW_SPEED = 8, /* PID forward speed */
|
||||
RAPP_MSG_TYPE_DATA_ID_NEO_BRIGHTNESS = 9, /* NeoPixel brightness */
|
||||
RAPP_MSG_TYPE_DATA_ID_NEO_RED = 10, /* NeoPixel red color level */
|
||||
RAPP_MSG_TYPE_DATA_ID_NEO_GREEN = 11, /* NeoPixel green color level */
|
||||
RAPP_MSG_TYPE_DATA_ID_NEO_BLUE = 12, /* NeoPixel blue color level */
|
||||
RAPP_MSG_TYPE_DATA_ID_SUMO_START_STOP=13, /* Start/Stop sumo, 0: stop, 1: start */
|
||||
RAPP_MSG_TYPE_DATA_ID_SUMO_RADAR=14, /* Radar, 0: off, 1: on */
|
||||
RAPP_MSG_TYPE_DATA_ID_SUMO_START_LEFT=15, /* first turn, 0: right, 1: left */
|
||||
RAPP_MSG_TYPE_DATA_ID_PRESENCE_DETECTION=16, /* Presence detection, 0: no presence, 1: presence */
|
||||
} RAPP_MSG_DataIDType;
|
||||
|
||||
#ifndef RNet_App_CONFIG_DO_SANITY_CHECK
|
||||
#define RNet_App_CONFIG_DO_SANITY_CHECK (0)
|
||||
#endif
|
||||
|
||||
#if PL_HAS_RADIO
|
||||
|
||||
#if PL_HAS_SMAC
|
||||
#include "SMAC1.h"
|
||||
#define RNET_CONFIG_TRANSCEIVER_PAYLOAD_SIZE SMAC1_RADIO_BUF_SIZE /* max 128 bytes */
|
||||
/*!< Size of the physical transceiver payload (bytes), max 32 bytes for nRF24L01+, max 128 bytes for MC1320x */
|
||||
#endif
|
||||
|
||||
#if PL_HAS_NRF24
|
||||
#define RNET_CONFIG_TRANSCEIVER_PAYLOAD_SIZE 32
|
||||
/*!< Size of the physical transceiver payload (bytes), max 32 bytes for nRF24L01+, max 128 bytes for MC1320x */
|
||||
#endif
|
||||
|
||||
#endif /* PL_HAS_RADIO */
|
||||
|
||||
#endif /* __RNET_APP_CONFIG__ */
|
||||
170
pico-sensor/src/application.c
Normal file
170
pico-sensor/src/application.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "PicoWiFi.h"
|
||||
#endif
|
||||
#include "application.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLED.h"
|
||||
#include "leds.h"
|
||||
#if PL_CONFIG_USE_BUTTONS && !PL_CONFIG_USE_BUTTONS_IRQ
|
||||
#include "buttons.h"
|
||||
#include "debounce.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_OLED
|
||||
#include "oled.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GCOV
|
||||
#include "McuCoverage.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GPROF
|
||||
#include "profile_test.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
#include "mqtt_client.h"
|
||||
#include "sensor.h"
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
void App_OnButtonEvent(BTN_Buttons_e button, McuDbnc_EventKinds kind) {
|
||||
const char *p = NULL;
|
||||
|
||||
if (kind==MCUDBNC_EVENT_PRESSED) {
|
||||
switch(button) {
|
||||
case BTN_NAV_UP:
|
||||
p = "up";
|
||||
break;
|
||||
case BTN_NAV_DOWN:
|
||||
p = "down";
|
||||
break;
|
||||
case BTN_NAV_LEFT:
|
||||
p = "left";
|
||||
break;
|
||||
case BTN_NAV_RIGHT:
|
||||
p = "right";
|
||||
break;
|
||||
case BTN_NAV_CENTER:
|
||||
p = "center";
|
||||
break;
|
||||
default:
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
if (p!=NULL) {
|
||||
McuLog_info(p);
|
||||
#if PL_CONFIG_USE_OLED
|
||||
OLED_SendText(p);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void AppTask(void *pv) {
|
||||
uint32_t ms = 0;
|
||||
volatile bool dumpCoverage = true;
|
||||
|
||||
#if PL_CONFIG_USE_PICO_W && PL_CONFIG_USE_LEDS
|
||||
Leds_InitFromTask(); /* needed for the on-board Pico-W LED */
|
||||
#endif
|
||||
for(;;) {
|
||||
#if PL_CONFIG_USE_BUTTONS && !PL_CONFIG_USE_BUTTONS_IRQ
|
||||
/*! \TODO if enabled WiFi, it triggers GPIO button interrupts? Doing polling instead */
|
||||
uint32_t buttons;
|
||||
|
||||
buttons = BTN_GetButtons();
|
||||
if (buttons!=0) { /* poll buttons */
|
||||
Debounce_StartDebounce(buttons);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
ms += 20;
|
||||
#else
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
ms += 1000;
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GCOV
|
||||
if (dumpCoverage && ms>5*1000) {
|
||||
vTaskEndScheduler(); /* exit scheduler to write coverage information */
|
||||
}
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GPROF
|
||||
gprof_test();
|
||||
if (ms>5*1000) {
|
||||
vTaskEndScheduler();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
|
||||
static TaskHandle_t mqttTaskHandle = NULL;
|
||||
|
||||
void App_MqttTaskResume(void) {
|
||||
if (mqttTaskHandle!=NULL) {
|
||||
vTaskResume(mqttTaskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void App_MqttTaskSuspend(void) {
|
||||
if (mqttTaskHandle!=NULL) {
|
||||
vTaskSuspend(mqttTaskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
static void MqttTask(void *pv) {
|
||||
for(;;) {
|
||||
float t, h;
|
||||
|
||||
h = Sensor_GetHumidity();
|
||||
t = Sensor_GetTemperature();
|
||||
if (MqttClient_GetDoPublish()) {
|
||||
if (MqttClient_Publish_SensorValues(t, h)!=ERR_OK) {
|
||||
McuLog_error("failed publishing sensor values");
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
} /* for */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void App_Init(void) {
|
||||
#if PL_CONFIG_USE_APP_TASK
|
||||
if (xTaskCreate(
|
||||
AppTask, /* pointer to the task */
|
||||
"App", /* task name for kernel awareness debugging */
|
||||
1500/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+2, /* initial priority */
|
||||
(TaskHandle_t*)NULL /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("Failed creating task"); // GCOVR_EXCL_LINE
|
||||
for(;;){} /* error! probably out of memory */ // GCOVR_EXCL_LINE
|
||||
}
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
if (xTaskCreate(
|
||||
MqttTask, /* pointer to the task */
|
||||
"mqtt", /* task name for kernel awareness debugging */
|
||||
1500/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+2, /* initial priority */
|
||||
&mqttTaskHandle /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("Failed creating myqtt task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
42
pico-sensor/src/application.h
Normal file
42
pico-sensor/src/application.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __APPLICATION_H__
|
||||
#define __APPLICATION_H__
|
||||
|
||||
#include "platform.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
#include "buttons.h"
|
||||
#include "McuDebounce.h"
|
||||
|
||||
void App_OnButtonEvent(BTN_Buttons_e button, McuDbnc_EventKinds kind);
|
||||
#endif
|
||||
|
||||
uint8_t App_GetSensorValues(float *temperature, float *humidity);
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
uint8_t App_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
void App_MqttTaskResume(void);
|
||||
void App_MqttTaskSuspend(void);
|
||||
#endif
|
||||
|
||||
void App_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __APPLICATION_H__ */
|
||||
151
pico-sensor/src/blinky.c
Normal file
151
pico-sensor/src/blinky.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_BLINKY
|
||||
|
||||
#include "blinky.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
#include "leds.h"
|
||||
|
||||
static TaskHandle_t taskHandle;
|
||||
static bool blinkyIsRunning = false;
|
||||
|
||||
#define LED_OFF_TIME_MS 1000
|
||||
static uint32_t onTimeMs = 10; /* default on time of LED */
|
||||
|
||||
void Blinky_SetOnTime(uint32_t ms) {
|
||||
onTimeMs = ms;
|
||||
}
|
||||
|
||||
void Blinky_On(void) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
Leds_On(LEDS_CONFIG_HAS_RED_LED);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Blinky_Off(void) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
Leds_Off(LEDS_CONFIG_HAS_RED_LED);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Blinky_Suspend(void) {
|
||||
if (taskHandle!=NULL) {
|
||||
vTaskSuspend(taskHandle);
|
||||
blinkyIsRunning = false;
|
||||
Blinky_Off();
|
||||
}
|
||||
}
|
||||
|
||||
void Blinky_Resume(void) {
|
||||
if (taskHandle!=NULL) {
|
||||
vTaskResume(taskHandle);
|
||||
blinkyIsRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Blinky_GetStatus(unsigned char *buf, size_t bufSize) {
|
||||
buf[0] = '\0';
|
||||
if (taskHandle!=NULL) {
|
||||
eTaskState state;
|
||||
|
||||
state = eTaskGetState(taskHandle);
|
||||
switch(state) {
|
||||
case eSuspended:
|
||||
McuUtility_strcpy(buf, bufSize, (unsigned char*)"suspended");
|
||||
break;
|
||||
case eRunning:
|
||||
case eBlocked:
|
||||
McuUtility_strcpy(buf, bufSize, (unsigned char*)"running");
|
||||
break;
|
||||
default:
|
||||
case eDeleted:
|
||||
McuUtility_strcpy(buf, bufSize, (unsigned char*)"ERROR!");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
McuUtility_strcpy(buf, bufSize, (unsigned char*)"ERROR: no task!");
|
||||
}
|
||||
}
|
||||
|
||||
static void blinkyTask(void *pv) {
|
||||
(void)pv;
|
||||
blinkyIsRunning = true;
|
||||
McuLog_info("started blinky task");
|
||||
for(;;) {
|
||||
#if 0
|
||||
LED_On();
|
||||
vTaskDelay(pdMS_TO_TICKS(onTimeMs));
|
||||
LED_Off();
|
||||
vTaskDelay(pdMS_TO_TICKS(LED_OFF_TIME_MS));
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
Leds_Neg(LEDS_RED);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
Leds_Neg(LEDS_GREEN);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
Leds_Neg(LEDS_BLUE);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
Leds_Neg(LEDS_ONBOARD);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
||||
McuShell_SendStatusStr((unsigned char*)"blinky", (unsigned char*)"Blinky status\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" status", blinkyIsRunning?(unsigned char*)"resumed\r\n":(unsigned char*)"suspended\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"blinky", (unsigned char*)"Group of blinky commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Show help or status\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" suspend", (unsigned char*)"Suspend the blinky task\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" resume", (unsigned char*)"Resume the blinky task\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t Blinky_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, (char*)"blinky help")==0) {
|
||||
*handled = TRUE;
|
||||
return PrintHelp(io);
|
||||
} else if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_STATUS)==0 || McuUtility_strcmp((char*)cmd, (char*)"blinky status")==0) {
|
||||
*handled = TRUE;
|
||||
return PrintStatus(io);
|
||||
} else if (McuUtility_strcmp((char*)cmd, (char*)"blinky suspend")==0) {
|
||||
*handled = TRUE;
|
||||
Blinky_Suspend();
|
||||
} else if (McuUtility_strcmp((char*)cmd, (char*)"blinky resume")==0) {
|
||||
*handled = TRUE;
|
||||
Blinky_Resume();
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_SHELL */
|
||||
|
||||
void Blinky_Deinit(void) {
|
||||
}
|
||||
|
||||
void Blinky_Init(void) {
|
||||
BaseType_t res;
|
||||
res = xTaskCreate(blinkyTask, "blinkyTask", 4*1024/sizeof(StackType_t), NULL, tskIDLE_PRIORITY, &taskHandle);
|
||||
if (res!=pdPASS) {
|
||||
McuLog_fatal("failed creating blinky!");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_BLINKY */
|
||||
49
pico-sensor/src/blinky.h
Normal file
49
pico-sensor/src/blinky.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef BLINKY_H_
|
||||
#define BLINKY_H_
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_BLINKY
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void Blinky_SetOnTime(uint32_t ms);
|
||||
void Blinky_Suspend(void);
|
||||
void Blinky_Resume(void);
|
||||
void Blinky_GetStatus(unsigned char *buf, size_t bufSize);
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
|
||||
/*!
|
||||
* \brief Command line and shell handler
|
||||
* \param cmd The command to be parsed
|
||||
* \param handled If command has been recognized and handled
|
||||
* \param io I/O handler to be used
|
||||
* \return error code, otherwise ERR_OK
|
||||
*/
|
||||
uint8_t Blinky_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
/*! \brief Module initialization */
|
||||
void Blinky_Init(void);
|
||||
|
||||
/*! \brief Module de-initialization */
|
||||
void Blinky_Deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* PL_CONFIG_USE_BLINKY */
|
||||
|
||||
#endif /* BLINKY_H_ */
|
||||
556
pico-sensor/src/buttons.c
Normal file
556
pico-sensor/src/buttons.c
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
#include "buttons.h"
|
||||
#include "buttons_config.h"
|
||||
#include <assert.h>
|
||||
#include "McuButton.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuLED.h"
|
||||
#include "McuLog.h"
|
||||
#include "leds.h"
|
||||
#include "debounce.h"
|
||||
#if McuLib_CONFIG_CPU_IS_KINETIS
|
||||
#include "fsl_port.h"
|
||||
#elif McuLib_CONFIG_CPU_IS_LPC
|
||||
#include "fsl_pint.h"
|
||||
#include "fsl_syscon.h"
|
||||
#endif
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
#include "McuSystemView.h"
|
||||
#endif
|
||||
|
||||
typedef struct BTN_Desc_t {
|
||||
McuBtn_Handle_t handle; /* handle of button pin */
|
||||
} BTN_Desc_t;
|
||||
|
||||
static BTN_Desc_t BTN_Infos[BTN_NOF_BUTTONS];
|
||||
|
||||
BTN_Buttons_e BTN_RotateButton(BTN_Buttons_e button) {
|
||||
#if BTN_CONFIG_ROTATION==0
|
||||
return button;
|
||||
#elif BTN_CONFIG_ROTATION==180
|
||||
if (button == BTN_NAV_LEFT) {
|
||||
return BTN_NAV_RIGHT;
|
||||
} else if (button == BTN_NAV_RIGHT) {
|
||||
return BTN_NAV_LEFT;
|
||||
} else if (button == BTN_NAV_UP) {
|
||||
return BTN_NAV_DOWN;
|
||||
} else if (button == BTN_NAV_DOWN) {
|
||||
return BTN_NAV_UP;
|
||||
}
|
||||
return button;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BTN_IsPressed(BTN_Buttons_e btn) {
|
||||
assert(btn<BTN_NOF_BUTTONS);
|
||||
return McuBtn_IsOn(BTN_Infos[btn].handle);
|
||||
}
|
||||
|
||||
uint32_t BTN_GetButtons(void) {
|
||||
uint32_t val = 0;
|
||||
|
||||
if (BTN_IsPressed(BTN_NAV_UP)) {
|
||||
val |= BTN_BIT_NAV_UP;
|
||||
}
|
||||
if (BTN_IsPressed(BTN_NAV_DOWN)) {
|
||||
val |= BTN_BIT_NAV_DOWN;
|
||||
}
|
||||
if (BTN_IsPressed(BTN_NAV_LEFT)) {
|
||||
val |= BTN_BIT_NAV_LEFT;
|
||||
}
|
||||
if (BTN_IsPressed(BTN_NAV_RIGHT)) {
|
||||
val |= BTN_BIT_NAV_RIGHT;
|
||||
}
|
||||
if (BTN_IsPressed(BTN_NAV_CENTER)) {
|
||||
val |= BTN_BIT_NAV_CENTER;
|
||||
}
|
||||
#if McuLib_CONFIG_CPU_IS_LPC
|
||||
if (BTN_IsPressed(BTN_USER)) {
|
||||
val |= BTN_BIT_USER;
|
||||
}
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
/* IDs for SystemView */
|
||||
#define MCU_SYSTEM_VIEW_USER_ID_BUTTON_INTERRUPT (0)
|
||||
|
||||
static void SysViewLogStart(void) {
|
||||
McuSystemView_RecordEnterISR();
|
||||
McuSystemView_Print((const char*)"Pressed button\r\n");
|
||||
McuSystemView_OnUserStart(MCU_SYSTEM_VIEW_USER_ID_BUTTON_INTERRUPT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
static void SysViewLogEnd(void) {
|
||||
McuSystemView_OnUserStop(MCU_SYSTEM_VIEW_USER_ID_BUTTON_INTERRUPT);
|
||||
McuSystemView_RecordExitISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_KINETIS && PL_CONFIG_USE_BUTTONS_IRQ
|
||||
void PORTA_IRQHandler(void) {
|
||||
uint32_t flags;
|
||||
uint32_t buttons = 0;
|
||||
BaseType_t xHigherPriorityTaskWoken = false;
|
||||
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SysViewLogStart();
|
||||
#endif
|
||||
flags = GPIO_PortGetInterruptFlags(GPIOA);
|
||||
if (flags&(1U<<BUTTONS_PINS_NAVLEFT_PIN)) {
|
||||
buttons |= BTN_BIT_NAV_LEFT;
|
||||
}
|
||||
if (flags&(1U<<BUTTONS_PINS_NAVRIGHT_PIN)) {
|
||||
buttons |= BTN_BIT_NAV_RIGHT;
|
||||
}
|
||||
GPIO_PortClearInterruptFlags(GPIOA, flags);
|
||||
Debounce_StartDebounceFromISR(buttons, &xHigherPriorityTaskWoken);
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SysViewLogEnd();
|
||||
#endif
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
taskYIELD();
|
||||
}
|
||||
__DSB();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_KINETIS && PL_CONFIG_USE_BUTTONS_IRQ
|
||||
void PORTB_IRQHandler(void) {
|
||||
uint32_t flags;
|
||||
uint32_t buttons = 0;
|
||||
BaseType_t xHigherPriorityTaskWoken = false;
|
||||
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SysViewLogStart();
|
||||
#endif
|
||||
flags = GPIO_PortGetInterruptFlags(GPIOB);
|
||||
if (flags&(1U<<BUTTONS_PINS_NAVCENTER_PIN)) {
|
||||
buttons |= BTN_BIT_NAV_CENTER;
|
||||
}
|
||||
if (flags&(1U<<BUTTONS_PINS_NAVDOWN_PIN)) {
|
||||
buttons |= BTN_BIT_NAV_DOWN;
|
||||
}
|
||||
if (flags&(1U<<BUTTONS_PINS_NAVUP_PIN)) {
|
||||
buttons |= BTN_BIT_NAV_UP;
|
||||
}
|
||||
GPIO_PortClearInterruptFlags(GPIOB, flags);
|
||||
Debounce_StartDebounceFromISR(buttons, &xHigherPriorityTaskWoken);
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SysViewLogEnd();
|
||||
#endif
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
__DSB(); /* need barrier due ARM Cortex bug */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_LPC && PL_CONFIG_USE_BUTTONS_IRQ
|
||||
static void pint_intr_callback(pint_pin_int_t pintr, uint32_t pmatch_status) {
|
||||
BaseType_t xHigherPriorityTaskWoken = false;
|
||||
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SysViewLogStart();
|
||||
#endif
|
||||
switch(pintr) {
|
||||
case kPINT_PinInt0: Debounce_StartDebounceFromISR(BTN_BIT_USER, &xHigherPriorityTaskWoken); break;
|
||||
case kPINT_PinInt1: Debounce_StartDebounceFromISR(BTN_BIT_NAV_UP, &xHigherPriorityTaskWoken); break;
|
||||
case kPINT_PinInt2: Debounce_StartDebounceFromISR(BTN_BIT_NAV_DOWN, &xHigherPriorityTaskWoken); break;
|
||||
case kPINT_PinInt3: Debounce_StartDebounceFromISR(BTN_BIT_NAV_LEFT, &xHigherPriorityTaskWoken); break;
|
||||
case kPINT_PinInt4: Debounce_StartDebounceFromISR(BTN_BIT_NAV_RIGHT, &xHigherPriorityTaskWoken); break;
|
||||
case kPINT_PinInt5: Debounce_StartDebounceFromISR(BTN_BIT_NAV_CENTER, &xHigherPriorityTaskWoken); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SysViewLogEnd();
|
||||
#endif
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_RPxxxx && PL_CONFIG_USE_BUTTONS_IRQ
|
||||
static void gpio_IsrCallback(uint gpio, uint32_t events) {
|
||||
uint32_t button = 0; /* init */
|
||||
BaseType_t xHigherPriorityTaskWoken = false;
|
||||
|
||||
switch(gpio) {
|
||||
case BUTTONS_PINS_NAVCENTER_PIN:
|
||||
button = BTN_BIT_NAV_CENTER;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVUP_PIN:
|
||||
button = BTN_BIT_NAV_UP;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVDOWN_PIN:
|
||||
button = BTN_BIT_NAV_DOWN;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVLEFT_PIN:
|
||||
button = BTN_BIT_NAV_LEFT;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVRIGHT_PIN:
|
||||
button = BTN_BIT_NAV_RIGHT;
|
||||
break;
|
||||
default:
|
||||
button = 0;
|
||||
break;
|
||||
}
|
||||
if (button!=0) {
|
||||
Debounce_StartDebounceFromISR(button, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
static uint8_t PrintStatus(McuShell_ConstStdIOType *io) {
|
||||
uint8_t buf[64];
|
||||
|
||||
McuShell_SendStatusStr((const unsigned char*)"button", (const unsigned char*)"button status\r\n", io->stdOut);
|
||||
McuBtn_GetPinStatusString(BTN_Infos[BTN_NAV_UP].handle, buf, sizeof(buf));
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((const unsigned char*)" up", (const unsigned char*)buf, io->stdOut);
|
||||
McuBtn_GetPinStatusString(BTN_Infos[BTN_NAV_DOWN].handle, buf, sizeof(buf));
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((const unsigned char*)" down", (const unsigned char*)buf, io->stdOut);
|
||||
McuBtn_GetPinStatusString(BTN_Infos[BTN_NAV_LEFT].handle, buf, sizeof(buf));
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((const unsigned char*)" left", (const unsigned char*)buf, io->stdOut);
|
||||
McuBtn_GetPinStatusString(BTN_Infos[BTN_NAV_RIGHT].handle, buf, sizeof(buf));
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((const unsigned char*)" right", (const unsigned char*)buf, io->stdOut);
|
||||
McuBtn_GetPinStatusString(BTN_Infos[BTN_NAV_CENTER].handle, buf, sizeof(buf));
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((const unsigned char*)" center", (const unsigned char*)buf, io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(McuShell_ConstStdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"button", (const unsigned char*)"Group of button commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (const unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t BTN_ParseCommand(const uint8_t *cmd, bool *handled, McuShell_ConstStdIOType *io) {
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "button help")==0) {
|
||||
*handled = TRUE;
|
||||
return PrintHelp(io);
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "button status")==0)) {
|
||||
*handled = TRUE;
|
||||
return PrintStatus(io);
|
||||
}
|
||||
return ERR_OK; /* no error */
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_SHELL */
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32 && PL_CONFIG_USE_BUTTONS_IRQ
|
||||
static void IRAM_ATTR gpio_interrupt_handler(void *args) {
|
||||
int gpio = (int)args;
|
||||
uint32_t button = 0; /* init */
|
||||
BaseType_t xHigherPriorityTaskWoken = false;
|
||||
|
||||
switch(gpio) {
|
||||
case BUTTONS_PINS_NAVCENTER_PIN:
|
||||
button = BTN_BIT_NAV_CENTER;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVUP_PIN:
|
||||
button = BTN_BIT_NAV_UP;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVDOWN_PIN:
|
||||
button = BTN_BIT_NAV_DOWN;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVLEFT_PIN:
|
||||
button = BTN_BIT_NAV_LEFT;
|
||||
break;
|
||||
case BUTTONS_PINS_NAVRIGHT_PIN:
|
||||
button = BTN_BIT_NAV_RIGHT;
|
||||
break;
|
||||
default:
|
||||
button = 0;
|
||||
break;
|
||||
}
|
||||
if (button!=0) {
|
||||
Debounce_StartDebounceFromISR(button, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void BTN_Deinit(void) {
|
||||
#if McuLib_CONFIG_CPU_IS_KINETIS
|
||||
DisableIRQ(PORTA_IRQn);
|
||||
DisableIRQ(PORTB_IRQn);
|
||||
#endif
|
||||
for(int i=0; i<BTN_NOF_BUTTONS; i++) {
|
||||
BTN_Infos[i].handle = McuBtn_DeinitButton(BTN_Infos[i].handle);
|
||||
}
|
||||
}
|
||||
|
||||
void BTN_Init(void) {
|
||||
#if McuLib_CONFIG_CPU_IS_KINETIS
|
||||
McuBtn_Config_t btnConfig;
|
||||
|
||||
BUTTONS_ENABLE_CLOCK();
|
||||
McuBtn_GetDefaultConfig(&btnConfig);
|
||||
btnConfig.isLowActive = true;
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVCENTER_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVCENTER_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVCENTER_PIN;
|
||||
#if PL_CONFIG_BOARD_ID==PL_CONFIG_BOARD_ID_TINYK22_APROG_HAT_V7 /* V7 does not have hardware pull-ups on the board */
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
#endif
|
||||
BTN_Infos[BTN_NAV_CENTER].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVLEFT_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVLEFT_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVLEFT_PIN;
|
||||
#if PL_CONFIG_BOARD_ID==PL_CONFIG_BOARD_ID_TINYK22_APROG_HAT_V7 /* V7 does not have hardware pull-ups on the board */
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
#endif
|
||||
BTN_Infos[BTN_NAV_LEFT].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVRIGHT_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVRIGHT_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVRIGHT_PIN;
|
||||
#if PL_CONFIG_BOARD_ID==PL_CONFIG_BOARD_ID_TINYK22_APROG_HAT_V7 /* V7 does not have hardware pull-ups on the board */
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
#endif
|
||||
BTN_Infos[BTN_NAV_RIGHT].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVUP_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVUP_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVUP_PIN;
|
||||
#if PL_CONFIG_BOARD_ID==PL_CONFIG_BOARD_ID_TINYK22_APROG_HAT_V7 /* V7 does not have hardware pull-ups on the board */
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
#endif
|
||||
BTN_Infos[BTN_NAV_UP].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVDOWN_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVDOWN_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVDOWN_PIN;
|
||||
#if PL_CONFIG_BOARD_ID==PL_CONFIG_BOARD_ID_TINYK22_APROG_HAT_V7 /* V7 does not have hardware pull-ups on the board */
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
#endif
|
||||
BTN_Infos[BTN_NAV_DOWN].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
#if PL_CONFIG_USE_BUTTONS_IRQ
|
||||
PORT_SetPinInterruptConfig(BUTTONS_PINS_NAVLEFT_PORT, BUTTONS_PINS_NAVLEFT_PIN, kPORT_InterruptFallingEdge);
|
||||
PORT_SetPinInterruptConfig(BUTTONS_PINS_NAVRIGHT_PORT, BUTTONS_PINS_NAVRIGHT_PIN, kPORT_InterruptFallingEdge);
|
||||
NVIC_SetPriority(PORTA_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
|
||||
EnableIRQ(PORTA_IRQn);
|
||||
|
||||
PORT_SetPinInterruptConfig(BUTTONS_PINS_NAVDOWN_PORT, BUTTONS_PINS_NAVDOWN_PIN, kPORT_InterruptFallingEdge);
|
||||
PORT_SetPinInterruptConfig(BUTTONS_PINS_NAVUP_PORT, BUTTONS_PINS_NAVUP_PIN, kPORT_InterruptFallingEdge);
|
||||
PORT_SetPinInterruptConfig(BUTTONS_PINS_NAVCENTER_PORT, BUTTONS_PINS_NAVCENTER_PIN, kPORT_InterruptFallingEdge);
|
||||
NVIC_SetPriority(PORTB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
|
||||
EnableIRQ(PORTB_IRQn);
|
||||
#endif
|
||||
#elif McuLib_CONFIG_CPU_IS_LPC
|
||||
/* user button on LPC845-BRK board: PIO0_4 */
|
||||
|
||||
McuBtn_Config_t btnConfig;
|
||||
|
||||
BUTTONS_ENABLE_CLOCK();
|
||||
McuBtn_GetDefaultConfig(&btnConfig);
|
||||
btnConfig.isLowActive = true;
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_USER_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_USER_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_USER_PIN;
|
||||
btnConfig.hw.iocon = BUTTONS_PINS_USER_IOCON;
|
||||
BTN_Infos[BTN_USER].handle = McuBtn_InitButton(&btnConfig);
|
||||
SYSCON_AttachSignal(SYSCON, kPINT_PinInt0, BUTTONS_PINS_USER_PINTSEL);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVUP_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVUP_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVUP_PIN;
|
||||
btnConfig.hw.iocon = BUTTONS_PINS_NAVUP_IOCON;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_UP].handle = McuBtn_InitButton(&btnConfig);
|
||||
SYSCON_AttachSignal(SYSCON, kPINT_PinInt1, BUTTONS_PINS_NAVUP_PINTSEL);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVDOWN_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVDOWN_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVDOWN_PIN;
|
||||
btnConfig.hw.iocon = BUTTONS_PINS_NAVDOWN_IOCON;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_DOWN].handle = McuBtn_InitButton(&btnConfig);
|
||||
SYSCON_AttachSignal(SYSCON, kPINT_PinInt2, BUTTONS_PINS_NAVDOWN_PINTSEL);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVLEFT_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVLEFT_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVLEFT_PIN;
|
||||
btnConfig.hw.iocon = BUTTONS_PINS_NAVLEFT_IOCON;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_LEFT].handle = McuBtn_InitButton(&btnConfig);
|
||||
SYSCON_AttachSignal(SYSCON, kPINT_PinInt3, BUTTONS_PINS_NAVLEFT_PINTSEL);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVRIGHT_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVRIGHT_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVRIGHT_PIN;
|
||||
btnConfig.hw.iocon = BUTTONS_PINS_NAVRIGHT_IOCON;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_RIGHT].handle = McuBtn_InitButton(&btnConfig);
|
||||
SYSCON_AttachSignal(SYSCON, kPINT_PinInt4, BUTTONS_PINS_NAVRIGHT_PINTSEL);
|
||||
|
||||
btnConfig.hw.gpio = BUTTONS_PINS_NAVCENTER_GPIO;
|
||||
btnConfig.hw.port = BUTTONS_PINS_NAVCENTER_PORT;
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVCENTER_PIN;
|
||||
btnConfig.hw.iocon = BUTTONS_PINS_NAVCENTER_IOCON;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_CENTER].handle = McuBtn_InitButton(&btnConfig);
|
||||
SYSCON_AttachSignal(SYSCON, kPINT_PinInt5, BUTTONS_PINS_NAVCENTER_PINTSEL);
|
||||
|
||||
#if PL_CONFIG_USE_BUTTONS_IRQ
|
||||
PINT_Init(PINT); /* Initialize PINT */
|
||||
PINT_PinInterruptConfig(PINT, kPINT_PinInt0, kPINT_PinIntEnableFallEdge, pint_intr_callback); /* Setup Pin Interrupt 0 for rising edge */
|
||||
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt0); /* Enable callbacks for PINT0 by Index */
|
||||
|
||||
PINT_PinInterruptConfig(PINT, kPINT_PinInt1, kPINT_PinIntEnableFallEdge, pint_intr_callback);
|
||||
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt1);
|
||||
|
||||
PINT_PinInterruptConfig(PINT, kPINT_PinInt2, kPINT_PinIntEnableFallEdge, pint_intr_callback);
|
||||
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt2);
|
||||
|
||||
PINT_PinInterruptConfig(PINT, kPINT_PinInt3, kPINT_PinIntEnableFallEdge, pint_intr_callback);
|
||||
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt3);
|
||||
|
||||
PINT_PinInterruptConfig(PINT, kPINT_PinInt4, kPINT_PinIntEnableFallEdge, pint_intr_callback);
|
||||
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt4);
|
||||
|
||||
PINT_PinInterruptConfig(PINT, kPINT_PinInt5, kPINT_PinIntEnableFallEdge, pint_intr_callback);
|
||||
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt5);
|
||||
#endif
|
||||
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
||||
McuBtn_Config_t btnConfig;
|
||||
|
||||
BUTTONS_ENABLE_CLOCK();
|
||||
McuBtn_GetDefaultConfig(&btnConfig);
|
||||
btnConfig.isLowActive = true;
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVCENTER_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_CENTER].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVLEFT_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_LEFT].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVRIGHT_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_RIGHT].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVUP_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_UP].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVDOWN_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_UP;
|
||||
BTN_Infos[BTN_NAV_DOWN].handle = McuBtn_InitButton(&btnConfig);
|
||||
#if PL_CONFIG_USE_BUTTONS_IRQ
|
||||
gpio_set_irq_enabled_with_callback(BUTTONS_PINS_NAVCENTER_PIN, GPIO_IRQ_EDGE_FALL, true, &gpio_IsrCallback);
|
||||
gpio_set_irq_enabled_with_callback(BUTTONS_PINS_NAVUP_PIN, GPIO_IRQ_EDGE_FALL, true, &gpio_IsrCallback);
|
||||
gpio_set_irq_enabled_with_callback(BUTTONS_PINS_NAVDOWN_PIN, GPIO_IRQ_EDGE_FALL, true, &gpio_IsrCallback);
|
||||
gpio_set_irq_enabled_with_callback(BUTTONS_PINS_NAVLEFT_PIN, GPIO_IRQ_EDGE_FALL, true, &gpio_IsrCallback);
|
||||
gpio_set_irq_enabled_with_callback(BUTTONS_PINS_NAVRIGHT_PIN, GPIO_IRQ_EDGE_FALL, true, &gpio_IsrCallback);
|
||||
#endif
|
||||
#elif McuLib_CONFIG_CPU_IS_ESP32
|
||||
McuBtn_Config_t btnConfig;
|
||||
|
||||
BUTTONS_ENABLE_CLOCK();
|
||||
McuBtn_GetDefaultConfig(&btnConfig);
|
||||
btnConfig.isLowActive = true;
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVCENTER_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_DISABLE;
|
||||
BTN_Infos[BTN_NAV_CENTER].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVLEFT_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_DISABLE;
|
||||
BTN_Infos[BTN_NAV_LEFT].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVRIGHT_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_DISABLE;
|
||||
BTN_Infos[BTN_NAV_RIGHT].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVUP_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_DISABLE;
|
||||
BTN_Infos[BTN_NAV_UP].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
btnConfig.hw.pin = BUTTONS_PINS_NAVDOWN_PIN;
|
||||
btnConfig.hw.pull = McuGPIO_PULL_DISABLE;
|
||||
BTN_Infos[BTN_NAV_DOWN].handle = McuBtn_InitButton(&btnConfig);
|
||||
|
||||
#if PL_CONFIG_USE_BUTTONS_IRQ
|
||||
#define ESP_INTR_FLAG_DEFAULT 0
|
||||
esp_err_t res;
|
||||
|
||||
res = gpio_set_intr_type(BUTTONS_PINS_NAVCENTER_PIN, GPIO_INTR_NEGEDGE); /* set to falling edge */
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed setting interrupt type");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_set_intr_type(BUTTONS_PINS_NAVLEFT_PIN, GPIO_INTR_NEGEDGE); /* set to falling edge */
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed setting interrupt type");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_set_intr_type(BUTTONS_PINS_NAVRIGHT_PIN, GPIO_INTR_NEGEDGE); /* set to falling edge */
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed setting interrupt type");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_set_intr_type(BUTTONS_PINS_NAVUP_PIN, GPIO_INTR_NEGEDGE); /* set to falling edge */
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed setting interrupt type");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_set_intr_type(BUTTONS_PINS_NAVDOWN_PIN, GPIO_INTR_NEGEDGE); /* set to falling edge */
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed setting interrupt type");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed installing interrupt service");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_isr_handler_add(BUTTONS_PINS_NAVCENTER_PIN, gpio_interrupt_handler, (void *)BUTTONS_PINS_NAVCENTER_PIN);
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed adding interrupt handler");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_isr_handler_add(BUTTONS_PINS_NAVLEFT_PIN, gpio_interrupt_handler, (void *)BUTTONS_PINS_NAVLEFT_PIN);
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed adding interrupt handler");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_isr_handler_add(BUTTONS_PINS_NAVRIGHT_PIN, gpio_interrupt_handler, (void *)BUTTONS_PINS_NAVRIGHT_PIN);
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed adding interrupt handler");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_isr_handler_add(BUTTONS_PINS_NAVUP_PIN, gpio_interrupt_handler, (void *)BUTTONS_PINS_NAVUP_PIN);
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed adding interrupt handler");
|
||||
for(;;) {}
|
||||
}
|
||||
res = gpio_isr_handler_add(BUTTONS_PINS_NAVDOWN_PIN, gpio_interrupt_handler, (void *)BUTTONS_PINS_NAVDOWN_PIN);
|
||||
if (res!=ESP_OK) {
|
||||
McuLog_fatal("Failed adding interrupt handler");
|
||||
for(;;) {}
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_BUTTONS_IRQ */
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_BUTTONS */
|
||||
64
pico-sensor/src/buttons.h
Normal file
64
pico-sensor/src/buttons.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef BUTTONS_H_
|
||||
#define BUTTONS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "buttons_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
/*!
|
||||
* \brief Module command line parser
|
||||
* \param cmd Pointer to command string to be parsed
|
||||
* \param handled Set to TRUE if command has handled by parser
|
||||
* \param io Shell standard I/O handler
|
||||
* \return Error code, ERR_OK if everything was ok
|
||||
*/
|
||||
uint8_t BTN_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Decides if a button is pressed, directly accessing the pin
|
||||
* \param btn Button to check
|
||||
* \return true if button is pressed
|
||||
*/
|
||||
bool BTN_IsPressed(BTN_Buttons_e btn);
|
||||
|
||||
/*!
|
||||
* \brief Read the button status from the pins and build a bitmask
|
||||
* \return Bitmask of buttons pressed, e.g. BTN_BIT_NAV_UP, see buttons_config.h
|
||||
*/
|
||||
uint32_t BTN_GetButtons(void);
|
||||
|
||||
/*!
|
||||
* \brief Rotates the button orientation based on BTN_CONFIG_ROTATION
|
||||
* \param button button pressed
|
||||
* \return rotated button
|
||||
*/
|
||||
BTN_Buttons_e BTN_RotateButton(BTN_Buttons_e button);
|
||||
|
||||
/*!
|
||||
* \brief Module de-initialization
|
||||
*/
|
||||
void BTN_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Module initialization
|
||||
*/
|
||||
void BTN_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BUTTONS_H_ */
|
||||
126
pico-sensor/src/buttons_config.h
Normal file
126
pico-sensor/src/buttons_config.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* buttons_config.h
|
||||
*
|
||||
* Copyright (c) 2021-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef BUTTONS_CONFIG_H_
|
||||
#define BUTTONS_CONFIG_H_
|
||||
|
||||
#include "McuLib.h"
|
||||
#include "platform.h"
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_KINETIS
|
||||
#define BUTTONS_PINS_NAVUP_GPIO GPIOB
|
||||
#define BUTTONS_PINS_NAVUP_PORT PORTB
|
||||
#define BUTTONS_PINS_NAVUP_PIN 3u
|
||||
|
||||
#define BUTTONS_PINS_NAVDOWN_GPIO GPIOB
|
||||
#define BUTTONS_PINS_NAVDOWN_PORT PORTB
|
||||
#define BUTTONS_PINS_NAVDOWN_PIN 2u
|
||||
|
||||
#define BUTTONS_PINS_NAVLEFT_GPIO GPIOA
|
||||
#define BUTTONS_PINS_NAVLEFT_PORT PORTA
|
||||
#define BUTTONS_PINS_NAVLEFT_PIN 13u
|
||||
|
||||
#define BUTTONS_PINS_NAVRIGHT_GPIO GPIOA
|
||||
#define BUTTONS_PINS_NAVRIGHT_PORT PORTA
|
||||
#define BUTTONS_PINS_NAVRIGHT_PIN 12u
|
||||
|
||||
#define BUTTONS_PINS_NAVCENTER_GPIO GPIOB
|
||||
#define BUTTONS_PINS_NAVCENTER_PORT PORTB
|
||||
#define BUTTONS_PINS_NAVCENTER_PIN 16u
|
||||
|
||||
#define BUTTONS_ENABLE_CLOCK() CLOCK_EnableClock(kCLOCK_PortA); CLOCK_EnableClock(kCLOCK_PortB) /* enable clocking */
|
||||
#elif McuLib_CONFIG_CPU_IS_LPC
|
||||
/* user button on LPC845-BRK board: PIO0_4 */
|
||||
#define BUTTONS_PINS_USER_GPIO GPIO
|
||||
#define BUTTONS_PINS_USER_PORT 0
|
||||
#define BUTTONS_PINS_USER_PIN 4
|
||||
#define BUTTONS_PINS_USER_IOCON IOCON_INDEX_PIO0_4
|
||||
#define BUTTONS_PINS_USER_PINTSEL kSYSCON_GpioPort0Pin4ToPintsel
|
||||
|
||||
#define BUTTONS_PINS_NAVUP_GPIO GPIO
|
||||
#define BUTTONS_PINS_NAVUP_PORT 0
|
||||
#define BUTTONS_PINS_NAVUP_PIN 8u
|
||||
#define BUTTONS_PINS_NAVUP_IOCON IOCON_INDEX_PIO0_8
|
||||
#define BUTTONS_PINS_NAVUP_PINTSEL kSYSCON_GpioPort0Pin8ToPintsel
|
||||
|
||||
#define BUTTONS_PINS_NAVDOWN_GPIO GPIO
|
||||
#define BUTTONS_PINS_NAVDOWN_PORT 0
|
||||
#define BUTTONS_PINS_NAVDOWN_PIN 9u
|
||||
#define BUTTONS_PINS_NAVDOWN_IOCON IOCON_INDEX_PIO0_9
|
||||
#define BUTTONS_PINS_NAVDOWN_PINTSEL kSYSCON_GpioPort0Pin9ToPintsel
|
||||
|
||||
#define BUTTONS_PINS_NAVLEFT_GPIO GPIO
|
||||
#define BUTTONS_PINS_NAVLEFT_PORT 0
|
||||
#define BUTTONS_PINS_NAVLEFT_PIN 29u
|
||||
#define BUTTONS_PINS_NAVLEFT_IOCON IOCON_INDEX_PIO0_29
|
||||
#define BUTTONS_PINS_NAVLEFT_PINTSEL kSYSCON_GpioPort0Pin29ToPintsel
|
||||
|
||||
#define BUTTONS_PINS_NAVRIGHT_GPIO GPIO
|
||||
#define BUTTONS_PINS_NAVRIGHT_PORT 0
|
||||
#define BUTTONS_PINS_NAVRIGHT_PIN 28u
|
||||
#define BUTTONS_PINS_NAVRIGHT_IOCON IOCON_INDEX_PIO0_28
|
||||
#define BUTTONS_PINS_NAVRIGHT_PINTSEL kSYSCON_GpioPort0Pin28ToPintsel
|
||||
|
||||
#define BUTTONS_PINS_NAVCENTER_GPIO GPIO
|
||||
#define BUTTONS_PINS_NAVCENTER_PORT 0
|
||||
#define BUTTONS_PINS_NAVCENTER_PIN 27u
|
||||
#define BUTTONS_PINS_NAVCENTER_IOCON IOCON_INDEX_PIO0_27
|
||||
#define BUTTONS_PINS_NAVCENTER_PINTSEL kSYSCON_GpioPort0Pin27ToPintsel
|
||||
|
||||
#define BUTTONS_ENABLE_CLOCK() GPIO_PortInit(GPIO, 0) /* ungate the clocks for GPIO0: used for user button */
|
||||
#elif PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_1
|
||||
#define BUTTONS_PINS_NAVUP_PIN 15u
|
||||
#define BUTTONS_PINS_NAVDOWN_PIN 14u
|
||||
#define BUTTONS_PINS_NAVLEFT_PIN 13u
|
||||
#define BUTTONS_PINS_NAVRIGHT_PIN 12u
|
||||
#define BUTTONS_PINS_NAVCENTER_PIN 11u
|
||||
|
||||
#define BUTTONS_ENABLE_CLOCK() /* nothing */
|
||||
#elif PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_2
|
||||
#define BUTTONS_PINS_NAVUP_PIN 14u
|
||||
#define BUTTONS_PINS_NAVDOWN_PIN 15u
|
||||
#define BUTTONS_PINS_NAVLEFT_PIN 28u
|
||||
#define BUTTONS_PINS_NAVRIGHT_PIN 26u
|
||||
#define BUTTONS_PINS_NAVCENTER_PIN 27u
|
||||
|
||||
#define BUTTONS_ENABLE_CLOCK() /* nothing */
|
||||
#elif McuLib_CONFIG_CPU_IS_ESP32
|
||||
/* ESP32: Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not. */
|
||||
#define BUTTONS_PINS_NAVUP_PIN GPIO_NUM_25
|
||||
#define BUTTONS_PINS_NAVDOWN_PIN GPIO_NUM_39 /* hardware bug: with WiFi enabled, it triggers an interrupt if using interrupts! */
|
||||
#define BUTTONS_PINS_NAVLEFT_PIN GPIO_NUM_35
|
||||
#define BUTTONS_PINS_NAVRIGHT_PIN GPIO_NUM_36 /* hardware bug: with WiFi enabled, it triggers an interrupt if using interrupts! */
|
||||
#define BUTTONS_PINS_NAVCENTER_PIN GPIO_NUM_34
|
||||
#define BUTTONS_ENABLE_CLOCK() /* nothing */
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
BTN_NAV_UP,
|
||||
BTN_NAV_DOWN,
|
||||
BTN_NAV_LEFT,
|
||||
BTN_NAV_RIGHT,
|
||||
BTN_NAV_CENTER,
|
||||
#if McuLib_CONFIG_CPU_IS_LPC
|
||||
BTN_USER,
|
||||
#endif
|
||||
BTN_NOF_BUTTONS /* sentinel, must be last in list! */
|
||||
} BTN_Buttons_e;
|
||||
|
||||
/* bits of the buttons */
|
||||
#define BTN_BIT_NAV_UP (1<<0)
|
||||
#define BTN_BIT_NAV_DOWN (1<<1)
|
||||
#define BTN_BIT_NAV_LEFT (1<<2)
|
||||
#define BTN_BIT_NAV_RIGHT (1<<3)
|
||||
#define BTN_BIT_NAV_CENTER (1<<4)
|
||||
#if McuLib_CONFIG_CPU_IS_LPC
|
||||
#define BTN_BIT_USER (1<<5)
|
||||
#endif
|
||||
|
||||
#define BTN_CONFIG_ROTATION (0) /* 180 for rotated nav 180 degree */
|
||||
|
||||
#endif /* BUTTONS_CONFIG_H_ */
|
||||
111
pico-sensor/src/debounce.c
Normal file
111
pico-sensor/src/debounce.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
|
||||
#include "debounce.h"
|
||||
#include "McuDebounce.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "buttons.h"
|
||||
#include "application.h"
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
#include "McuSystemView.h"
|
||||
#endif
|
||||
|
||||
static void OnDebounceEvent(McuDbnc_EventKinds event, uint32_t buttons);
|
||||
|
||||
#define TIMER_PERIOD_MS 20 /* frequency of debouncing timer */
|
||||
|
||||
static McuDbnc_Desc_t data =
|
||||
{
|
||||
.state = MCUDBMC_STATE_IDLE, /* state of state machine */
|
||||
.timerPeriodMs = TIMER_PERIOD_MS, /* timer period for debouncing */
|
||||
.timer = NULL, /* FreeRTOS timer handle */
|
||||
.debounceTimeMs = 100, /* debouncing time */
|
||||
.repeatTimeMs = 200, /* time for repeated button events */
|
||||
.longKeyTimeMs = 1000, /* time for a long key press */
|
||||
.getButtons = BTN_GetButtons, /* callback to get bitset of buttons */
|
||||
.onDebounceEvent = OnDebounceEvent, /* debounce event handler */
|
||||
};
|
||||
|
||||
static void OnDebounceEvent(McuDbnc_EventKinds event, uint32_t buttons) {
|
||||
BTN_Buttons_e button = BTN_NOF_BUTTONS;
|
||||
|
||||
if (buttons&BTN_BIT_NAV_LEFT) {
|
||||
button = BTN_NAV_LEFT;
|
||||
} else if (buttons&BTN_BIT_NAV_RIGHT) {
|
||||
button = BTN_NAV_RIGHT;
|
||||
} else if (buttons&BTN_BIT_NAV_UP) {
|
||||
button = BTN_NAV_UP;
|
||||
} else if (buttons&BTN_BIT_NAV_DOWN) {
|
||||
button = BTN_NAV_DOWN;
|
||||
} else if (buttons&BTN_BIT_NAV_CENTER) {
|
||||
button = BTN_NAV_CENTER;
|
||||
}
|
||||
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
SEGGER_SYSVIEW_PrintfTarget("event: %d, buttons %d pressed:\n", buttons, event);
|
||||
#endif
|
||||
switch(event) {
|
||||
case MCUDBNC_EVENT_PRESSED:
|
||||
case MCUDBNC_EVENT_PRESSED_REPEAT:
|
||||
case MCUDBNC_EVENT_LONG_PRESSED:
|
||||
case MCUDBNC_EVENT_LONG_PRESSED_REPEAT:
|
||||
case MCUDBNC_EVENT_RELEASED:
|
||||
case MCUDBNC_EVENT_LONG_RELEASED:
|
||||
button = BTN_RotateButton(button);
|
||||
App_OnButtonEvent(button, event);
|
||||
break;
|
||||
|
||||
case MCUDBNC_EVENT_END:
|
||||
(void)xTimerStop(data.timer, pdMS_TO_TICKS(100)); /* stop timer */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void vTimerCallbackDebounce(TimerHandle_t pxTimer) {
|
||||
/* called with TIMER_PERIOD_MS during debouncing */
|
||||
McuDbnc_Process(&data);
|
||||
}
|
||||
|
||||
void Debounce_StartDebounce(uint32_t buttons) {
|
||||
if (data.state==MCUDBMC_STATE_IDLE) {
|
||||
data.scanValue = buttons;
|
||||
data.state = MCUDBMC_STATE_START;
|
||||
McuDbnc_Process(&data);
|
||||
(void)xTimerStart(data.timer, pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
|
||||
void Debounce_StartDebounceFromISR(uint32_t buttons, BaseType_t *pxHigherPriorityTaskWoken) {
|
||||
if (data.state==MCUDBMC_STATE_IDLE) {
|
||||
data.scanValue = buttons;
|
||||
data.state = MCUDBMC_STATE_START;
|
||||
McuDbnc_Process(&data);
|
||||
(void)xTimerStartFromISR(data.timer, pxHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
|
||||
void Debounce_Deinit(void) { // GCOVR_EXCL_LINE
|
||||
/* nothing needed */ // GCOVR_EXCL_LINE
|
||||
} // GCOVR_EXCL_LINE
|
||||
|
||||
void Debounce_Init(void) {
|
||||
data.timer = xTimerCreate(
|
||||
"tmrDbnc", /* name */
|
||||
pdMS_TO_TICKS(TIMER_PERIOD_MS), /* period/time */
|
||||
pdTRUE, /* auto reload */
|
||||
(void*)0, /* timer ID */
|
||||
vTimerCallbackDebounce); /* callback */
|
||||
if (data.timer==NULL) {
|
||||
for(;;); /* failure! */ // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_BUTTONS */
|
||||
45
pico-sensor/src/debounce.h
Normal file
45
pico-sensor/src/debounce.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef DEBOUNCE_H_
|
||||
#define DEBOUNCE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "McuRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Start debouncing with a set of buttons. Do not call this method from an interrupt.
|
||||
* The application gets notified through events.
|
||||
* \param buttons Set of initial buttons pressed
|
||||
*/
|
||||
void Debounce_StartDebounce(uint32_t buttons);
|
||||
|
||||
/*!
|
||||
* \brief Same as Debounce_StartDebounce(), but usable from an interrupt
|
||||
* \param buttons Set of initial buttons pressed
|
||||
* \param pxHigherPriorityTaskWoken Set to true if a task with a higher priority has been woken up
|
||||
*/
|
||||
void Debounce_StartDebounceFromISR(uint32_t buttons, BaseType_t *pxHigherPriorityTaskWoken);
|
||||
|
||||
/*!
|
||||
* Module de-initialization
|
||||
*/
|
||||
void Debounce_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Module initialization
|
||||
*/
|
||||
void Debounce_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* DEBOUNCE_H_ */
|
||||
71
pico-sensor/src/dns_resolver.c
Normal file
71
pico-sensor/src/dns_resolver.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "dns_resolver.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuRTOS.h"
|
||||
|
||||
typedef void (*DnsResolver_dns_found_cb_fptr)(const char *hostname, const ip_addr_t *ipaddr, void *arg);
|
||||
|
||||
/* Call back with a DNS result */
|
||||
static void dns_found_cb(const char *hostname, const ip_addr_t *ipaddr, void *arg) {
|
||||
DnsResolver_info_t *info = (DnsResolver_info_t*)arg;
|
||||
info->dns_response_received = true; /* have received a response */
|
||||
if (ipaddr!=NULL) {
|
||||
info->resolved_addr = *ipaddr; /* store address */
|
||||
info->dns_request_sent = false;
|
||||
McuLog_info("'%s' resolved to %s", hostname, ip4addr_ntoa(ipaddr));
|
||||
} else {
|
||||
McuLog_error("dns request for '%s' failed", hostname);
|
||||
/* keep dns_request_sent asserted, so caller knows that it is an error */
|
||||
}
|
||||
}
|
||||
|
||||
static DnsResolver_dns_found_cb_fptr dnsFoundCallback = dns_found_cb;
|
||||
|
||||
void DnsResolver_SetDnsFoundCallback(DnsResolver_dns_found_cb_fptr callback) {
|
||||
dnsFoundCallback = callback;
|
||||
}
|
||||
|
||||
int DnsResolver_ResolveName(const char *name, DnsResolver_info_t *info, int32_t timeoutMs) {
|
||||
if (name[0]>='0' && name[0]<='9') { /* Assuming IP address */
|
||||
u32_t addr_u32 = ipaddr_addr(name); /* convert ASCII (e.g. "192.168.1.1") to a value in network order */
|
||||
ip4_addr_set_u32(&info->resolved_addr, addr_u32); /* set the IP address given as u32_t */
|
||||
} else {
|
||||
info->dns_response_received = false; /* reset flag */
|
||||
info->dns_request_sent = true;
|
||||
cyw43_arch_lwip_begin();
|
||||
int err = dns_gethostbyname(name, &info->resolved_addr, dnsFoundCallback, info);
|
||||
cyw43_arch_lwip_end();
|
||||
|
||||
if (err == ERR_OK) { /* cached result */
|
||||
McuLog_info("dns cached result for '%s', OK", name);
|
||||
return 0; /* ok */
|
||||
} else if (err != ERR_INPROGRESS) { /* ERR_INPROGRESS means expect a callback */
|
||||
McuLog_error("dns request failed for '%s", name);
|
||||
return -1; /* failed */
|
||||
}
|
||||
while(timeoutMs>0 && !info->dns_response_received) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); /* wait for response */
|
||||
timeoutMs -= 100;
|
||||
}
|
||||
if (timeoutMs<=0) {
|
||||
McuLog_error("dns request timeout");
|
||||
return -2;
|
||||
}
|
||||
if (info->dns_response_received && info->dns_request_sent) {
|
||||
/* sent flag not reset? error */
|
||||
McuLog_error("dns response for '%s' received, but not successful", name);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
return 0; /* ok */
|
||||
}
|
||||
|
||||
__attribute__((weak)) void DnsResolver_Init(void) {
|
||||
}
|
||||
34
pico-sensor/src/dns_resolver.h
Normal file
34
pico-sensor/src/dns_resolver.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef DNS_RESOLVER_H_
|
||||
#define DNS_RESOLVER_H_
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct DnsResolver_info_t {
|
||||
bool dns_request_sent; /* flag set after sending a DNS response. Reset if received a good answer */
|
||||
bool dns_response_received; /* flag to indicate in DNS callback that we have received a response */
|
||||
ip_addr_t resolved_addr; /* here the resolved address gets stored */
|
||||
} DnsResolver_info_t;
|
||||
|
||||
/*!
|
||||
* \brief resolves a name (IP or hostname) string to an address
|
||||
* \param name IP ("192.168.1.1") or hostname ("server")
|
||||
* \param info Pointer to data, which is used to store the address found. Does not need to be initialized, but has to global or memory always accessible, as dns callback can happen later.
|
||||
* \param timeoutMs timeout in milliseconds. Uses FreeRTOS delay
|
||||
* \return negative number in case of error, 0 otherwise
|
||||
*/
|
||||
int DnsResolver_ResolveName(const char *name, DnsResolver_info_t *info, int32_t timeoutMs);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Module intitialization function. Marked as 'weak' so it can be overwritten by fff (fake functions framework) for testing
|
||||
*/
|
||||
__attribute__((weak)) void DnsResolver_Init(void);
|
||||
|
||||
#endif /* DNS_RESOLVER_H_ */
|
||||
402
pico-sensor/src/leds.c
Normal file
402
pico-sensor/src/leds.c
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "PicoWiFi.h"
|
||||
#endif
|
||||
#include "McuLib.h"
|
||||
#include "leds_config.h"
|
||||
#include "leds.h"
|
||||
#include "McuLED.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
static McuLED_Handle_t ledRed;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
static McuLED_Handle_t ledGreen;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
static McuLED_Handle_t ledBlue;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
static McuLED_Handle_t ledOrange;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
static bool onBoardLedIsOn = false;
|
||||
#else
|
||||
static McuLED_Handle_t ledOnboard;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void Leds_On(LEDS_Leds_e led) {
|
||||
switch(led) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
case LEDS_RED: McuLED_On(ledRed); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
case LEDS_GREEN: McuLED_On(ledGreen); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
case LEDS_BLUE: McuLED_On(ledBlue); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
case LEDS_ORANGE: McuLED_On(ledOrange); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
case LEDS_ONBOARD:
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
onBoardLedIsOn = true;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, onBoardLedIsOn);
|
||||
#else
|
||||
McuLED_On(ledOnboard);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break; /* error */
|
||||
}
|
||||
}
|
||||
|
||||
void Leds_Off(LEDS_Leds_e led) {
|
||||
switch(led) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
case LEDS_RED: McuLED_Off(ledRed); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
case LEDS_GREEN: McuLED_Off(ledGreen); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
case LEDS_BLUE: McuLED_Off(ledBlue); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
case LEDS_ORANGE: McuLED_Off(ledOrange); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
case LEDS_ONBOARD:
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
onBoardLedIsOn = false;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, onBoardLedIsOn);
|
||||
#else
|
||||
McuLED_Off(ledOnboard);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break; /* error */
|
||||
}
|
||||
}
|
||||
|
||||
void Leds_Neg(LEDS_Leds_e led) {
|
||||
switch(led) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
case LEDS_RED: McuLED_Toggle(ledRed); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
case LEDS_GREEN: McuLED_Toggle(ledGreen); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
case LEDS_BLUE: McuLED_Toggle(ledBlue); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
case LEDS_ORANGE: McuLED_Toggle(ledOrange); break;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
case LEDS_ONBOARD:
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
onBoardLedIsOn = !onBoardLedIsOn;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, onBoardLedIsOn);
|
||||
#else
|
||||
McuLED_Toggle(ledOnboard);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break; /* error */
|
||||
}
|
||||
}
|
||||
|
||||
bool Leds_Get(LEDS_Leds_e led) {
|
||||
switch(led) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
case LEDS_RED: return McuLED_Get(ledRed);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
case LEDS_GREEN: return McuLED_Get(ledGreen);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
case LEDS_BLUE: return McuLED_Get(ledBlue);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
case LEDS_ORANGE: return McuLED_Get(ledOrange);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
case LEDS_ONBOARD:
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
return onBoardLedIsOn;
|
||||
#else
|
||||
return McuLED_Get(ledOnboard);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break; /* error */
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
static uint8_t PrintStatus(McuShell_ConstStdIOType *io) {
|
||||
uint8_t buf[16];
|
||||
|
||||
McuShell_SendStatusStr((const unsigned char*)"led", (const unsigned char*)"LED module status\r\n", io->stdOut);
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
if (Leds_Get(LEDS_RED)) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is ON\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is OFF\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((const unsigned char*)" red", (const unsigned char*)buf, io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
if (Leds_Get(LEDS_GREEN)) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is ON\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is OFF\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((const unsigned char*)" green", (const unsigned char*)buf, io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
if (Leds_Get(LEDS_BLUE)) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is ON\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is OFF\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((const unsigned char*)" blue", (const unsigned char*)buf, io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
if (Leds_Get(LEDS_ORANGE)) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is ON\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is OFF\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((const unsigned char*)" orange", (const unsigned char*)buf, io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
if (Leds_Get(LEDS_ONBOARD)) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is ON\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"is OFF\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((const unsigned char*)" onboard", (const unsigned char*)buf, io->stdOut);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(McuShell_ConstStdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"led", (const unsigned char*)"Group of LED commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (const unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
McuShell_SendHelpStr((unsigned char*)" red on|off|neg", (const unsigned char*)"Control red LED\r\n", io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
McuShell_SendHelpStr((unsigned char*)" green on|off|neg", (const unsigned char*)"Control green LED\r\n", io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
McuShell_SendHelpStr((unsigned char*)" blue on|off|neg", (const unsigned char*)"Control blue LED\r\n", io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
McuShell_SendHelpStr((unsigned char*)" orange on|off|neg", (const unsigned char*)"Control orange LED\r\n", io->stdOut);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
McuShell_SendHelpStr((unsigned char*)" onboard on|off|neg", (const unsigned char*)"Control onboard LED\r\n", io->stdOut);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static bool ParseLedCommand(const unsigned char *cmd, bool *handled, unsigned char *ledStr, LEDS_Leds_e led) {
|
||||
unsigned char ledCmd[16];
|
||||
size_t len;
|
||||
|
||||
McuUtility_strcpy(ledCmd, sizeof(ledCmd), (const unsigned char*)"led ");
|
||||
McuUtility_strcat(ledCmd, sizeof(ledCmd), ledStr);
|
||||
len = McuUtility_strlen((char*)ledCmd);
|
||||
if (McuUtility_strncmp((char*)cmd, (char*)ledCmd, len)==0) {
|
||||
*handled = true;
|
||||
cmd += len;
|
||||
if (McuUtility_strcmp((char*)cmd, " on")==0) {
|
||||
Leds_On(led);
|
||||
return true;
|
||||
} else if (McuUtility_strcmp((char*)cmd, " off")==0) {
|
||||
Leds_Off(led);
|
||||
return true;
|
||||
} else if (McuUtility_strcmp((char*)cmd, " neg")==0) {
|
||||
Leds_Neg(led);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; /* not found */
|
||||
}
|
||||
|
||||
uint8_t Leds_ParseCommand(const uint8_t *cmd, bool *handled, McuShell_ConstStdIOType *io) {
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "led help")==0) {
|
||||
*handled = TRUE;
|
||||
return PrintHelp(io);
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "led status")==0)) {
|
||||
*handled = TRUE;
|
||||
return PrintStatus(io);
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
} else if (ParseLedCommand(cmd, handled, (unsigned char*)"red", LEDS_RED)) {
|
||||
return ERR_OK;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
} else if (ParseLedCommand(cmd, handled, (unsigned char*)"green", LEDS_GREEN)) {
|
||||
return ERR_OK;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
} else if (ParseLedCommand(cmd, handled, (unsigned char*)"blue", LEDS_BLUE)) {
|
||||
return ERR_OK;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
} else if (ParseLedCommand(cmd, handled, (unsigned char*)"orange", LEDS_ORANGE)) {
|
||||
return ERR_OK;
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
} else if (ParseLedCommand(cmd, handled, (unsigned char*)"onboard", LEDS_ONBOARD)) {
|
||||
return ERR_OK;
|
||||
#endif
|
||||
}
|
||||
return ERR_OK; /* no error */
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_SHELL */
|
||||
|
||||
void Leds_Init(void) {
|
||||
McuLED_Config_t config;
|
||||
|
||||
LEDS_CONFIG_ENABLE_CLOCK(); /* enable clocking or initialize GPIO as required by hardware */
|
||||
|
||||
McuLED_GetDefaultConfig(&config);
|
||||
config.isOnInit = false;
|
||||
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
#if McuLib_CONFIG_CPU_IS_LPC || McuLib_CONFIG_CPU_IS_KINETIS
|
||||
config.hw.gpio = LEDS_CONFIG_RED_GPIO;
|
||||
config.hw.port = LEDS_CONFIG_RED_PORT;
|
||||
#endif
|
||||
config.hw.pin = LEDS_CONFIG_RED_PIN;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC
|
||||
config.hw.iocon = LEDS_CONFIG_RED_IOCON;
|
||||
#endif
|
||||
config.isLowActive = LEDS_CONFIG_RED_LOW_ACTIVE;
|
||||
ledRed = McuLED_InitLed(&config);
|
||||
if (ledRed==NULL) {
|
||||
for(;;) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
config.isLowActive = true;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC || McuLib_CONFIG_CPU_IS_KINETIS
|
||||
config.hw.gpio = LEDS_CONFIG_GREEN_GPIO;
|
||||
config.hw.port = LEDS_CONFIG_GREEN_PORT;
|
||||
#endif
|
||||
config.hw.pin = LEDS_CONFIG_GREEN_PIN;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC
|
||||
config.hw.iocon = LEDS_CONFIG_GREEN_IOCON;
|
||||
#endif
|
||||
config.isLowActive = LEDS_CONFIG_GREEN_LOW_ACTIVE;
|
||||
ledGreen = McuLED_InitLed(&config);
|
||||
if (ledGreen==NULL) {
|
||||
for(;;) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
config.isLowActive = true;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC || McuLib_CONFIG_CPU_IS_KINETIS
|
||||
config.hw.gpio = LEDS_CONFIG_BLUE_GPIO;
|
||||
config.hw.port = LEDS_CONFIG_BLUE_PORT;
|
||||
#endif
|
||||
config.hw.pin = LEDS_CONFIG_BLUE_PIN;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC
|
||||
config.hw.iocon = LEDS_CONFIG_BLUE_IOCON;
|
||||
#endif
|
||||
config.isLowActive = LEDS_CONFIG_BLUE_LOW_ACTIVE;
|
||||
ledBlue = McuLED_InitLed(&config);
|
||||
if (ledBlue==NULL) {
|
||||
for(;;) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
config.isLowActive = false;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC || McuLib_CONFIG_CPU_IS_KINETIS
|
||||
config.hw.gpio = LEDS_CONFIG_ORANGE_GPIO;
|
||||
config.hw.port = LEDS_CONFIG_ORANGE_PORT;
|
||||
#endif
|
||||
config.hw.pin = LEDS_CONFIG_ORANGE_PIN;
|
||||
ledOrange = McuLED_InitLed(&config);
|
||||
config.isLowActive = LEDS_CONFIG_ORANGE_LOW_ACTIVE;
|
||||
if (ledOrange==NULL) {
|
||||
for(;;) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
/* NOTE: you have to call Leds_InitFromTask() from a FreeRTOS task context! */
|
||||
#else
|
||||
config.isLowActive = true;
|
||||
#if McuLib_CONFIG_CPU_IS_LPC || McuLib_CONFIG_CPU_IS_KINETIS
|
||||
config.hw.gpio = LEDS_CONFIG_ONBOARD_GPIO;
|
||||
config.hw.port = LEDS_CONFIG_ONBOARD_PORT;
|
||||
#endif
|
||||
config.hw.pin = LEDS_CONFIG_ONBOARD_PIN;
|
||||
config.isLowActive = LEDS_CONFIG_ONBOARD_LOW_ACTIVE;
|
||||
ledOnboard = McuLED_InitLed(&config);
|
||||
if (ledOnboard==NULL) {
|
||||
for(;;) {}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void Leds_InitFromTask(void) {
|
||||
#if !PL_CONFIG_USE_WIFI && PL_CONFIG_USE_PICO_W
|
||||
if (cyw43_arch_init()==0) { /* need to init for accessing LEDs and other pins */
|
||||
PicoWiFi_SetArchIsInitialized(true);
|
||||
} else {
|
||||
McuLog_fatal("failed initializing CYW43");
|
||||
for(;;){}
|
||||
}
|
||||
onBoardLedIsOn = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Leds_Deinit(void) {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
ledRed = McuLED_DeinitLed(ledRed);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
ledGreen = McuLED_DeinitLed(ledGreen);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
ledBlue = McuLED_DeinitLed(ledBlue);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ORANGE_LED
|
||||
ledOrange = McuLED_DeinitLed(ledOrange);
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED &&! PL_CONFIG_USE_PICO_W
|
||||
ledOnboard = McuLED_DeinitLed(ledOnboard);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_LEDS */
|
||||
101
pico-sensor/src/leds.h
Normal file
101
pico-sensor/src/leds.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MY_LEDS_H_
|
||||
#define MY_LEDS_H_
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
|
||||
#include "McuLib.h"
|
||||
#include "leds_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "McuShell.h"
|
||||
|
||||
/*!
|
||||
* \brief Command line handler
|
||||
* \param cmd String to command to be parsed
|
||||
* \param handled Returns if command has been handled
|
||||
* \param io I/O channel
|
||||
* \return Error code, ERR_OK if everything is ok
|
||||
*/
|
||||
uint8_t Leds_ParseCommand(const uint8_t *cmd, bool *handled, McuShell_ConstStdIOType *io);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* handles for the different LEDs
|
||||
*/
|
||||
typedef enum LEDS_Leds_e {
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
LEDS_RED,
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
LEDS_GREEN,
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
LEDS_BLUE,
|
||||
#endif
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
LEDS_ONBOARD,
|
||||
#endif
|
||||
LEDS_NOF_LEDS, /*!< Sentinel, must be last! */
|
||||
} LEDS_Leds_e;
|
||||
|
||||
/*!
|
||||
* \brief Turn LED on
|
||||
* \param led LED handle
|
||||
*/
|
||||
void Leds_On(LEDS_Leds_e led);
|
||||
|
||||
/*!
|
||||
* \brief Turn LED off
|
||||
* \param led LED handle
|
||||
*/
|
||||
void Leds_Off(LEDS_Leds_e led);
|
||||
|
||||
/*!
|
||||
* \brief Toggle LED
|
||||
* \param led LED handle
|
||||
*/
|
||||
void Leds_Neg(LEDS_Leds_e led);
|
||||
|
||||
/*!
|
||||
* \brief Return the status (on/off) of the LED
|
||||
* \param led LED handle
|
||||
* \return true if LED is on, false otherwise
|
||||
*/
|
||||
bool Leds_Get(LEDS_Leds_e led);
|
||||
|
||||
/*!
|
||||
* \brief Module initialization, call it to initialize the driver
|
||||
*/
|
||||
void Leds_Init(void);
|
||||
|
||||
/*!
|
||||
* \brief Initialization to be called from a task context, for example for the on-board LED of the Pico-W
|
||||
*/
|
||||
void Leds_InitFromTask(void);
|
||||
|
||||
/*!
|
||||
* \brief Module de-initialization, call it to de-initialize the driver
|
||||
*/
|
||||
void Leds_Deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* PL_CONFIG_USE_LEDS */
|
||||
|
||||
#endif /* MY_LEDS_H_ */
|
||||
93
pico-sensor/src/leds_config.h
Normal file
93
pico-sensor/src/leds_config.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef LEDS_CONFIG_H_
|
||||
#define LEDS_CONFIG_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V0_1) \
|
||||
|| (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V0_2) \
|
||||
|| (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V1_0)
|
||||
#define LEDS_CONFIG_HAS_ONBOARD_LED (0)
|
||||
#define LEDS_CONFIG_HAS_RED_LED (1)
|
||||
#define LEDS_CONFIG_HAS_GREEN_LED (1)
|
||||
#define LEDS_CONFIG_HAS_BLUE_LED (1)
|
||||
#define LEDS_CONFIG_HAS_ORANGE_LED (0)
|
||||
#elif PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP_ROBO_SHIELD
|
||||
#define LEDS_CONFIG_HAS_ONBOARD_LED (0)
|
||||
#define LEDS_CONFIG_HAS_RED_LED (1)
|
||||
#define LEDS_CONFIG_HAS_GREEN_LED (0)
|
||||
#define LEDS_CONFIG_HAS_BLUE_LED (0)
|
||||
#define LEDS_CONFIG_HAS_ORANGE_LED (0)
|
||||
#elif (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_1) || (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_2)
|
||||
#define LEDS_CONFIG_HAS_ONBOARD_LED (1)
|
||||
#define LEDS_CONFIG_HAS_RED_LED (1)
|
||||
#define LEDS_CONFIG_HAS_GREEN_LED (1)
|
||||
#define LEDS_CONFIG_HAS_BLUE_LED (1)
|
||||
#define LEDS_CONFIG_HAS_ORANGE_LED (0)
|
||||
#endif
|
||||
|
||||
#if (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V0_1) \
|
||||
|| (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V0_2) \
|
||||
|| (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP32_CONSOLE_V1_0)
|
||||
#define LEDS_CONFIG_ENABLE_CLOCK() /* nothing */
|
||||
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
/* red led on IO27, HIGH active */
|
||||
#define LEDS_CONFIG_RED_PIN (GPIO_NUM_27)
|
||||
#define LEDS_CONFIG_RED_LOW_ACTIVE (0)
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
/* green led on IO26, HIGH active */
|
||||
#define LEDS_CONFIG_GREEN_PIN (GPIO_NUM_26)
|
||||
#define LEDS_CONFIG_GREEN_LOW_ACTIVE (0)
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
/* blue led on IO16, HIGH active */
|
||||
#define LEDS_CONFIG_BLUE_PIN (GPIO_NUM_16)
|
||||
#define LEDS_CONFIG_BLUE_LOW_ACTIVE (0)
|
||||
#endif
|
||||
#elif PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_ESP_ROBO_SHIELD
|
||||
#define LEDS_CONFIG_ENABLE_CLOCK() /* nothing */
|
||||
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
/* red led on the shield is on IO10, LOW active */
|
||||
#define LEDS_CONFIG_RED_PIN (GPIO_NUM_10) /* IO10 */
|
||||
#define LEDS_CONFIG_RED_LOW_ACTIVE (1)
|
||||
#endif
|
||||
#elif (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_1) || (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_2)
|
||||
/* Green: GPIO18
|
||||
* Blue: GPIO19
|
||||
* Red: GPIO20 */
|
||||
#define LEDS_CONFIG_ENABLE_CLOCK() /* nothing */
|
||||
|
||||
#if LEDS_CONFIG_HAS_RED_LED
|
||||
#define LEDS_CONFIG_RED_PIN 20
|
||||
#define LEDS_CONFIG_RED_LOW_ACTIVE false
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_GREEN_LED
|
||||
#define LEDS_CONFIG_GREEN_PIN 19
|
||||
#define LEDS_CONFIG_GREEN_LOW_ACTIVE false
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_BLUE_LED
|
||||
#define LEDS_CONFIG_BLUE_PIN 18
|
||||
#define LEDS_CONFIG_BLUE_LOW_ACTIVE false
|
||||
#endif
|
||||
|
||||
#if LEDS_CONFIG_HAS_ONBOARD_LED
|
||||
#if !PL_CONFIG_USE_PICO_W
|
||||
#define LEDS_CONFIG_ONBOARD_PIN 25 /* only for non-W! */
|
||||
#define LEDS_CONFIG_ONBOARD_LOW_ACTIVE false
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* LEDS_CONFIG_H_ */
|
||||
153
pico-sensor/src/lwipopts.h
Normal file
153
pico-sensor/src/lwipopts.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#ifndef _LWIPOPTS_H
|
||||
#define _LWIPOPTS_H
|
||||
|
||||
// Generally you would define your own explicit list of lwIP options
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
|
||||
//
|
||||
|
||||
#ifndef NO_SYS
|
||||
#define NO_SYS 0 /* with FreeRTOS (pico_cyw43_arch_lwip_sys_freertos), this needs to be set to 0 */
|
||||
#endif
|
||||
// allow override in some examples
|
||||
#ifndef LWIP_SOCKET
|
||||
#define LWIP_SOCKET 1
|
||||
#endif
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
#define MEM_LIBC_MALLOC 1
|
||||
#else
|
||||
// MEM_LIBC_MALLOC is incompatible with non polling versions
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
#endif
|
||||
#define MEM_ALIGNMENT 4
|
||||
#define MEM_SIZE 16000
|
||||
#define MEMP_NUM_TCP_SEG 32
|
||||
#define MEMP_NUM_ARP_QUEUE 10
|
||||
#define PBUF_POOL_SIZE (2*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 MEM_STATS 0
|
||||
#define SYS_STATS 0
|
||||
#define MEMP_STATS 0
|
||||
#define LINK_STATS 0
|
||||
// #define ETH_PAD_SIZE 2
|
||||
#define LWIP_CHKSUM_ALGORITHM 3
|
||||
#define LWIP_DHCP 1
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_TCP 1
|
||||
#define LWIP_UDP 1
|
||||
#define LWIP_DNS 1
|
||||
#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
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define LWIP_DEBUG 1
|
||||
#define LWIP_STATS 1
|
||||
#define LWIP_STATS_DISPLAY 1
|
||||
#endif
|
||||
|
||||
#define ETHARP_DEBUG LWIP_DBG_OFF
|
||||
#define NETIF_DEBUG LWIP_DBG_OFF
|
||||
#define PBUF_DEBUG LWIP_DBG_OFF
|
||||
#define API_LIB_DEBUG LWIP_DBG_OFF
|
||||
#define API_MSG_DEBUG LWIP_DBG_OFF
|
||||
#define SOCKETS_DEBUG LWIP_DBG_OFF
|
||||
#define ICMP_DEBUG LWIP_DBG_OFF
|
||||
#define INET_DEBUG LWIP_DBG_OFF
|
||||
#define IP_DEBUG LWIP_DBG_OFF
|
||||
#define IP_REASS_DEBUG LWIP_DBG_OFF
|
||||
#define RAW_DEBUG LWIP_DBG_OFF
|
||||
#define MEM_DEBUG LWIP_DBG_OFF
|
||||
#define MEMP_DEBUG LWIP_DBG_OFF
|
||||
#define SYS_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RTO_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_CWND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_WND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_FR_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RST_DEBUG LWIP_DBG_OFF
|
||||
#define UDP_DEBUG LWIP_DBG_OFF
|
||||
#define TCPIP_DEBUG LWIP_DBG_OFF
|
||||
#define PPP_DEBUG LWIP_DBG_OFF
|
||||
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
#if !NO_SYS
|
||||
#define TCPIP_THREAD_STACKSIZE 1024
|
||||
#define TCPIP_THREAD_PRIO 3
|
||||
#define DEFAULT_THREAD_STACKSIZE 1024
|
||||
#define DEFAULT_RAW_RECVMBOX_SIZE 8
|
||||
#define TCPIP_MBOX_SIZE 8
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
|
||||
// not necessary, can be done either way
|
||||
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
|
||||
#endif
|
||||
|
||||
/* You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use MQTT!
|
||||
* see https://forums.raspberrypi.com/viewtopic.php?t=341914
|
||||
*/
|
||||
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 1)
|
||||
#define MQTT_REQ_MAX_IN_FLIGHT (5) /* maximum of subscribe requests */
|
||||
|
||||
#define DEFAULT_UDP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
|
||||
#define DEFAULT_TCP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
|
||||
#define DEFAULT_ACCEPTMBOX_SIZE TCPIP_MBOX_SIZE
|
||||
|
||||
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
|
||||
sends a lot of data out of ROM (or other static memory), this
|
||||
should be set high. */
|
||||
#ifndef MEMP_NUM_PBUF
|
||||
#define MEMP_NUM_PBUF 15
|
||||
#endif
|
||||
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
|
||||
per active UDP "connection". */
|
||||
#ifndef MEMP_NUM_UDP_PCB
|
||||
#define MEMP_NUM_UDP_PCB 6
|
||||
#endif
|
||||
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
|
||||
connections. */
|
||||
#ifndef MEMP_NUM_TCP_PCB
|
||||
#define MEMP_NUM_TCP_PCB 10
|
||||
#endif
|
||||
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
|
||||
connections. */
|
||||
#ifndef MEMP_NUM_TCP_PCB_LISTEN
|
||||
#define MEMP_NUM_TCP_PCB_LISTEN 6
|
||||
#endif
|
||||
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
|
||||
segments. */
|
||||
#ifndef MEMP_NUM_TCP_SEG
|
||||
#define MEMP_NUM_TCP_SEG 22
|
||||
#endif
|
||||
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
|
||||
timeouts. */
|
||||
#ifndef MEMP_NUM_SYS_TIMEOUT
|
||||
#define MEMP_NUM_SYS_TIMEOUT 10
|
||||
#endif
|
||||
|
||||
/* ---------- Pbuf options ---------- */
|
||||
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
|
||||
#ifndef PBUF_POOL_SIZE
|
||||
#define PBUF_POOL_SIZE 5
|
||||
#endif
|
||||
|
||||
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
|
||||
/* Default value is defined in lwip\src\include\lwip\opt.h as
|
||||
* LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)*/
|
||||
|
||||
#endif
|
||||
49
pico-sensor/src/main.c
Normal file
49
pico-sensor/src/main.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "McuLib.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuWait.h"
|
||||
#include <stdio.h>
|
||||
#include "application.h"
|
||||
#include "McuShell.h"
|
||||
#include "McuRTT.h"
|
||||
#include "McuSemihost.h"
|
||||
#include "McuLog.h"
|
||||
#if PL_CONFIG_USE_GCOV
|
||||
#include "McuCoverage.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GPROF
|
||||
#include "gprof_support.h"
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
PL_Init();
|
||||
vTaskStartScheduler();
|
||||
// GCOVR_EXCL_START
|
||||
#if PL_CONFIG_USE_GCOV
|
||||
McuCoverage_WriteFiles(); /* write coverage data files */
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GPROF
|
||||
profile_write_data_file();
|
||||
#endif
|
||||
|
||||
#if 0 && McuSemihost_CONFIG_IS_ENABLED
|
||||
/* not using any RTOS or queues after scheduler has stopped! */
|
||||
McuSemihost_WriteString0("exit with semihosting\n");
|
||||
McuWait_Waitms(1); /* give output some time */
|
||||
McuSemihost_SysException(McuSemihost_ADP_Stopped_ApplicationExit);
|
||||
#endif
|
||||
McuRTT_WriteString(0, "Stopping JRun with stop command\n");
|
||||
McuWait_Waitms(1); /* give output some time */
|
||||
McuRTT_WriteString(0, "*STOP*\n"); /* stop JRun */
|
||||
for(;;) {
|
||||
__asm("nop"); /* do not leave main() */
|
||||
}
|
||||
// GCOVR_EXCL_STOP
|
||||
return 0;
|
||||
}
|
||||
1480
pico-sensor/src/mqtt.c
Normal file
1480
pico-sensor/src/mqtt.c
Normal file
File diff suppressed because it is too large
Load Diff
613
pico-sensor/src/mqtt_client.c
Normal file
613
pico-sensor/src/mqtt_client.c
Normal file
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Useful read: https://github.com/particle-iot/lwip/blob/master/doc/mqtt_client.txt
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "lwip/apps/mqtt.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "dns_resolver.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuRTOS.h"
|
||||
#if PL_CONFIG_USE_MINI
|
||||
#include "minIni/McuMinINI.h"
|
||||
#include "MinIniKeys.h"
|
||||
#endif
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
#include "Modbus/McuHeidelberg.h"
|
||||
#endif
|
||||
|
||||
#if LWIP_TCP
|
||||
|
||||
#define MQTT_EXTRA_LOGS (0) /* set to 1 to produce extra log output */
|
||||
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
/* HomeAssistant Tesla Powerwall topics */
|
||||
#define TOPIC_NAME_SOLAR_POWER "homeassistant/sensor/powerwall_solar_now/state"
|
||||
#define TOPIC_NAME_SITE_POWER "homeassistant/sensor/powerwall_load_now/state"
|
||||
#define TOPIC_NAME_GRID_POWER "homeassistant/sensor/powerwall_site_now/state"
|
||||
#define TOPIC_NAME_BATTERY_POWER "homeassistant/sensor/powerwall_battery_now/state"
|
||||
#define TOPIC_NAME_BATTERY_PERCENTAGE "homeassistant/sensor/powerwall_charge/state"
|
||||
#define TOPIC_NAME_CHARGER_CHARGING_POWER "home/charger/power"
|
||||
#elif MQTT_CLIENT_IS_SENSOR
|
||||
#define TOPIC_NAME_SENSORS_UPDATE "sylvan/Home/PicoSensor/update" /*<user>/<room>/<device>/update*/
|
||||
#endif
|
||||
|
||||
typedef enum topic_ID_e {
|
||||
Topic_ID_None,
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
Topic_ID_Solar_Power, /* power from PV panels */
|
||||
Topic_ID_Site_Power, /* power to the house/site */
|
||||
Topic_ID_Grid_Power, /* power from/to grid */
|
||||
Topic_ID_Battery_Power, /* power from/to battery */
|
||||
Topic_ID_Battery_Percentage,/* battery level percentage */
|
||||
Topic_ID_Charging_Power, /* actual charging power */
|
||||
#elif MQTT_CLIENT_IS_SENSOR
|
||||
Topic_ID_Sensor_Update,
|
||||
#endif
|
||||
} topic_ID_e;
|
||||
|
||||
/* default entries for the MQTT broker connection */
|
||||
#define MQTT_DEFAULT_BROKER "homeassistant"
|
||||
#define MQTT_DEFAULT_CLIENT "client"
|
||||
#define MQTT_DEFAULT_USER "user"
|
||||
#define MQTT_DEFAULT_PASS "password"
|
||||
#define MQTT_DEFAULT_PUBLISH true
|
||||
|
||||
typedef struct mqtt_t {
|
||||
mqtt_client_t *mqtt_client; /* lwIP MQTT client handle */
|
||||
DnsResolver_info_t addr; /* broker lwip address, resolved by DNS if hostname is used */
|
||||
unsigned char broker[32]; /* broker IP or hostname string. For hostname, DNS will be used */
|
||||
unsigned char client_id[32]; /* client ID used for connection: each client should have a unique ID */
|
||||
unsigned char client_user[32]; /* client user name used for connection */
|
||||
unsigned char client_pass[96]; /* client user password */
|
||||
topic_ID_e in_pub_ID; /* incoming published ID, set in the incoming_publish_cb and used in the incoming_data_cb */
|
||||
/* configuration settings */
|
||||
bool doLogging; /* if it shall write log messages */
|
||||
bool doPublishing; /* if it publish messages */
|
||||
} mqtt_t;
|
||||
|
||||
static mqtt_t mqtt; /* information used for MQTT connection */
|
||||
|
||||
static const struct mqtt_connect_client_info_t mqtt_client_info = {
|
||||
mqtt.client_id, /* client ID */
|
||||
mqtt.client_user, /* client user name */
|
||||
mqtt.client_pass, /* client password */
|
||||
100, /* keep alive timeout in seconds */
|
||||
NULL, /* will_topic */
|
||||
NULL, /* will_msg */
|
||||
0, /* will_qos */
|
||||
0 /* will_retain */
|
||||
#if LWIP_ALTCP && LWIP_ALTCP_TLS
|
||||
, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static void mqtt_publish_request_cb(void *arg, err_t err) {
|
||||
#if 0 && MQTT_EXTRA_LOGS
|
||||
const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg;
|
||||
McuLog_trace("MQTT client \"%s\" publish request cb: err %d", client_info->client_id, (int)err);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MQTT_CLIENT_IS_SENSOR
|
||||
int MqttClient_Publish_SensorValues(float temperature, float humidity) {
|
||||
err_t res;
|
||||
uint8_t buf[64];
|
||||
const uint8_t qos = 0; /* quos: 0: fire&forget, 1: at least once */
|
||||
const uint8_t retain = 0;
|
||||
|
||||
if (!MqttClient_GetDoPublish()) {
|
||||
return ERR_DISABLED;
|
||||
}
|
||||
|
||||
if (mqtt.mqtt_client != NULL) { /* connected? */
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("publish t:%f h:%f", temperature, humidity);
|
||||
}
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"{\"values\": {\"temperature\": ");
|
||||
McuUtility_strcatNumFloat(buf, sizeof(buf), temperature, 2);
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", \"humidity\": ");
|
||||
McuUtility_strcatNumFloat(buf, sizeof(buf), humidity, 2);
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"}}");
|
||||
|
||||
res = mqtt_publish(mqtt.mqtt_client, TOPIC_NAME_SENSORS_UPDATE, buf, strlen(buf), qos, retain, mqtt_publish_request_cb, NULL);
|
||||
if (res != ERR_OK) {
|
||||
McuLog_error("Failed sensor values mqtt_publish: %d", res);
|
||||
(void)MqttClient_Disconnect(); /* try disconnect and connect again */
|
||||
(void)MqttClient_Connect();
|
||||
return res;
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
int MqttClient_Publish_ChargingPower(uint32_t powerW) {
|
||||
err_t res;
|
||||
uint8_t buf[64];
|
||||
const uint8_t qos = 0; /* quos: 0: fire&forget, 1: at least once */
|
||||
const uint8_t retain = 0;
|
||||
|
||||
if (!MqttClient_GetDoPublish()) {
|
||||
return ERR_DISABLED;
|
||||
}
|
||||
|
||||
if (mqtt.mqtt_client!=NULL) { /* connected? */
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("publish P: %d W", powerW);
|
||||
}
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"{\"chargeP\": ");
|
||||
McuUtility_strcatNum32u(buf, sizeof(buf), powerW);
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", \"unit\": \"W\"}");
|
||||
res = mqtt_publish(mqtt.mqtt_client, TOPIC_NAME_CHARGER_CHARGING_POWER, buf, strlen(buf), qos, retain, mqtt_publish_request_cb, NULL);
|
||||
if (res!=ERR_OK) {
|
||||
McuLog_error("Failed charging power mqtt_publish: %d", res);
|
||||
(void)MqttClient_Disconnect(); /* try disconnect and connect again */
|
||||
(void)MqttClient_Connect();
|
||||
return res;
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool MqttClient_GetDoPublish(void) {
|
||||
return mqtt.doPublishing && mqtt.mqtt_client!=NULL;
|
||||
}
|
||||
|
||||
void MqttClient_SetDoPublish(bool publish) {
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_putl(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PUBLISH, publish, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
mqtt.doPublishing = publish;
|
||||
}
|
||||
|
||||
int MqttClient_Publish(const unsigned char *topic, const unsigned char *value) {
|
||||
err_t res;
|
||||
uint8_t buf[64];
|
||||
const uint8_t qos = 0; /* quos: 0: fire&forget, 1: at least once */
|
||||
const uint8_t retain = 0;
|
||||
|
||||
if (!MqttClient_GetDoPublish()) {
|
||||
return ERR_DISABLED;
|
||||
}
|
||||
|
||||
if (mqtt.mqtt_client!=NULL) { /* connected? */
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("publish topic: \"%s\" value: \"%s\"", topic, value);
|
||||
}
|
||||
res = mqtt_publish(mqtt.mqtt_client, topic, value, strlen(value), qos, retain, mqtt_publish_request_cb, NULL);
|
||||
if (res!=ERR_OK) {
|
||||
McuLog_error("Failed mqtt_publish: %d", res);
|
||||
(void)MqttClient_Disconnect(); /* try disconnect and connect again */
|
||||
(void)MqttClient_Connect();
|
||||
return res;
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static void GetDataString(unsigned char *buf, size_t bufSize, const u8_t *data, u16_t len) {
|
||||
buf[0] = '\0';
|
||||
for(int i=0; i<len; i++){
|
||||
McuUtility_chcat(buf, bufSize, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
static int32_t scanWattValue(const unsigned char *str) {
|
||||
/* string in in kW and it returns the number in Watt, so for example:
|
||||
* "1" => 1000, * "1.2" => 1200, "3.025" = 3025, "-1.002" = -1002
|
||||
*/
|
||||
int32_t watt;
|
||||
float f;
|
||||
|
||||
if (sscanf(str, "%f", &f)!=1) { /* check number of conversions, shall be 1 */
|
||||
McuLog_error("failed conversion of %s", str);
|
||||
return 0; /* conversion failed, return 0 */
|
||||
}
|
||||
watt = (int)(f*1000.0f);
|
||||
return watt;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) {
|
||||
const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg;
|
||||
LWIP_UNUSED_ARG(data);
|
||||
unsigned char buf[32];
|
||||
int32_t watt;
|
||||
|
||||
#if MQTT_EXTRA_LOGS
|
||||
McuLog_trace("MQTT client \"%s\" data cb: len %d, flags %d", client_info->client_id, (int)len, (int)flags);
|
||||
#endif
|
||||
if(flags & MQTT_DATA_FLAG_LAST) {
|
||||
/* Last fragment of payload received (or whole part if payload fits receive buffer. See MQTT_VAR_HEADER_BUFFER_LEN) */
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
if (mqtt.in_pub_ID == Topic_ID_Solar_Power) {
|
||||
GetDataString(buf, sizeof(buf), data, len);
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("solarP: %s kW", buf);
|
||||
}
|
||||
watt = scanWattValue(buf);
|
||||
if (watt>=0) { /* can only be positive */
|
||||
McuHeidelberg_SetSolarPowerWatt(watt);
|
||||
}
|
||||
} else if(mqtt.in_pub_ID == Topic_ID_Site_Power) {
|
||||
GetDataString(buf, sizeof(buf), data, len);
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("siteP: %s kW", buf);
|
||||
}
|
||||
watt = scanWattValue(buf);
|
||||
if (watt>=0) { /* can only be positive */
|
||||
McuHeidelberg_SetSitePowerWatt(watt);
|
||||
}
|
||||
} else if(mqtt.in_pub_ID == Topic_ID_Grid_Power) {
|
||||
GetDataString(buf, sizeof(buf), data, len);
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("gridP: %s kW", buf);
|
||||
}
|
||||
watt = scanWattValue(buf);
|
||||
McuHeidelberg_SetGridPowerWatt(watt);
|
||||
} else if(mqtt.in_pub_ID == Topic_ID_Battery_Power) {
|
||||
GetDataString(buf, sizeof(buf), data, len);
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("battP: %s, kW", buf);
|
||||
}
|
||||
} else if(mqtt.in_pub_ID == Topic_ID_Battery_Percentage) {
|
||||
GetDataString(buf, sizeof(buf), data, len);
|
||||
if (mqtt.doLogging) {
|
||||
McuLog_trace("bat%%: %s%%", buf);
|
||||
}
|
||||
#elif MQTT_CLIENT_IS_SENSOR
|
||||
if (mqtt.in_pub_ID == Topic_ID_Sensor_Update) {
|
||||
McuLog_trace("Sensor update");
|
||||
#endif
|
||||
} else {
|
||||
McuLog_trace("mqtt_incoming_data_cb: Ignoring payload...");
|
||||
}
|
||||
} else {
|
||||
McuLog_trace("mqtt_incoming_data_cb: fragmented payload ...");
|
||||
/* Handle fragmented payload, store in buffer, write to file or whatever */
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) {
|
||||
const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg;
|
||||
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
if (McuUtility_strcmp(topic, TOPIC_NAME_SOLAR_POWER)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Solar_Power;
|
||||
} else if (McuUtility_strcmp(topic, TOPIC_NAME_SITE_POWER)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Site_Power;
|
||||
} else if (McuUtility_strcmp(topic, TOPIC_NAME_GRID_POWER)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Grid_Power;
|
||||
} else if (McuUtility_strcmp(topic, TOPIC_NAME_BATTERY_POWER)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Battery_Power;
|
||||
} else if (McuUtility_strcmp(topic, TOPIC_NAME_BATTERY_PERCENTAGE)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Battery_Percentage;
|
||||
} else if (McuUtility_strcmp(topic, TOPIC_NAME_CHARGER_CHARGING_POWER)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Charging_Power;
|
||||
#elif MQTT_CLIENT_IS_SENSOR
|
||||
if (McuUtility_strcmp(topic, TOPIC_NAME_SENSORS_UPDATE)==0) {
|
||||
mqtt.in_pub_ID = Topic_ID_Sensor_Update;
|
||||
#endif
|
||||
} else { /* unknown */
|
||||
McuLog_trace("MQTT client \"%s\" publish cb: topic %s, len %d", client_info->client_id, topic, (int)tot_len);
|
||||
mqtt.in_pub_ID = Topic_ID_None;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_request_cb(void *arg, err_t err) {
|
||||
#if MQTT_EXTRA_LOGS
|
||||
const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg;
|
||||
McuLog_trace("MQTT client \"%s\" request cb: err %d", client_info->client_id, (int)err);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) {
|
||||
const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg;
|
||||
LWIP_UNUSED_ARG(client);
|
||||
err_t err;
|
||||
|
||||
#if MQTT_EXTRA_LOGS
|
||||
McuLog_trace("MQTT client \"%s\" connection cb: status %d", client_info->client_id, (int)status);
|
||||
#endif
|
||||
if (status!=MQTT_CONNECT_ACCEPTED) {
|
||||
McuLog_error("MQTT client \"%s\" connection cb: FAILED status %d", client_info->client_id, (int)status);
|
||||
}
|
||||
/* subscribe to topics */
|
||||
if (status == MQTT_CONNECT_ACCEPTED) {
|
||||
McuLog_trace("MQTT connect accepted");
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
err = mqtt_sub_unsub(client,
|
||||
TOPIC_NAME_SOLAR_POWER, /* solar P in kW */
|
||||
1, /* quos: 0: fire&forget, 1: at least once */
|
||||
mqtt_request_cb, /* callback */
|
||||
LWIP_CONST_CAST(void*, client_info),
|
||||
1 /* subscribe */
|
||||
);
|
||||
if (err!=ERR_OK) {
|
||||
McuLog_error("failed subscribing, err %d", err);
|
||||
}
|
||||
err = mqtt_sub_unsub(client,
|
||||
TOPIC_NAME_SITE_POWER, /* site/house P in kW */
|
||||
1, /* quos */
|
||||
mqtt_request_cb,
|
||||
LWIP_CONST_CAST(void*, client_info),
|
||||
1);
|
||||
if (err!=ERR_OK) {
|
||||
McuLog_error("failed subscribing, err %d", err);
|
||||
}
|
||||
err = mqtt_sub_unsub(client,
|
||||
TOPIC_NAME_GRID_POWER, /* grid P in kW */
|
||||
1, /* quos */
|
||||
mqtt_request_cb,
|
||||
LWIP_CONST_CAST(void*, client_info),
|
||||
1);
|
||||
if (err!=ERR_OK) {
|
||||
McuLog_error("failed subscribing, err %d", err);
|
||||
}
|
||||
err = mqtt_sub_unsub(client,
|
||||
TOPIC_NAME_BATTERY_POWER, /* battery P in kW */
|
||||
1, /* quos */
|
||||
mqtt_request_cb,
|
||||
LWIP_CONST_CAST(void*, client_info),
|
||||
1);
|
||||
if (err!=ERR_OK) {
|
||||
McuLog_error("failed subscribing, err %d", err);
|
||||
}
|
||||
err = mqtt_sub_unsub(client,
|
||||
TOPIC_NAME_BATTERY_PERCENTAGE, /* topic: percentage of battery charge */
|
||||
1, /* quos */
|
||||
mqtt_request_cb, LWIP_CONST_CAST(void*, client_info),
|
||||
1);
|
||||
if (err!=ERR_OK) {
|
||||
McuLog_error("failed subscribing, err %d", err);
|
||||
}
|
||||
#elif MQTT_CLIENT_IS_SENSOR
|
||||
/* no subscriptions */
|
||||
#endif
|
||||
} else if (status==MQTT_CONNECT_DISCONNECTED) {
|
||||
McuLog_trace("MQTT connect disconnect");
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
uint8_t MqttClient_Connect(void) {
|
||||
#if LWIP_TCP
|
||||
int nofRetry;
|
||||
mqtt.mqtt_client = mqtt_client_new(); /* create client handle */
|
||||
err_t err;
|
||||
|
||||
if (mqtt.mqtt_client==NULL) {
|
||||
McuLog_fatal("new mqtt client is NULL");
|
||||
}
|
||||
|
||||
/* setup connection information */
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_BROKER, MQTT_DEFAULT_BROKER, mqtt.broker, sizeof(mqtt.broker), NVMC_MININI_FILE_NAME);
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_CLIENT, MQTT_DEFAULT_CLIENT, mqtt.client_id, sizeof(mqtt.client_id), NVMC_MININI_FILE_NAME);
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_USER, MQTT_DEFAULT_USER, mqtt.client_user, sizeof(mqtt.client_user), NVMC_MININI_FILE_NAME);
|
||||
McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PASS, MQTT_DEFAULT_PASS, mqtt.client_pass, sizeof(mqtt.client_pass), NVMC_MININI_FILE_NAME);
|
||||
mqtt.doPublishing = McuMinINI_ini_getbool(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PASS, MQTT_DEFAULT_PUBLISH, NVMC_MININI_FILE_NAME);
|
||||
#else
|
||||
McuUtility_strcpy(mqtt.broker, sizeof(mqtt.broker), MQTT_DEFAULT_BROKER);
|
||||
McuUtility_strcpy(mqtt.client_id, sizeof(mqtt.client_id), MQTT_DEFAULT_CLIENT);
|
||||
McuUtility_strcpy(mqtt.client_user, sizeof(mqtt.client_user), MQTT_DEFAULT_USER);
|
||||
McuUtility_strcpy(mqtt.client_pass, sizeof(mqtt.client_pass), MQTT_DEFAULT_PASS);
|
||||
mqtt.doPublishing = MQTT_DEFAULT_PUBLISH;
|
||||
#endif
|
||||
|
||||
/* resolve host name to IP address: */
|
||||
for (nofRetry=60; nofRetry>=0; nofRetry--) {
|
||||
if (DnsResolver_ResolveName(mqtt.broker, &mqtt.addr, 5*1000)!=0) { /* use DNS to resolve name to IP address */
|
||||
McuLog_error("failed to resolve broker name %s, retry ...", mqtt.broker);
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
} else {
|
||||
break; /* success! leaving loop */
|
||||
}
|
||||
}
|
||||
if (nofRetry<0) {
|
||||
McuLog_fatal("failed to resolve broker name %s, giving up", mqtt.broker);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
/* setup callbacks for incoming data: */
|
||||
mqtt_set_inpub_callback(
|
||||
mqtt.mqtt_client, /* client handle */
|
||||
mqtt_incoming_publish_cb, /* callback for incoming publish messages */
|
||||
mqtt_incoming_data_cb, /* callback for incoming data */
|
||||
LWIP_CONST_CAST(void*, &mqtt_client_info) /* argument for callbacks */
|
||||
);
|
||||
/* connect to broker */
|
||||
cyw43_arch_lwip_begin(); /* start section for to lwIP access */
|
||||
err = mqtt_client_connect(
|
||||
mqtt.mqtt_client, /* client handle */
|
||||
&mqtt.addr.resolved_addr, /* broker IP address */
|
||||
MQTT_PORT, /* port to be used */
|
||||
mqtt_connection_cb, LWIP_CONST_CAST(void*, &mqtt_client_info), /* connection callback with argument */
|
||||
&mqtt_client_info /* client information */
|
||||
);
|
||||
cyw43_arch_lwip_end(); /* end section accessing lwIP */
|
||||
if (err!=ERR_OK) {
|
||||
McuLog_error("failed connecting client to server");
|
||||
} else {
|
||||
McuLog_trace("client connecting");
|
||||
}
|
||||
return err;
|
||||
#else
|
||||
return ERR_FAILED;
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
uint8_t MqttClient_Disconnect(void) {
|
||||
if (mqtt.mqtt_client!=NULL) {
|
||||
McuLog_trace("disconnecting client");
|
||||
cyw43_arch_lwip_begin(); /* start section for to lwIP access */
|
||||
mqtt_disconnect(mqtt.mqtt_client);
|
||||
mqtt_client_free(mqtt.mqtt_client);
|
||||
cyw43_arch_lwip_end(); /* end section accessing lwIP */
|
||||
mqtt.mqtt_client = NULL;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t SetBroker(const unsigned char *broker) {
|
||||
unsigned char buf[64];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&broker, buf, sizeof(buf));
|
||||
McuUtility_strcpy(mqtt.broker, sizeof(mqtt.broker), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_BROKER, mqtt.broker, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t SetID(const unsigned char *id) {
|
||||
unsigned char buf[64];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&id, buf, sizeof(buf));
|
||||
McuUtility_strcpy(mqtt.client_id, sizeof(mqtt.client_id), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_CLIENT, mqtt.client_id, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t SetUser(const unsigned char *user) {
|
||||
unsigned char buf[64];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&user, buf, sizeof(buf));
|
||||
McuUtility_strcpy(mqtt.client_user, sizeof(mqtt.client_user), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_USER, mqtt.client_user, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t SetPassword(const unsigned char *pass) {
|
||||
unsigned char buf[96];
|
||||
|
||||
McuUtility_ScanDoubleQuotedString(&pass, buf, sizeof(buf));
|
||||
McuUtility_strcpy(mqtt.client_pass, sizeof(mqtt.client_pass), buf);
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PASS, mqtt.client_pass, NVMC_MININI_FILE_NAME);
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
||||
McuShell_SendStatusStr((unsigned char*)"mqttclient", (unsigned char*)"mqttclient status\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" log", mqtt.doLogging?(unsigned char*)"on\r\n":(unsigned char*)"off\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" publish", MqttClient_GetDoPublish()?(unsigned char*)"on\r\n":(unsigned char*)"off\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" client", mqtt.mqtt_client==NULL?(unsigned char*)"diconnected\r\n":(unsigned char*)"connected\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" broker", mqtt.broker, io->stdOut);
|
||||
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" client ID", mqtt.client_id, io->stdOut);
|
||||
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" client user", mqtt.client_user, io->stdOut);
|
||||
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" client password", mqtt.client_pass, io->stdOut);
|
||||
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"mqttclient", (unsigned char*)"Group of mqttclient commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" log on|off", (unsigned char*)"Turn logging on or off\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" publish on|off", (unsigned char*)"Publishing on or off\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" connect|disconnect", (unsigned char*)"Connect or disconnect from server\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set broker \"<broker>\"", (unsigned char*)"Set broker name\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set id \"<id>\"", (unsigned char*)"Set client ID\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set user \"<user>\"", (unsigned char*)"Set client user name\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" set pass \"<password>\"", (unsigned char*)"Set client password\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" pub \"<topic>\" \"<txt>\"", (unsigned char*)"Publish text to a topic\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t MqttClient_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
const unsigned char *p;
|
||||
uint16_t val16u;
|
||||
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "mqttclient help")==0) {
|
||||
*handled = true;
|
||||
return PrintHelp(io);
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "mqttclient status")==0)) {
|
||||
*handled = true;
|
||||
return PrintStatus(io);
|
||||
} else if (McuUtility_strcmp((char*)cmd, "mqttclient log on")==0) {
|
||||
*handled = true;
|
||||
mqtt.doLogging = true;
|
||||
} else if (McuUtility_strcmp((char*)cmd, "mqttclient log off")==0) {
|
||||
*handled = true;
|
||||
mqtt.doLogging = false;
|
||||
} else if (McuUtility_strcmp((char*)cmd, "mqttclient publish on")==0) {
|
||||
*handled = true;
|
||||
MqttClient_SetDoPublish(true);
|
||||
} else if (McuUtility_strcmp((char*)cmd, "mqttclient publish off")==0) {
|
||||
*handled = true;
|
||||
MqttClient_SetDoPublish(false);
|
||||
} else if (McuUtility_strcmp((char*)cmd, "mqttclient connect")==0) {
|
||||
*handled = true;
|
||||
MqttClient_Connect();
|
||||
} else if (McuUtility_strcmp((char*)cmd, "mqttclient disconnect")==0) {
|
||||
*handled = true;
|
||||
MqttClient_Disconnect();
|
||||
} else if (McuUtility_strncmp((char*)cmd, "mqttclient set broker ", sizeof("mqttclient set broker ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("mqttclient set broker ")-1;
|
||||
return SetBroker(p);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "mqttclient set id ", sizeof("mqttclient set id ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("mqttclient set id ")-1;
|
||||
return SetID(p);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "mqttclient set user ", sizeof("mqttclient set user ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("mqttclient set user ")-1;
|
||||
return SetUser(p);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "mqttclient set pass ", sizeof("mqttclient set pass ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("mqttclient set pass ")-1;
|
||||
return SetPassword(p);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "mqttclient pub ", sizeof("mqttclient pub ")-1)==0) {
|
||||
unsigned char topic[128], text[128];
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("mqttclient pub ")-1;
|
||||
if (McuUtility_ScanDoubleQuotedString(&p, topic, sizeof(topic))!=ERR_OK) {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
McuUtility_SkipSpaces(&p);
|
||||
if (McuUtility_ScanDoubleQuotedString(&p, text, sizeof(text))!=ERR_OK) {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
return MqttClient_Publish(topic, text);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void MqttClient_Deinit(void) {
|
||||
MqttClient_Disconnect();
|
||||
}
|
||||
|
||||
void MqttClient_Init(void) {
|
||||
mqtt.doLogging = true;
|
||||
mqtt.doPublishing = MQTT_DEFAULT_PUBLISH;
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_MQTT_CLIENT */
|
||||
77
pico-sensor/src/mqtt_client.h
Normal file
77
pico-sensor/src/mqtt_client.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SRC_MQTT_CLIENT_H_
|
||||
#define SRC_MQTT_CLIENT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* which topics to use: choose only one: */
|
||||
#define MQTT_CLIENT_IS_EV_CHARGER (0)
|
||||
#define MQTT_CLIENT_IS_SENSOR (1)
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
|
||||
/*!
|
||||
* \brief Command line and shell handler
|
||||
* \param cmd The command to be parsed
|
||||
* \param handled If command has been recognized and handled
|
||||
* \param io I/O handler to be used
|
||||
* \return error code, otherwise ERR_OK
|
||||
*/
|
||||
uint8_t MqttClient_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
#if MQTT_CLIENT_IS_SENSOR
|
||||
int MqttClient_Publish_SensorValues(float temperature, float humidity);
|
||||
#endif
|
||||
|
||||
#if MQTT_CLIENT_IS_EV_CHARGER
|
||||
int MqttClient_Publish_ChargingPower(uint32_t powerW);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Connect as client to the server
|
||||
* \return error code, otherwise ERR_OK
|
||||
*/
|
||||
uint8_t MqttClient_Connect(void);
|
||||
|
||||
/*!
|
||||
* \brief Disconnect from the server
|
||||
* \return error code, otherwise ERR_OK
|
||||
*/
|
||||
uint8_t MqttClient_Disconnect(void);
|
||||
|
||||
/*!
|
||||
* \brief Decides if client is set to publish or not
|
||||
* \return true if client is publishing, false otherwise
|
||||
*/
|
||||
bool MqttClient_GetDoPublish(void);
|
||||
|
||||
/*!
|
||||
* \brief Sets if the client is publishing or not
|
||||
* \param publish true to publish, false otherwise
|
||||
*/
|
||||
void MqttClient_SetDoPublish(bool publish);
|
||||
|
||||
/*!
|
||||
* \brief Module de-initialization
|
||||
*/
|
||||
void MqttClient_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Module initialization
|
||||
*/
|
||||
void MqttClient_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SRC_MQTT_CLIENT_H_ */
|
||||
242
pico-sensor/src/ntp_client.c
Normal file
242
pico-sensor/src/ntp_client.c
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuTimeDate.h"
|
||||
#include "dns_resolver.h"
|
||||
#include "ntp_client.h"
|
||||
#if PL_CONFIG_USE_MINI
|
||||
#include "minIni/McuMinINI.h"
|
||||
#include "MinIniKeys.h"
|
||||
#endif
|
||||
|
||||
static TaskHandle_t taskHandle; /* task handle of ntp task */
|
||||
|
||||
typedef struct ntp_desc_t {
|
||||
DnsResolver_info_t addr; /* DNS resolved address information of DNS server */
|
||||
struct udp_pcb *ntp_pcb; /* UDP protocol block */
|
||||
alarm_id_t ntp_timeout_alarm; /* timeout alarm id, zero if no timeout is running */
|
||||
} ntp_desc_t;
|
||||
|
||||
#define NTP_SERVER "pool.ntp.org" /* ntp server name */
|
||||
#define NTP_MSG_LEN 48
|
||||
#define NTP_PORT 123 /* ntp udp port number */
|
||||
#define NTP_DELTA 2208988800 /* seconds between 1 Jan 1900 and 1 Jan 1970 */
|
||||
#define NTP_PERIOD_TIME_MS (30*60*1000) /* period in ms between ntp requests */
|
||||
#define NTP_TIMEOUT_TIME_MS (10*1000) /* timeout time in ms if there is no ntp response */
|
||||
|
||||
static unsigned int AddDaylightSavingHourOffset(uint8_t day, uint8_t month) {
|
||||
return 2; /* \todo */
|
||||
}
|
||||
|
||||
/* Called with results of operation */
|
||||
static void ntp_result(ntp_desc_t *state, int status, time_t *result) {
|
||||
if (status == 0 && result!=NULL) {
|
||||
struct tm *utc = gmtime(result);
|
||||
McuLog_info("got ntp response: %02d/%02d/%04d %02d:%02d:%02d",
|
||||
utc->tm_mday, utc->tm_mon + 1, utc->tm_year + 1900,
|
||||
utc->tm_hour, utc->tm_min, utc->tm_sec);
|
||||
McuTimeDate_SetDate(utc->tm_year+1900, utc->tm_mon+1, utc->tm_mday);
|
||||
McuTimeDate_SetTime(utc->tm_hour+AddDaylightSavingHourOffset(utc->tm_mday, utc->tm_mday), utc->tm_min, utc->tm_sec, 0);
|
||||
}
|
||||
if (state->ntp_timeout_alarm > 0) { /* cancel timeout pending alarm, as we have received a response */
|
||||
cancel_alarm(state->ntp_timeout_alarm);
|
||||
state->ntp_timeout_alarm = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* send an UDP NTP request message */
|
||||
static void ntp_request(ntp_desc_t *state) {
|
||||
// cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
|
||||
// You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
|
||||
// these calls are a no-op and can be omitted, but it is a good practice to use them in
|
||||
// case you switch the cyw43_arch type later.
|
||||
cyw43_arch_lwip_begin();
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM);
|
||||
uint8_t *req = (uint8_t *)p->payload;
|
||||
memset(req, 0, NTP_MSG_LEN);
|
||||
req[0] = 0x1b;
|
||||
udp_sendto(state->ntp_pcb, p, &state->addr.resolved_addr, NTP_PORT);
|
||||
pbuf_free(p);
|
||||
cyw43_arch_lwip_end();
|
||||
}
|
||||
|
||||
/* alarm callback handler */
|
||||
static int64_t ntp_timeout_handler(alarm_id_t id, void *user_data) {
|
||||
ntp_desc_t *state = (ntp_desc_t*)user_data;
|
||||
McuLog_error("ntp request timeout");
|
||||
ntp_result(state, -1, NULL); /* abort */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* lwIP callback for NTP data received */
|
||||
static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
|
||||
ntp_desc_t *state = (ntp_desc_t*)arg;
|
||||
uint8_t mode = pbuf_get_at(p, 0) & 0x7;
|
||||
uint8_t stratum = pbuf_get_at(p, 1);
|
||||
|
||||
/* Check the result */
|
||||
if (ip_addr_cmp(addr, &state->addr.resolved_addr) && port == NTP_PORT && p->tot_len == NTP_MSG_LEN && mode == 0x4 && stratum != 0) {
|
||||
uint8_t seconds_buf[4] = {0};
|
||||
pbuf_copy_partial(p, seconds_buf, sizeof(seconds_buf), 40);
|
||||
uint32_t seconds_since_1900 = seconds_buf[0] << 24 | seconds_buf[1] << 16 | seconds_buf[2] << 8 | seconds_buf[3];
|
||||
uint32_t seconds_since_1970 = seconds_since_1900 - NTP_DELTA;
|
||||
time_t epoch = seconds_since_1970;
|
||||
ntp_result(state, 0, &epoch);
|
||||
} else {
|
||||
McuLog_error("invalid ntp response");
|
||||
ntp_result(state, -1, NULL); /* abort */
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
static int ntp_init(ntp_desc_t *ntp_state) {
|
||||
memset(ntp_state, 0, sizeof(ntp_desc_t));
|
||||
ntp_state->ntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); /* setup udp protocol block */
|
||||
if (!ntp_state->ntp_pcb) {
|
||||
McuLog_error("failed to create udp pcb");
|
||||
return -1; /* failed */
|
||||
}
|
||||
udp_recv(ntp_state->ntp_pcb, ntp_recv, ntp_state); /* set receive callback */
|
||||
return 0; /* ok */
|
||||
}
|
||||
|
||||
struct ntp {
|
||||
bool start; /* if task remains suspended after startup, stored in minINI */
|
||||
bool taskIsSuspended; /* if task is suspended or not */
|
||||
} ntp;
|
||||
|
||||
bool NtpClient_GetDefaultStart(void) {
|
||||
return ntp.start;
|
||||
}
|
||||
|
||||
static uint8_t SetDefaultStart(bool start) {
|
||||
#if PL_CONFIG_USE_MINI
|
||||
if (McuMinINI_ini_putl(NVMC_MININI_SECTION_NTP, NVMC_MININI_KEY_NTP_START, start, NVMC_MININI_FILE_NAME)!=1) { /* 1: success */
|
||||
return ERR_FAILED;
|
||||
}
|
||||
#endif
|
||||
ntp.start = start;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void ntpTask(void *pv) {
|
||||
ntp_desc_t ntp_state;
|
||||
|
||||
#define NTP_DEFAULT_START true
|
||||
#if PL_CONFIG_USE_MINI
|
||||
ntp.start = McuMinINI_ini_getbool(NVMC_MININI_SECTION_NTP, NVMC_MININI_KEY_NTP_START, NTP_DEFAULT_START, NVMC_MININI_FILE_NAME);
|
||||
#else
|
||||
ntp.start = NTP_DEFAULT_START;
|
||||
#endif
|
||||
ntp.taskIsSuspended = true;
|
||||
vTaskSuspend(NULL); /* will be resumed by WiFi task */
|
||||
if (ntp_init(&ntp_state)!=0) {
|
||||
McuLog_fatal("failed initializing ntp");
|
||||
for(;;) {
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
}
|
||||
/* resolve NTP server name */
|
||||
while (DnsResolver_ResolveName(NTP_SERVER, &ntp_state.addr, 5*1000)!=0) {
|
||||
McuLog_error("dns request for '%s' failed", NTP_SERVER);
|
||||
vTaskDelay(pdMS_TO_TICKS(30*1000));
|
||||
} /* retry until success */
|
||||
for(;;) {
|
||||
do {
|
||||
/* Set timeout alarm in case udp requests are lost */
|
||||
ntp_state.ntp_timeout_alarm = add_alarm_in_ms(NTP_TIMEOUT_TIME_MS, ntp_timeout_handler, &ntp_state, true);
|
||||
ntp_request(&ntp_state);
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); /* wait for response or timeout */
|
||||
} while (ntp_state.ntp_timeout_alarm>0); /* request still going on, timeout not expired? */
|
||||
} while (ntp_state.ntp_timeout_alarm>0); /* retry */
|
||||
vTaskDelay(pdMS_TO_TICKS(NTP_PERIOD_TIME_MS)); /* delay until next ntp request */
|
||||
}
|
||||
}
|
||||
|
||||
void NtpClient_TaskResume(void) {
|
||||
if (taskHandle!=NULL) {
|
||||
vTaskResume(taskHandle);
|
||||
ntp.taskIsSuspended = false;
|
||||
}
|
||||
}
|
||||
|
||||
void NtpClient_TaskSuspend(void) {
|
||||
if (taskHandle!=NULL) {
|
||||
vTaskSuspend(taskHandle);
|
||||
ntp.taskIsSuspended = true;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
||||
McuShell_SendStatusStr((unsigned char*)"ntpclient", (unsigned char*)"NTP client status\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" start", ntp.start?(unsigned char*)"true\r\n":(unsigned char*)"false\r\n", io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" suspended", ntp.taskIsSuspended?(unsigned char*)"true\r\n":(unsigned char*)"false\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"ntpclient", (unsigned char*)"Group of ntpclient commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" start yes|no", (unsigned char*)"If ntplient task shall start be default\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" suspend|resume", (unsigned char*)"Suspend or resume ntp client task\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t NtpClient_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
const unsigned char *p;
|
||||
uint16_t val16u;
|
||||
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "ntpclient help")==0) {
|
||||
*handled = true;
|
||||
return PrintHelp(io);
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "ntpclient status")==0)) {
|
||||
*handled = true;
|
||||
return PrintStatus(io);
|
||||
} else if (McuUtility_strcmp((char*)cmd, "ntpclient resume")==0) {
|
||||
*handled = true;
|
||||
NtpClient_TaskResume();
|
||||
} else if (McuUtility_strcmp((char*)cmd, "ntpclient suspend")==0) {
|
||||
*handled = true;
|
||||
NtpClient_TaskSuspend();
|
||||
} else if (McuUtility_strcmp((char*)cmd, "ntpclient start yes")==0) {
|
||||
*handled = true;
|
||||
return SetDefaultStart(true);
|
||||
} else if (McuUtility_strcmp((char*)cmd, "ntpclient start no")==0) {
|
||||
*handled = true;
|
||||
return SetDefaultStart(false);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void NtpClient_Init(void) {
|
||||
if (xTaskCreate(
|
||||
ntpTask, /* pointer to the task */
|
||||
"ntp", /* task name for kernel awareness debugging */
|
||||
4096/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+1, /* initial priority */
|
||||
&taskHandle /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("failed creating task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_NTP_CLIENT */
|
||||
52
pico-sensor/src/ntp_client.h
Normal file
52
pico-sensor/src/ntp_client.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SRC_NTP_CLIENT_H_
|
||||
#define SRC_NTP_CLIENT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
|
||||
/*!
|
||||
* \brief Command line and shell handler
|
||||
* \param cmd The command to be parsed
|
||||
* \param handled If command has been recognized and handled
|
||||
* \param io I/O handler to be used
|
||||
* \return error code, otherwise ERR_OK
|
||||
*/
|
||||
uint8_t NtpClient_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Decide if NTP client shall start by default.
|
||||
* \return true if it shall be started, false otherwise.
|
||||
*/
|
||||
bool NtpClient_GetDefaultStart(void);
|
||||
|
||||
/*!
|
||||
* \brief Suspend the NTP client task
|
||||
*/
|
||||
void NtpClient_TaskSuspend(void);
|
||||
|
||||
/*!
|
||||
* \brief Resume the NTP client task
|
||||
*/
|
||||
void NtpClient_TaskResume(void);
|
||||
|
||||
/*!
|
||||
* \brief Module initialization
|
||||
*/
|
||||
void NtpClient_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SRC_NTP_CLIENT_H_ */
|
||||
238
pico-sensor/src/nvmc.c
Normal file
238
pico-sensor/src/nvmc.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
#include "nvmc.h"
|
||||
#include <string.h>
|
||||
#if PL_CONFIG_USE_MININI
|
||||
#include "MinIni/McuMinINI.h"
|
||||
#endif
|
||||
#include "McuLib.h"
|
||||
#include "McuUtility.h"
|
||||
#include "shell.h"
|
||||
#include "McuLog.h"
|
||||
|
||||
#define NVMC_MININI_FILE_NAME "settings.ini" /* 'file' name used */
|
||||
|
||||
/* RS-485 bus settings */
|
||||
#define NVMC_MININI_SECTION_RS485 "rs485"
|
||||
#define NVMC_MININI_KEY_RS485_ADDR "addr" /* long value: RS-485 address */
|
||||
|
||||
/* application settings */
|
||||
#define NVMC_MININI_SECTION_APP "app"
|
||||
#define NVMC_MININI_KEY_APP_FLAGS "flags" /* long value: application flags */
|
||||
|
||||
/* motor settings */
|
||||
#define NVMC_MININI_SECTION_MOTOR "motor" /* motor0, motor1, ... */
|
||||
#define NVMC_MININI_KEY_MOTOR_ID "id" /* long value: stepper motor id/label */
|
||||
#define NVMC_MININI_KEY_MOTOR_OFFSET "offs" /* long value: stepper motor offset */
|
||||
#define NVMC_MININI_KEY_MOTOR_X "x" /* long value: x position of split-flap */
|
||||
#define NVMC_MININI_KEY_MOTOR_Y "y" /* long value: y position of split-flap */
|
||||
|
||||
uint8_t NVMC_GetRS485Addr(uint8_t *addr) {
|
||||
#if PL_CONFIG_USE_MININI
|
||||
*addr = McuMinINI_ini_getl(NVMC_MININI_SECTION_RS485, NVMC_MININI_KEY_RS485_ADDR, 0x1, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
*addr = 0x1;
|
||||
return ERR_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_SetRS485Addr(uint8_t addr) {
|
||||
#if PL_CONFIG_USE_MININI && McuMinINI_CONFIG_READ_ONLY
|
||||
return ERR_FAILED;
|
||||
#elif PL_CONFIG_USE_MININI
|
||||
McuMinINI_ini_putl(NVMC_MININI_SECTION_RS485, NVMC_MININI_KEY_RS485_ADDR, addr, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
return ERR_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_GetFlags(uint32_t *flags) {
|
||||
#if PL_CONFIG_USE_MININI
|
||||
*flags = McuMinINI_ini_getl(NVMC_MININI_SECTION_APP, NVMC_MININI_KEY_APP_FLAGS, 0x0, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
*flags = 0;
|
||||
return ERR_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_SetFlags(uint32_t flags) {
|
||||
#if PL_CONFIG_USE_MININI && McuMinINI_CONFIG_READ_ONLY
|
||||
return ERR_FAILED;
|
||||
#elif PL_CONFIG_USE_MININI
|
||||
McuMinINI_ini_putl(NVMC_MININI_SECTION_APP, NVMC_MININI_KEY_APP_FLAGS, flags, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
return ERR_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_MININI
|
||||
static void BuildStepperSectionName(unsigned char *sectionName, size_t nameSize, uint8_t motorIdx) {
|
||||
McuUtility_strcpy(sectionName, nameSize, (unsigned char*)NVMC_MININI_SECTION_MOTOR);
|
||||
McuUtility_strcatNum8u(sectionName, nameSize, motorIdx); /* append motor index to section name */
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t NVMC_GetStepperID(uint8_t motorIdx, int16_t *id) {
|
||||
#if PL_CONFIG_USE_MININI
|
||||
unsigned char sectionName[16];
|
||||
|
||||
BuildStepperSectionName(sectionName, sizeof(sectionName), motorIdx);
|
||||
*id = McuMinINI_ini_getl((char*)sectionName, NVMC_MININI_KEY_MOTOR_ID, -1, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
*id = -1;
|
||||
return ERR_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_SetStepperID(uint8_t motorIdx, uint16_t id) {
|
||||
#if PL_CONFIG_USE_MININI && McuMinINI_CONFIG_READ_ONLY
|
||||
return ERR_FAILED;
|
||||
#elif PL_CONFIG_USE_MININI
|
||||
unsigned char sectionName[16];
|
||||
|
||||
BuildStepperSectionName(sectionName, sizeof(sectionName), motorIdx);
|
||||
McuMinINI_ini_putl((char*)sectionName, NVMC_MININI_KEY_MOTOR_ID, id, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
return ERR_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_GetStepperPosition(uint8_t motorIdx, int16_t *xp, int16_t *yp) {
|
||||
#if PL_CONFIG_USE_MININI
|
||||
unsigned char sectionName[16];
|
||||
|
||||
BuildStepperSectionName(sectionName, sizeof(sectionName), motorIdx);
|
||||
*xp = McuMinINI_ini_getl((char*)sectionName, NVMC_MININI_KEY_MOTOR_X, -1, NVMC_MININI_FILE_NAME);
|
||||
*yp = McuMinINI_ini_getl((char*)sectionName, NVMC_MININI_KEY_MOTOR_Y, -1, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
*xp = 0;
|
||||
*yp = 0;
|
||||
return ERR_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_SetStepperPosition(uint8_t motorIdx, int16_t xPos, int16_t yPos) {
|
||||
#if PL_CONFIG_USE_MININI && McuMinINI_CONFIG_READ_ONLY
|
||||
return ERR_FAILED;
|
||||
#elif PL_CONFIG_USE_MININI
|
||||
unsigned char sectionName[16];
|
||||
|
||||
BuildStepperSectionName(sectionName, sizeof(sectionName), motorIdx);
|
||||
McuMinINI_ini_putl((char*)sectionName, NVMC_MININI_KEY_MOTOR_X, xPos, NVMC_MININI_FILE_NAME);
|
||||
McuMinINI_ini_putl((char*)sectionName, NVMC_MININI_KEY_MOTOR_Y, yPos, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
return ERR_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int16_t NVMC_GetStepperZeroOffset(uint8_t motorIdx) {
|
||||
#if PL_CONFIG_USE_MININI
|
||||
unsigned char sectionName[16];
|
||||
|
||||
BuildStepperSectionName(sectionName, sizeof(sectionName), motorIdx);
|
||||
return McuMinINI_ini_getl((char*)sectionName, NVMC_MININI_KEY_MOTOR_OFFSET, 0, NVMC_MININI_FILE_NAME);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t NVMC_SetStepperZeroOffset(uint8_t motorIdx, int16_t offset) {
|
||||
#if PL_CONFIG_USE_MININI && McuMinINI_CONFIG_READ_ONLY
|
||||
return ERR_FAILED;
|
||||
#elif PL_CONFIG_USE_MININI
|
||||
unsigned char sectionName[16];
|
||||
|
||||
BuildStepperSectionName(sectionName, sizeof(sectionName), motorIdx);
|
||||
McuMinINI_ini_putl((char*)sectionName, NVMC_MININI_KEY_MOTOR_OFFSET, offset, NVMC_MININI_FILE_NAME);
|
||||
return ERR_OK;
|
||||
#else
|
||||
return ERR_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
||||
uint8_t buf[64];
|
||||
uint8_t res, addr;
|
||||
uint32_t flags;
|
||||
|
||||
McuShell_SendStatusStr((unsigned char*)"nvmc", (unsigned char*)"Non-volatile memory configuration area\r\n", io->stdOut);
|
||||
|
||||
res = NVMC_GetRS485Addr(&addr);
|
||||
if (res==ERR_OK) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), addr);
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERROR\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((unsigned char*)" RS-485 addr", buf, io->stdOut);
|
||||
|
||||
res = NVMC_GetFlags(&flags);
|
||||
if (res==ERR_OK) {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
|
||||
McuUtility_strcatNum32Hex(buf, sizeof(buf), flags);
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" mag: ");
|
||||
if (flags&NVMC_FLAGS_MAGNET_ENABLED) {
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"1");
|
||||
} else {
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"0");
|
||||
}
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
} else {
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERROR\r\n");
|
||||
}
|
||||
McuShell_SendStatusStr((unsigned char*)" flags", buf, io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"nvmc", (unsigned char*)"Group of NVMC commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" flags <val>", (unsigned char*)"Set flags\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t NVMC_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "nvmc help")==0) {
|
||||
*handled = true;
|
||||
return PrintHelp(io);
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "nvmc status")==0)) {
|
||||
*handled = true;
|
||||
return PrintStatus(io);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "nvmc flags", sizeof("nvmc flags")-1)==0) {
|
||||
*handled = true;
|
||||
const unsigned char *p;
|
||||
int32_t val;
|
||||
|
||||
p = cmd + sizeof("nvmc flags ")-1;
|
||||
if (McuUtility_xatoi(&p, &val)==ERR_OK) {
|
||||
return NVMC_SetFlags((uint32_t)val);
|
||||
} else {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void NVMC_Deinit(void) {
|
||||
/* nothing needed */
|
||||
}
|
||||
|
||||
void NVMC_Init(void){
|
||||
/* nothing needed */
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_NVMC */
|
||||
106
pico-sensor/src/nvmc.h
Normal file
106
pico-sensor/src/nvmc.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NVMC_H_
|
||||
#define NVMC_H_
|
||||
|
||||
#include "platform.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "McuShell.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NVMC_FLAGS_MAGNET_ENABLED (1<<0) /* if magnets are enabled or not */
|
||||
|
||||
/*!
|
||||
* \brief Provide the id/label of the stepper motor
|
||||
* \param motorIdx Motor index
|
||||
* \param id Where the id gets stored
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_GetStepperID(uint8_t motorIdx, int16_t *id);
|
||||
/*!
|
||||
* \brief Set the id/label of the stepper motor
|
||||
* \param motorIdx Motor index
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_SetStepperID(uint8_t motorIdx, uint16_t id);
|
||||
|
||||
/*!
|
||||
* \brief Provide the offset from the magnet position for a stepper motor
|
||||
* \param motorIdx Motor index
|
||||
* \return Stored offset
|
||||
*/
|
||||
int16_t NVMC_GetStepperZeroOffset(uint8_t motorIdx);
|
||||
|
||||
/*!
|
||||
* \brief Store the offset from the magnet position for a stepper motor
|
||||
* \param motorIdx Motor index
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_SetStepperZeroOffset(uint8_t motorIdx, int16_t offset);
|
||||
|
||||
/*!
|
||||
* \brief Getter to get the RS-485 address
|
||||
* \param addr Where to store the address
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_GetRS485Addr(uint8_t *addr);
|
||||
|
||||
/*!
|
||||
* \brief Setter to set the RS-485 address.
|
||||
* \param addr Address to store
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_SetRS485Addr(uint8_t addr);
|
||||
|
||||
/*!
|
||||
* \brief Return for a given motor the character it is responsible for.
|
||||
* \param motorIdx Motor index number
|
||||
* \param xp Where to store the x coordinate, returns -1 for not attached motor
|
||||
* \param yp Where to store the y coordinate, returns -1 for not attached motor
|
||||
*/
|
||||
uint8_t NVMC_GetStepperPosition(uint8_t motorIdx, int16_t *xp, int16_t *yp);
|
||||
|
||||
/*!
|
||||
* \brief Set position for a given motor the character it is responsible for.
|
||||
* \param motorIdx Motor index number
|
||||
* \param xp Where to store the x coordinate, returns -1 for not attached motor
|
||||
* \param yp Where to store the y coordinate, returns -1 for not attached motor
|
||||
*/
|
||||
uint8_t NVMC_SetStepperPosition(uint8_t motorIdx, int16_t xPos, int16_t yPos);
|
||||
|
||||
/*!
|
||||
* \brief Getter to get the flags stored
|
||||
* \flags Where to store the flags
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_GetFlags(uint32_t *flags);
|
||||
|
||||
/*!
|
||||
* \brief Setter to set the flags in the configuration
|
||||
* \param flags The flags to be set
|
||||
* \return Error code, ERR_OK for everything ok
|
||||
*/
|
||||
uint8_t NVMC_SetFlags(uint32_t flags);
|
||||
|
||||
/*! \brief Command line shell parser interface */
|
||||
uint8_t NVMC_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
|
||||
/*! \brief Module de-initialization */
|
||||
void NVMC_Deinit(void);
|
||||
|
||||
/*! \brief Module initialization */
|
||||
void NVMC_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* NVMC_H_ */
|
||||
195
pico-sensor/src/oled.c
Normal file
195
pico-sensor/src/oled.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_OLED
|
||||
#include "McuUtility.h"
|
||||
#include "McuSSD1306.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuSSD1306.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuGDisplaySSD1306.h"
|
||||
#include "McuFontDisplay.h"
|
||||
#include "McuFontHelv10Normal.h"
|
||||
#include "McuFontHelv12Normal.h"
|
||||
#include "McuFontHelv18Bold.h"
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
#include "sensor.h"
|
||||
#endif
|
||||
#if PL_HAS_RADIO
|
||||
#include "RNet/Radio.h"
|
||||
#endif
|
||||
|
||||
static QueueHandle_t oledTextQueue; /* Queue storing pointers to the text to display */
|
||||
#define OLED_TEXT_QUEUE_LENGTH (8)
|
||||
#define OLED_TEXT_QUEUE_ELEM_SIZE (sizeof(unsigned char*))
|
||||
|
||||
void OLED_SendText(const char *text) {
|
||||
size_t len;
|
||||
unsigned char *p;
|
||||
|
||||
len = McuUtility_strlen(text)+1; /* plus 1 for the zero byte */
|
||||
p = pvPortMalloc(len);
|
||||
|
||||
McuUtility_strcpy(p, len, (unsigned char*)text);
|
||||
if (xQueueSendToBack(oledTextQueue, &p, pdMS_TO_TICKS(3000))!= pdPASS) { /* queue pointer to data */
|
||||
vPortFree(p); /* failed, give memory free again */
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t OLED_GetText(unsigned char *buf, size_t bufSize) {
|
||||
unsigned char *p;
|
||||
|
||||
if (xQueueReceive(oledTextQueue, &p, 0)==pdPASS) {
|
||||
McuUtility_strcpy(buf, bufSize, p);
|
||||
vPortFree(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_IDLE;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Shows one line of text centered on the display, with a border around it
|
||||
* \param text0 Line one of text
|
||||
*/
|
||||
static void Show1Liner(const unsigned char *text0) {
|
||||
PGFONT_Callbacks font = McuFontHelv12Normal_GetFont();
|
||||
McuFontDisplay_PixelDim x, y;
|
||||
McuFontDisplay_PixelDim charHeight, totalHeight;
|
||||
|
||||
McuGDisplaySSD1306_Clear();
|
||||
McuFontDisplay_GetFontHeight(font, &charHeight, &totalHeight);
|
||||
|
||||
x = McuGDisplaySSD1306_GetWidth()/2 - McuFontDisplay_GetStringWidth((unsigned char*)text0, font, NULL)/2;
|
||||
y = McuGDisplaySSD1306_GetHeight()/2 - charHeight/2; /* 1 line */
|
||||
McuFontDisplay_WriteString((unsigned char*)text0, McuGDisplaySSD1306_COLOR_BLUE, &x, &y, font);
|
||||
|
||||
McuGDisplaySSD1306_DrawBox(0, 0, McuGDisplaySSD1306_GetWidth()-1, McuGDisplaySSD1306_GetHeight()-1, 1, McuGDisplaySSD1306_COLOR_BLUE);
|
||||
McuGDisplaySSD1306_DrawBox(2, 2, McuGDisplaySSD1306_GetWidth()-1-4, McuGDisplaySSD1306_GetHeight()-1-4, 1, McuGDisplaySSD1306_COLOR_BLUE);
|
||||
McuGDisplaySSD1306_UpdateFull();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Shows two lines of text centered on the display, with a border around it
|
||||
* \param text0 Line one of text
|
||||
* \param text1 Line two of text
|
||||
*/
|
||||
static void Show2Liner(const unsigned char *text0, const unsigned char *text1) {
|
||||
PGFONT_Callbacks font = McuFontHelv12Normal_GetFont();
|
||||
McuFontDisplay_PixelDim x, y;
|
||||
McuFontDisplay_PixelDim charHeight, totalHeight;
|
||||
|
||||
McuGDisplaySSD1306_Clear();
|
||||
McuFontDisplay_GetFontHeight(font, &charHeight, &totalHeight);
|
||||
|
||||
x = McuGDisplaySSD1306_GetWidth()/2 - McuFontDisplay_GetStringWidth((unsigned char*)text0, font, NULL)/2;
|
||||
y = McuGDisplaySSD1306_GetHeight()/2 - (2*charHeight)/2; /* 2 lines */
|
||||
McuFontDisplay_WriteString((unsigned char*)text0, McuGDisplaySSD1306_COLOR_BLUE, &x, &y, font);
|
||||
|
||||
x = McuGDisplaySSD1306_GetWidth()/2 - McuFontDisplay_GetStringWidth((unsigned char*)text1, font, NULL)/2;
|
||||
y += McuGDisplaySSD1306_GetHeight()/2 - (2*charHeight)/2;
|
||||
McuFontDisplay_WriteString((unsigned char*)text1, McuGDisplaySSD1306_COLOR_BLUE, &x, &y, font);
|
||||
|
||||
McuGDisplaySSD1306_DrawBox(0, 0, McuGDisplaySSD1306_GetWidth()-1, McuGDisplaySSD1306_GetHeight()-1, 1, McuGDisplaySSD1306_COLOR_BLUE);
|
||||
McuGDisplaySSD1306_DrawBox(2, 2, McuGDisplaySSD1306_GetWidth()-1-4, McuGDisplaySSD1306_GetHeight()-1-4, 1, McuGDisplaySSD1306_COLOR_BLUE);
|
||||
McuGDisplaySSD1306_UpdateFull();
|
||||
}
|
||||
|
||||
//static bool volatile wait = false;
|
||||
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
static void ShowSensorValues(void) {
|
||||
float t, h;
|
||||
unsigned char buf1[16], buf2[16];
|
||||
|
||||
h = Sensor_GetHumidity();
|
||||
t = Sensor_GetTemperature();
|
||||
McuUtility_strcpy(buf1, sizeof(buf1), (unsigned char*)"T: ");
|
||||
McuUtility_strcatNumFloat(buf1, sizeof(buf1), t, 2);
|
||||
McuUtility_strcat(buf1, sizeof(buf1), (unsigned char*)" C");
|
||||
McuUtility_strcpy(buf2, sizeof(buf2), (unsigned char*)"H: ");
|
||||
McuUtility_strcatNumFloat(buf2, sizeof(buf2), h, 2);
|
||||
McuUtility_strcat(buf2, sizeof(buf2), (unsigned char*)" %");
|
||||
Show2Liner(buf1, buf2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void OledTask(void *pv) {
|
||||
unsigned char buf[16];
|
||||
uint32_t counter = 0;
|
||||
uint32_t ms = 0;
|
||||
|
||||
//while(wait) {
|
||||
// vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
// McuLog_info("waiting for debugger");
|
||||
//}
|
||||
McuSSD1306_Clear();
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
Show2Liner((unsigned char*)"ADIS", (unsigned char*)"ESP32");
|
||||
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
||||
Show2Liner((unsigned char*)"TSM", (unsigned char*)"RP2040");
|
||||
#endif
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
ShowSensorValues();
|
||||
#endif
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
for(;;) {
|
||||
while (OLED_GetText(buf, sizeof(buf))==ERR_OK) {
|
||||
Show1Liner(buf);
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
ms += 500;
|
||||
}
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
if ((ms%10000)==0) { /* every 10 seconds */
|
||||
ShowSensorValues();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
ms += 1000;
|
||||
#endif
|
||||
#if PL_HAS_RADIO
|
||||
if (RADIO_IsSane()==ERR_OK) {
|
||||
Show1Liner("nRF ok");
|
||||
} else {
|
||||
Show1Liner("nRF NOT ok");
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
ms += 1000;
|
||||
#endif
|
||||
} else if ((ms%1000)==0) { /* every second */
|
||||
McuUtility_Num32uToStr(buf, sizeof(buf), counter);
|
||||
counter++;
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
Show2Liner((unsigned char*)"ADIS ESP32", buf);
|
||||
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
||||
Show2Liner((unsigned char*)"TSM RP2040", buf);
|
||||
#else
|
||||
#error "???"
|
||||
#endif
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ms += 100;
|
||||
}
|
||||
}
|
||||
|
||||
void OLED_Init(void) {
|
||||
BaseType_t res;
|
||||
|
||||
res = xTaskCreate(OledTask, "OledTask", (2*1024)/sizeof(StackType_t), NULL, tskIDLE_PRIORITY+4, NULL);
|
||||
if (res!=pdPASS) {
|
||||
McuLog_fatal("creating OledTask task failed!"); // GCOVR_EXCL_LINE
|
||||
}
|
||||
McuSSD1306_Init();
|
||||
McuGDisplaySSD1306_Init();
|
||||
|
||||
oledTextQueue = xQueueCreate(OLED_TEXT_QUEUE_LENGTH, OLED_TEXT_QUEUE_ELEM_SIZE);
|
||||
if (oledTextQueue==NULL) {
|
||||
McuLog_fatal("not able to create oledTextQueue queue"); // GCOVR_EXCL_LINE
|
||||
for(;;){} /* out of memory? */ // GCOVR_EXCL_LINE
|
||||
}
|
||||
vQueueAddToRegistry(oledTextQueue, "oledTextQueue");
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_OLED */
|
||||
31
pico-sensor/src/oled.h
Normal file
31
pico-sensor/src/oled.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MAIN_OLED_H_
|
||||
#define MAIN_OLED_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
#include "buttons.h"
|
||||
#include "McuDebounce.h"
|
||||
|
||||
void OLED_OnButtonEvent(BTN_Buttons_e button, McuDbnc_EventKinds kind);
|
||||
#endif
|
||||
|
||||
void OLED_SendText(const char *text);
|
||||
|
||||
void OLED_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_OLED_H_ */
|
||||
289
pico-sensor/src/platform.c
Normal file
289
pico-sensor/src/platform.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_WIFI
|
||||
#include "PicoWiFi.h"
|
||||
#elif PL_CONFIG_USE_PICO_W
|
||||
#include "pico/cyw43_arch.h" /* must be first, otherwise conflict with lwIP ERR_OK */
|
||||
#endif
|
||||
#include "McuLib.h"
|
||||
#if PL_CONFIG_USE_BLINKY
|
||||
#include "blinky.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_USB_CDC
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
#include "McuButton.h"
|
||||
#include "McuDebounce.h"
|
||||
#include "buttons.h"
|
||||
#include "debounce.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_CLIENT
|
||||
#include "udp_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_SERVER
|
||||
#include "udp_server.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "shell.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
#include "McuFlash.h"
|
||||
#include "nvmc.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MININI
|
||||
#include "MinIni/McuMinINI.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_PING
|
||||
#include "ping_shell.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
#include "ntp_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
#include "mqtt_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_TIME_DATE
|
||||
#include "McuTimeDate.h"
|
||||
#include "timer.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_ROBO_REMOTE
|
||||
#include "robot.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_CHALLENGE
|
||||
#include "challenge.h"
|
||||
#endif
|
||||
#include "McuWait.h"
|
||||
#include "McuGPIO.h"
|
||||
#include "McuLED.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuXFormat.h"
|
||||
#if McuLib_CONFIG_SDK_USE_FREERTOS
|
||||
#include "McuRTOS.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_USB_CDC
|
||||
#include "pico/stdio_usb.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_TUD_CDC
|
||||
#include "McuShellCdcDevice.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UART
|
||||
#include "pico/stdio_uart.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SEMIHOSTING
|
||||
#include "pico/stdio_semihosting.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "shell.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RTT
|
||||
#include "McuRTT.h"
|
||||
#endif
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
#include "McuSystemView.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SPI
|
||||
#include "McuSPI.h"
|
||||
#endif
|
||||
#if PL_HAS_RADIO
|
||||
#include "RNet_App.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_I2C
|
||||
#include "McuGenericI2C.h"
|
||||
#include "McuGenericSWI2C.h"
|
||||
#include "McuI2cLib.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_OLED
|
||||
#include "McuSSD1306.h"
|
||||
#include "oled.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
#include "sensor.h"
|
||||
#endif
|
||||
#if McuUart485_CONFIG_USE_RS_485
|
||||
#include "McuUart485.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RS485_SHELL
|
||||
#include "rs485.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UNIT_TESTS
|
||||
#include "tests/tests.h"
|
||||
#endif
|
||||
#if McuRdimon_CONFIG_IS_ENABLED
|
||||
#include "rdimon/McuRdimon.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GCOV
|
||||
#include "McuCoverage.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
#include "leds.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MCUFLASH
|
||||
#include "McuFlash.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MINI
|
||||
#include "minIni/McuMinINI.h"
|
||||
#endif
|
||||
#if McuSemihost_CONFIG_IS_ENABLED
|
||||
#include "McuSemihost.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GPROF
|
||||
#include "gprof_support.h"
|
||||
#endif
|
||||
#include "McuHardFault.h"
|
||||
#include "application.h"
|
||||
#include "hardware/timer.h"
|
||||
|
||||
void PL_Init(void) {
|
||||
portDISABLE_ALL_INTERRUPTS();
|
||||
#if McuRdimon_CONFIG_IS_ENABLED
|
||||
McuRdimon_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_TUD_CDC
|
||||
McuShellCdcDevice_Init();
|
||||
McuShellCdcDevice_SetBufferRxCharCallback(McuShellCdcDevice_QueueChar);
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GCOV
|
||||
McuCoverage_Init(); /* initialize library */
|
||||
McuCoverage_Check(); /* testing only */
|
||||
//gcov_test(3); /* testing only */
|
||||
#endif
|
||||
#if PL_CONFIG_USE_GPROF
|
||||
if (profile_file_write_check()!=1) {
|
||||
McuLog_fatal("cannot write file with semihosting");
|
||||
for(;;) {}
|
||||
}
|
||||
gprof_init_timer();
|
||||
// gprof_test(); /* test only */
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SEMIHOSTING
|
||||
stdio_semihosting_init();
|
||||
stdio_set_translate_crlf(&stdio_semihosting, false);
|
||||
#endif
|
||||
#if 1 /* workaround for CMSIS-DAP, see https://github.com/raspberrypi/pico-sdk/issues/1152 */
|
||||
timer_hw->dbgpause = 0;
|
||||
#endif
|
||||
McuLib_Init();
|
||||
McuHardFault_Init();
|
||||
McuWait_Init();
|
||||
#if PL_CONFIG_USE_PICO_W
|
||||
McuWait_Waitms(50); /* need to wait some time, otherwise cyw43_arch_init() might hang. */
|
||||
#endif
|
||||
#if McuLib_CONFIG_SDK_USE_FREERTOS
|
||||
McuRTOS_Init();
|
||||
#endif
|
||||
McuLog_Init();
|
||||
McuUtility_Init();
|
||||
McuGPIO_Init();
|
||||
McuLED_Init();
|
||||
#if PL_CONFIG_USE_TIME_DATE
|
||||
McuTimeDate_Init();
|
||||
TMR_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
Leds_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MCUFLASH
|
||||
McuFlash_Init();
|
||||
McuFlash_RegisterMemory((void*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, McuMinINI_CONFIG_FLASH_NVM_NOF_BLOCKS*McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE);
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_BLINKY
|
||||
Blinky_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
McuBtn_Init();
|
||||
BTN_Init();
|
||||
McuDbnc_Init();
|
||||
Debounce_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RTT
|
||||
McuRTT_Init();
|
||||
#endif
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
McuSystemView_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_WIFI && McuLib_CONFIG_CPU_IS_ESP32
|
||||
ESP_ERROR_CHECK(nvs_flash_init()); /* need to call this before using any WiFi functions */
|
||||
ESP32_MacInit();
|
||||
WiFi_Init();
|
||||
#elif PL_CONFIG_USE_WIFI && McuLib_CONFIG_CPU_IS_RPxxxx
|
||||
PicoWiFi_Init();
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_UDP_SERVER
|
||||
UDP_Server_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_CLIENT
|
||||
UDP_Client_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_PING
|
||||
PING_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
NtpClient_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
MqttClient_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SPI
|
||||
McuSPI_Init();
|
||||
#endif
|
||||
#if PL_HAS_RADIO
|
||||
RNETA_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
McuXFormat_Init();
|
||||
McuShell_Init();
|
||||
SHELL_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
NVMC_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_I2C
|
||||
#if CONFIG_USE_HW_I2C
|
||||
McuI2cLib_Init();
|
||||
#else
|
||||
McuGenericSWI2C_Init();
|
||||
#endif
|
||||
McuGenericI2C_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_OLED
|
||||
OLED_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
Sensor_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
NVMC_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MININI
|
||||
McuMinINI_Init();
|
||||
McuFlash_Init();
|
||||
McuFlash_RegisterMemory((const void*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, 1*McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE);
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RS485
|
||||
RS485_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_ROBO_REMOTE
|
||||
ROBOT_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_CHALLENGE
|
||||
Challenge_Init();
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UNIT_TESTS
|
||||
Tests_Init();
|
||||
#endif
|
||||
#if McuSemihost_CONFIG_IS_ENABLED
|
||||
McuSemiHost_Init();
|
||||
#endif
|
||||
App_Init();
|
||||
}
|
||||
96
pico-sensor/src/platform.h
Normal file
96
pico-sensor/src/platform.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_H_
|
||||
#define PLATFORM_H_
|
||||
|
||||
#include "IncludeMcuLibConfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PL_CONFIG_USE_PICO_W ((PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_1) || (PL_CONFIG_HW_VERSION==PL_CONFIG_HW_ADIS_PICO_W_CONSOLE_V0_2))
|
||||
/* if using Pico W board */
|
||||
/* Note:
|
||||
* if using Pico-W:
|
||||
* a) enable 'library pico_cyw43_arch_lwip_sys_freertos' in CMakeLists.txt of src folder
|
||||
* b) Enable set(PICO_BOARD pico_w) in CMakeLists.txt in project root
|
||||
*/
|
||||
|
||||
/* platform configuration macros: set to 1 to enable functionality */
|
||||
#define PL_CONFIG_USE_LEDS (1) /* if using LEDs */
|
||||
#define PL_CONFIG_USE_APP_TASK (1) /* if using app task */
|
||||
#define PL_CONFIG_USE_BLINKY (0 && PL_CONFIG_USE_LEDS) /*!< if using blinky */
|
||||
#define PL_CONFIG_USE_BUTTONS (1) /* using nav switch buttons */
|
||||
#define PL_CONFIG_USE_BUTTONS_IRQ (1 && !(McuLib_CONFIG_CPU_IS_ESP32 && PL_CONFIG_USE_WIFI)) /* if using button interrupts */
|
||||
/* Note: on ESP32, there is a hardware bug, triggering interrupts on GPIO36 (right) and GPIO39 (down).
|
||||
* See https://github.com/espressif/esp-idf/commit/d890a516a1097f0a07788e203fdb1a82bb83520e
|
||||
* and 3.11 in https://www.espressif.com/sites/default/files/documentation/esp32_errata_en.pdf */
|
||||
|
||||
/* Wireless related settings */
|
||||
#define PL_CONFIG_USE_WIFI (1) /* if using WiFi functionality */
|
||||
#define PL_CONFIG_USE_IDENTIFY (0 && PL_CONFIG_USE_WIFI) /*!< used to identify MAC, needed for EEE network */
|
||||
#define PL_CONFIG_USE_UDP_SERVER (0 && PL_CONFIG_USE_WIFI) /*!< UDP server, used for communication to robot */
|
||||
#define PL_CONFIG_USE_UDP_CLIENT (0 && PL_CONFIG_USE_WIFI) /*!< UDP client, optionally available for tests */
|
||||
#define PL_CONFIG_USE_PING (0 && PL_CONFIG_USE_WIFI) /*!< shell command with ping, to test network connection */
|
||||
#define PL_CONFIG_USE_NTP_CLIENT (1 && PL_CONFIG_USE_WIFI)
|
||||
#define PL_CONFIG_USE_MQTT_CLIENT (1 && PL_CONFIG_USE_WIFI) /* if running MQTT client */
|
||||
|
||||
#define PL_CONFIG_USE_TIME_DATE (1) /*!< if using Time and Date information */
|
||||
|
||||
#define PL_CONFIG_USE_SPI (1) /* if using SPI bus */
|
||||
#define PL_HAS_RADIO (1 && PL_CONFIG_USE_SPI && McuRNET_CONFIG_IS_ENABLED && McuNRF24L01_CONFIG_IS_ENABLED) /* RNET with nRF24L01+ */
|
||||
|
||||
#define PL_CONFIG_USE_SHELL (1 && !PL_CONFIG_USE_UNIT_TESTS) /* command line shell: cannot use it with unit tests because of argument handling */
|
||||
#define PL_CONFIG_USE_RTT (1) /* SEGGER RTT */
|
||||
#define PL_CONFIG_USE_UART (0) /* if using UART for stdio */
|
||||
#define PL_CONFIG_USE_TUD_CDC (1) /* tinyUSB CDC device with McuShellCdcDevice */
|
||||
#define PL_CONFIG_USE_SHELL_CDC (1 && PL_CONFIG_USE_TUD_CDC) /* if using CDC as shell interface */
|
||||
#define PL_CONFIG_USE_SEMIHOSTING (0) /* if using semihosting for standard I/O */
|
||||
#define PL_CONFIG_USE_RS485 (0 && McuUart485_CONFIG_USE_RS_485)
|
||||
#define PL_CONFIG_USE_RS485_SHELL (1 && PL_CONFIG_USE_RS485)
|
||||
|
||||
/* I2C: OLED and Sensor */
|
||||
#define PL_CONFIG_USE_I2C (1) /* if using I2C bus */
|
||||
#define PL_CONFIG_USE_HW_I2C (1 && PL_CONFIG_USE_I2C && CONFIG_USE_HW_I2C)
|
||||
#define PL_CONFIG_USE_OLED (1 && PL_CONFIG_USE_I2C)
|
||||
#define PL_CONFIG_USE_SENSOR (1 && PL_CONFIG_USE_I2C)
|
||||
#define PL_CONFIG_USE_SHT31 (1 && PL_CONFIG_USE_SENSOR) /* board is using SHT31 */
|
||||
#define PL_CONFIG_USE_SHT40 (!PL_CONFIG_USE_SHT31 && PL_CONFIG_USE_SENSOR) /* board is using SHT31 */
|
||||
|
||||
#define PL_CONFIG_USE_NVMC (1) /* if using non-volatile memory for storing settings */
|
||||
#define PL_CONFIG_USE_MINI (1 && PL_CONFIG_USE_NVMC)
|
||||
|
||||
/* robot specific */
|
||||
#define PL_CONFIG_USE_ROBOT_HAT (0) /* if using RobotHAT */
|
||||
#define PL_CONFIG_USE_CHALLENGE (0 && PL_CONFIG_USE_ROTOT_HAT) /* HS2022 challenge */
|
||||
#define PL_CONFIG_USE_ROBO_REMOTE (0 && PL_CONFIG_USE_ROTOT_HAT && PL_CONFIG_USE_UDP_SERVER) /* UDP Remote controller for robot */
|
||||
#define PL_CONFIG_USE_WDT (0) /* watchdog */
|
||||
|
||||
#define PL_CONFIG_USE_UNIT_TESTS (1 && defined(ENABLE_UNIT_TESTS) && ENABLE_UNIT_TESTS==1) /* if using unit tests. ENABLE_UNIT_TESTS is set by the CMake file */
|
||||
#if PL_CONFIG_USE_UNIT_TESTS && !defined(UNITY_OUTPUT_CHAR)
|
||||
#error "needs to be defined in IncludeMcuLibConfig.h!"
|
||||
#endif
|
||||
|
||||
#define PL_CONFIG_USE_GCOV (0 && McuRdimon_CONFIG_IS_ENABLED && McuCoverage_CONFIG_IS_ENABLED) /* if using gcov */
|
||||
#define PL_CONFIG_USE_GPROF (0) /* GNU gprof profiling */
|
||||
|
||||
/*!
|
||||
* \brief de-initializes the platform
|
||||
*/
|
||||
void PL_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief initializes the platform
|
||||
*/
|
||||
void PL_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* PLATFORM_H_ */
|
||||
629
pico-sensor/src/rs485.c
Normal file
629
pico-sensor/src/rs485.c
Normal file
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_RS485
|
||||
#include "rs485.h"
|
||||
#include "McuGPIO.h"
|
||||
#include "McuUart485.h"
|
||||
#include "McuShell.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
#include "shell.h"
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
#include "nvmc.h"
|
||||
#endif
|
||||
|
||||
typedef enum RS485_Response_e {
|
||||
RS485_RESPONSE_CONTINUE, /* continue scanning and parsing */
|
||||
RS485_RESPONSE_OK, /* ok response */
|
||||
RS485_RESPONSE_NOK, /* not ok response */
|
||||
RS485_RESPONSE_TIMEOUT, /* timeout */
|
||||
} RS485_Response_e;
|
||||
|
||||
static bool RS485_DoLogging = false; /* if traffic on the bus shall be reported on the shell */
|
||||
static SemaphoreHandle_t RS485_stdioMutex; /* mutex to protect access to standard I/O */
|
||||
|
||||
uint8_t RS485_GetAddress(void) {
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
uint8_t addr = 0;
|
||||
|
||||
if (NVMC_GetRS485Addr(&addr)==ERR_OK) {
|
||||
return addr;
|
||||
}
|
||||
return 0; /* failed */
|
||||
#elif McuLib_CONFIG_CPU_IS_LPC
|
||||
return 1; /* hard coded */
|
||||
#elif McuLib_CONFIG_CPU_IS_ESP32
|
||||
return 1; /* hard coded */
|
||||
#endif
|
||||
return 0; /* error, default */
|
||||
}
|
||||
|
||||
static void RS485_SendChar(unsigned char ch) {
|
||||
McuUart485_stdio.stdOut(ch);
|
||||
}
|
||||
|
||||
static void RS485_NullSend(unsigned char ch) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void RS485_ReadChar(uint8_t *c) {
|
||||
*c = '\0'; /* only sending on this channel */
|
||||
}
|
||||
|
||||
static bool RS485_CharPresent(void) {
|
||||
return false; /* only sending on this channel */
|
||||
}
|
||||
|
||||
McuShell_ConstStdIOType RS485_stdio = {
|
||||
.stdIn = (McuShell_StdIO_In_FctType)RS485_ReadChar,
|
||||
.stdOut = (McuShell_StdIO_OutErr_FctType)RS485_SendChar,
|
||||
.stdErr = (McuShell_StdIO_OutErr_FctType)RS485_SendChar,
|
||||
.keyPressed = RS485_CharPresent, /* if input is not empty */
|
||||
#if McuShell_CONFIG_ECHO_ENABLED
|
||||
.echoEnabled = false,
|
||||
#endif
|
||||
};
|
||||
|
||||
McuShell_ConstStdIOType RS485_stdioBroadcast = {
|
||||
.stdIn = (McuShell_StdIO_In_FctType)RS485_ReadChar,
|
||||
.stdOut = (McuShell_StdIO_OutErr_FctType)RS485_NullSend,
|
||||
.stdErr = (McuShell_StdIO_OutErr_FctType)RS485_NullSend,
|
||||
.keyPressed = RS485_CharPresent, /* if input is not empty */
|
||||
#if McuShell_CONFIG_ECHO_ENABLED
|
||||
.echoEnabled = false,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* parser I/O handler, used to parse the returned data after sending a command to the RS-485 bus */
|
||||
static void RS485Parse_SendChar(unsigned char ch) {
|
||||
if (xSemaphoreTakeRecursive(RS485_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
McuUart485_stdio.stdOut(ch);
|
||||
(void)xSemaphoreGiveRecursive(RS485_stdioMutex); /* give back mutex */
|
||||
}
|
||||
}
|
||||
|
||||
static void RS485Parse_ReadChar(uint8_t *c) {
|
||||
if (xSemaphoreTakeRecursive(RS485_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
McuUart485_stdio.stdIn(c);
|
||||
(void)xSemaphoreGiveRecursive(RS485_stdioMutex); /* give back mutex */
|
||||
}
|
||||
}
|
||||
|
||||
static bool RS485Parse_CharPresent(void) {
|
||||
bool inputPresent = false;
|
||||
|
||||
if (xSemaphoreTakeRecursive(RS485_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
inputPresent = McuUart485_stdio.keyPressed();
|
||||
(void)xSemaphoreGiveRecursive(RS485_stdioMutex); /* give back mutex */
|
||||
}
|
||||
return inputPresent;
|
||||
}
|
||||
|
||||
static McuShell_ConstStdIOType RS485Parse_stdio = {
|
||||
.stdIn = (McuShell_StdIO_In_FctType)RS485Parse_ReadChar,
|
||||
.stdOut = (McuShell_StdIO_OutErr_FctType)RS485Parse_SendChar,
|
||||
.stdErr = (McuShell_StdIO_OutErr_FctType)RS485Parse_SendChar,
|
||||
.keyPressed = RS485Parse_CharPresent, /* if input is not empty */
|
||||
#if McuShell_CONFIG_ECHO_ENABLED
|
||||
.echoEnabled = false,
|
||||
#endif
|
||||
};
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void RS485_SendStr(unsigned char *str) {
|
||||
while(*str!='\0') {
|
||||
RS485_stdio.stdOut(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t CalcCRC(const uint8_t *data, uint8_t dataSize, uint8_t start) {
|
||||
uint8_t crc, i, x, y;
|
||||
|
||||
crc = start;
|
||||
for(x=0;x<dataSize;x++){
|
||||
y = data[x];
|
||||
for(i=0;i<8;i++) { /* go through all bits of the data byte */
|
||||
if((crc&0x01)^(y&0x01)) {
|
||||
crc >>= 1;
|
||||
crc ^= 0x8c;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
y >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint8_t CalcMsgCrc(const unsigned char *msg) {
|
||||
/* header is "@dd ss cc ...", both dd, ss and cc are 8bit HEX values. The CRC (cc) is not included in the CRC */
|
||||
uint8_t crc;
|
||||
|
||||
crc = CalcCRC(msg, sizeof("@dd ss ")-1, 0);
|
||||
crc = CalcCRC(msg+sizeof("@dd ss cc")-1, strlen((char*)msg+sizeof("@dd ss cc")-1), crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
typedef enum CMD_ParserState_e {
|
||||
CMD_PARSER_INIT,
|
||||
CMD_PARSER_START_DETECTED, /* start '@' detected */
|
||||
CMD_PARSER_SCAN_DST_ADDR, /* scanning destination address */
|
||||
CMD_PARSER_SCAN_SRC_ADDR, /* scan source address */
|
||||
CMD_PARSER_SCAN_CRC, /* scan CRC */
|
||||
CMD_PARSER_SCAN_OK_NOK, /* reading NOK or OK */
|
||||
} CMD_ParserState_e;
|
||||
|
||||
static RS485_Response_e Scan(CMD_ParserState_e *state, unsigned char ch, unsigned char *buf, size_t bufSize, uint8_t fromAddr) {
|
||||
/* scan for "@<dstaddr> <srcAddr> <CRC> OK"
|
||||
* or "@<dstaddr> <srcAddr> <CRC> NOK"
|
||||
*/
|
||||
const unsigned char *p;
|
||||
uint8_t addr;
|
||||
uint8_t exp_crc;
|
||||
static uint8_t crc = 0;
|
||||
|
||||
if (ch=='@') { /* a marker? start scanning again */
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
for(;;) { /* breaks or returns */
|
||||
switch(*state) {
|
||||
case CMD_PARSER_INIT:
|
||||
buf[0] = '\0'; /* reset buffer */
|
||||
if (ch=='@') { /* a marker? start scanning again */
|
||||
McuUtility_chcat(buf, bufSize, ch);
|
||||
*state = CMD_PARSER_START_DETECTED;
|
||||
break; /* continue state machine */
|
||||
}
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
|
||||
case CMD_PARSER_START_DETECTED:
|
||||
*state = CMD_PARSER_SCAN_DST_ADDR;
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
|
||||
case CMD_PARSER_SCAN_DST_ADDR:
|
||||
McuUtility_chcat(buf, bufSize, ch);
|
||||
if (ch==' ') {
|
||||
p = &buf[sizeof("@")-1];
|
||||
if (McuUtility_ScanHex8uNumberNoPrefix(&p, &addr)==ERR_OK && addr==RS485_GetAddress()) {
|
||||
*state = CMD_PARSER_SCAN_SRC_ADDR;
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
} else {
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
} else if (ch=='\n') { /* failed */
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
|
||||
case CMD_PARSER_SCAN_SRC_ADDR:
|
||||
McuUtility_chcat(buf, bufSize, ch);
|
||||
if (ch==' ') {
|
||||
p = &buf[sizeof("@ss ")-1];
|
||||
if (McuUtility_ScanHex8uNumberNoPrefix(&p, &addr)==ERR_OK && addr==fromAddr) {
|
||||
*state = CMD_PARSER_SCAN_CRC;
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
} else {
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
} else if (ch=='\n') { /* failed */
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
|
||||
case CMD_PARSER_SCAN_CRC:
|
||||
McuUtility_chcat(buf, bufSize, ch);
|
||||
if (ch==' ') {
|
||||
p = &buf[sizeof("@ss dd ")-1];
|
||||
if (McuUtility_ScanHex8uNumberNoPrefix(&p, &crc)==ERR_OK) {
|
||||
*state = CMD_PARSER_SCAN_OK_NOK;
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
} else {
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
} else if (ch=='\n') { /* failed */
|
||||
*state = CMD_PARSER_INIT;
|
||||
}
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
|
||||
case CMD_PARSER_SCAN_OK_NOK:
|
||||
McuUtility_chcat(buf, bufSize, ch);
|
||||
if (ch=='\n') {
|
||||
p = &buf[sizeof("@ss dd cc ")-1];
|
||||
if (McuUtility_strcmp((char*)p, (char*)"OK\n")==0) { /* a match! */
|
||||
buf[sizeof("@ss dd cc OK")-1] = '\0'; /* overwrite '\n' as not included in CRC */
|
||||
exp_crc = CalcMsgCrc(buf);
|
||||
*state = CMD_PARSER_INIT;
|
||||
if (crc==exp_crc) {
|
||||
return RS485_RESPONSE_OK;
|
||||
} else {
|
||||
return RS485_RESPONSE_NOK;
|
||||
}
|
||||
} else if (McuUtility_strcmp((char*)buf, (char*)"NOK\n")==0) { /* a match! */
|
||||
buf[sizeof("@ss dd cc NOK")-1] = '\0'; /* overwrite '\n' as not included in CRC */
|
||||
exp_crc = CalcMsgCrc(buf);
|
||||
*state = CMD_PARSER_INIT;
|
||||
if (crc==exp_crc) {
|
||||
return RS485_RESPONSE_NOK;
|
||||
} else {
|
||||
return RS485_RESPONSE_NOK; /* CRC is not ok, and message is NOK too */
|
||||
}
|
||||
} else if (ch=='\n') { /* failed */
|
||||
*state = CMD_PARSER_INIT;
|
||||
break; /* continue in state machine */
|
||||
}
|
||||
}
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
|
||||
default:
|
||||
break;
|
||||
} /* switch */
|
||||
/* get here with a break */
|
||||
} /* for */
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
}
|
||||
|
||||
static RS485_Response_e WaitForResponse(int32_t timeoutMs, uint8_t fromAddr, McuShell_ConstStdIOType *shellIO, McuShell_ConstStdIOType *rsIO) {
|
||||
unsigned char buf[24] = ""; /* enough for "@<addr> <fromAddr> OK" or "@<addr> <fromAddr> NOK" */
|
||||
unsigned char ch;
|
||||
RS485_Response_e resp;
|
||||
CMD_ParserState_e state = CMD_PARSER_INIT;
|
||||
|
||||
for(;;) { /* returns */
|
||||
/* read response text and write into buffer or to console */
|
||||
static unsigned char lineBuffer[512]; /* enough for a line of text coming back from the bus */
|
||||
|
||||
lineBuffer[0] = '\0'; /* initialize buffer */
|
||||
do {
|
||||
rsIO->stdIn(&ch);
|
||||
if (ch!='\0') {
|
||||
McuUtility_chcat(lineBuffer, sizeof(lineBuffer), ch);
|
||||
if (ch=='\n') {
|
||||
if (lineBuffer[0]!='@') { /* do not send things like OK or NOK messages from bus */
|
||||
SHELL_SendStringToIO(lineBuffer, shellIO);
|
||||
}
|
||||
lineBuffer[0] = '\0'; /* reset buffer */
|
||||
}
|
||||
}
|
||||
} while(ch!='\0');
|
||||
|
||||
ch = McuUart485_GetResponseQueueChar();
|
||||
if (ch!='\0') {
|
||||
resp = Scan(&state, ch, buf, sizeof(buf), fromAddr);
|
||||
if (resp==RS485_RESPONSE_OK || resp==RS485_RESPONSE_NOK) {
|
||||
return resp;
|
||||
}
|
||||
} else { /* empty response buffer: check normal incoming characters */
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
#if PL_CONFIG_USE_WDT
|
||||
WDT_Report(WDT_REPORT_ID_CURR_TASK, 50);
|
||||
#endif
|
||||
timeoutMs -= 50;
|
||||
if (timeoutMs<=0) {
|
||||
return RS485_RESPONSE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
} /* for */
|
||||
return RS485_RESPONSE_CONTINUE;
|
||||
}
|
||||
|
||||
uint8_t RS485_SendCommand(uint8_t dstAddr, const unsigned char *cmd, int32_t timeoutMs, uint32_t nofRetry, McuShell_ConstStdIOType *shellIO, McuShell_ConstStdIOType *rsIO) {
|
||||
/* example: send "@16 1 cmd stepper status" */
|
||||
unsigned char buf[McuShell_DEFAULT_SHELL_BUFFER_SIZE];
|
||||
uint8_t res = ERR_OK;
|
||||
RS485_Response_e resp;
|
||||
uint8_t crc, hex;
|
||||
|
||||
if (rsIO==NULL) { /* assign default */
|
||||
rsIO = &RS485Parse_stdio;
|
||||
}
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)("@"));
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), dstAddr); /* add destination address */
|
||||
McuUtility_chcat(buf, sizeof(buf), ' ');
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), RS485_GetAddress()); /* add src address */
|
||||
McuUtility_chcat(buf, sizeof(buf), ' ');
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), 0); /* dummy crc, will be replaced with real one */
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)(" cmd "));
|
||||
McuUtility_strcat(buf, sizeof(buf), cmd);
|
||||
/* update crc */
|
||||
crc = CalcMsgCrc(buf);
|
||||
hex = (char)((crc>>4) & 0x0F);
|
||||
buf[sizeof("@dd ss ")-1] = (char)(hex + ((hex <= 9) ? '0' : ('A'-10)));
|
||||
hex = (char)(crc & 0x0F);
|
||||
buf[sizeof("@dd ss c")-1] = (char)(hex + ((hex <= 9) ? '0' : ('A'-10)));
|
||||
|
||||
if (xSemaphoreTakeRecursive(RS485_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
for(;;) { /* breaks */
|
||||
McuUart485_ClearResponseQueue(); /* clear up if there is something pending */
|
||||
if (RS485_DoLogging) {
|
||||
McuLog_trace("Tx: %s", buf);
|
||||
}
|
||||
RS485_SendStr(buf);
|
||||
RS485_SendStr((unsigned char*)"\n");
|
||||
if (dstAddr==RS485_BROADCAST_ADDRESS) {
|
||||
/* do not wait for a OK/NOK response for broadcast messages. The caller has to check with 'lastError' */
|
||||
res = ERR_OK;
|
||||
break; /* leave loop */
|
||||
} else {
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); /* give back some time for receiving a response */
|
||||
resp = WaitForResponse(timeoutMs, dstAddr, shellIO, rsIO);
|
||||
if (resp==RS485_RESPONSE_OK) {
|
||||
res = ERR_OK;
|
||||
break; /* fine, leave loop */
|
||||
} else if (resp==RS485_RESPONSE_TIMEOUT) { /* board did not respond? */
|
||||
res = ERR_BUSOFF; /* retry */
|
||||
} else if (resp==RS485_RESPONSE_NOK) { /* not ok, crc error? */
|
||||
res = ERR_CRC; /* retry */
|
||||
}
|
||||
}
|
||||
/* NOK or timeout */
|
||||
if (nofRetry==0) { /* tried enough */
|
||||
res = ERR_FAILED;
|
||||
break; /* leave loop */
|
||||
}
|
||||
nofRetry--; /* try again */
|
||||
} /* for */
|
||||
(void)xSemaphoreGiveRecursive(RS485_stdioMutex); /* give back mutex */
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
||||
uint8_t buf[16];
|
||||
|
||||
McuShell_SendStatusStr((unsigned char*)"rs", (unsigned char*)"RS-485 settings\r\n", io->stdOut);
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), RS485_GetAddress());
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
||||
McuShell_SendStatusStr((unsigned char*)" addr", buf, io->stdOut);
|
||||
McuShell_SendStatusStr((unsigned char*)" log", RS485_DoLogging?(unsigned char*)"on\r\n":(unsigned char*)"off\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
|
||||
McuShell_SendHelpStr((unsigned char*)"rs", (unsigned char*)"Group of RS-485 commands\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
McuShell_SendHelpStr((unsigned char*)" addr <addr>", (unsigned char*)"Set RS-485 address\r\n", io->stdOut);
|
||||
#endif
|
||||
McuShell_SendHelpStr((unsigned char*)" send <text>", (unsigned char*)"Send a text to the RS-485 bus\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" sendcmd <addr> <cmd>", (unsigned char*)"Send a shell command to the RS-485 address and check response\r\n", io->stdOut);
|
||||
McuShell_SendHelpStr((unsigned char*)" log on|off", (unsigned char*)"Log RS-485 bus activity to McuLog\r\n", io->stdOut);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t RS485_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
const unsigned char *p;
|
||||
int32_t val;
|
||||
|
||||
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "rs help")==0) {
|
||||
*handled = TRUE;
|
||||
return PrintHelp(io);
|
||||
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "rs status")==0)) {
|
||||
*handled = TRUE;
|
||||
return PrintStatus(io);
|
||||
} else if (McuUtility_strncmp((char*)cmd, "rs log ", sizeof("rs log ")-1)==0) {
|
||||
*handled = TRUE;
|
||||
p = cmd + sizeof("rs log ")-1;
|
||||
if (McuUtility_strcmp((char*)p, "on")==0) {
|
||||
RS485_DoLogging = true;
|
||||
return ERR_OK;
|
||||
} else if (McuUtility_strcmp((char*)p, "off")==0) {
|
||||
RS485_DoLogging = false;
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_FAILED;
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
} else if (McuUtility_strncmp((char*)cmd, "rs addr ", sizeof("rs addr ")-1)==0) {
|
||||
*handled = true;
|
||||
p = cmd + sizeof("rs addr ")-1;
|
||||
if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=0xff) {
|
||||
return NVMC_SetRS485Addr(val);
|
||||
}
|
||||
return ERR_FAILED;
|
||||
#endif
|
||||
} else if (McuUtility_strncmp((char*)cmd, "rs send ", sizeof("rs send ")-1)==0) {
|
||||
*handled = true;
|
||||
RS485_SendStr((unsigned char*)cmd+sizeof("rs send ")-1);
|
||||
RS485_SendStr((unsigned char*)("\n"));
|
||||
} else if (McuUtility_strncmp((char*)cmd, "rs sendcmd ", sizeof("rs sendcmd ")-1)==0) {
|
||||
*handled = true;
|
||||
p = cmd + sizeof("rs sendcmd ")-1;
|
||||
if (McuUtility_xatoi(&p, &val)==ERR_OK) { /* parse destination address */
|
||||
unsigned char buffer[McuShell_CONFIG_DEFAULT_SHELL_BUFFER_SIZE];
|
||||
|
||||
while (*p==' ') { /* skip leading spaces */
|
||||
p++;
|
||||
}
|
||||
if (*p=='"') { /* double-quoted command: it can contain multiple commands */
|
||||
if (McuUtility_ScanDoubleQuotedString(&p, buffer, sizeof(buffer))!=ERR_OK) {
|
||||
return ERR_FAILED;
|
||||
}
|
||||
p = buffer;
|
||||
}
|
||||
return RS485_SendCommand(val, (unsigned char*)p, 10000, 0, io, &RS485Parse_stdio); /* 10 seconds should be enough */
|
||||
}
|
||||
return ERR_FAILED;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static uint8_t CheckHeader(unsigned char *msg, const unsigned char **startCmd, uint8_t *sourceAddr, uint8_t *destinationAddr) {
|
||||
/* format is in the form "@<DST_ADDR> <SRC_ADDR> <CRC> cmd help" */
|
||||
const unsigned char *p;
|
||||
uint8_t dstAddr, srcAddr;
|
||||
uint8_t expected_crc, crc, res;
|
||||
unsigned char buf[42];
|
||||
|
||||
/* init with defaults in case of error */
|
||||
*sourceAddr = RS485_BROADCAST_ADDRESS;
|
||||
*destinationAddr = RS485_BROADCAST_ADDRESS;
|
||||
*startCmd = msg;
|
||||
if (*msg=='@') {
|
||||
p = msg+1; /* skip '@' */
|
||||
/* check for "@<DST_ADDR> <SRC_ADDR>" */
|
||||
if ( McuUtility_ScanHex8uNumberNoPrefix(&p, &dstAddr)==ERR_OK
|
||||
&& (dstAddr==RS485_GetAddress() || dstAddr==RS485_BROADCAST_ADDRESS) /* broadcast or matching destination address */
|
||||
&& McuUtility_ScanHex8uNumberNoPrefix(&p, &srcAddr)==ERR_OK /* get source address */
|
||||
)
|
||||
{
|
||||
*sourceAddr = srcAddr;
|
||||
*destinationAddr = dstAddr;
|
||||
/* check CRC */
|
||||
res = McuUtility_ScanHex8uNumberNoPrefix(&p, &crc);
|
||||
if (res!=ERR_OK) {
|
||||
return ERR_CRC;
|
||||
}
|
||||
expected_crc = CalcMsgCrc(msg);
|
||||
if (crc!=expected_crc) {
|
||||
if (dstAddr!=RS485_BROADCAST_ADDRESS) { /* only send back error if it was not a broadcast */
|
||||
McuUtility_strcpy(buf, sizeof(buf), (uint8_t*)"CRC_ERR 0x");
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), RS485_GetAddress());
|
||||
McuUtility_strcat(buf, sizeof(buf), (uint8_t*)": 0x");
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), crc);
|
||||
McuUtility_strcat(buf, sizeof(buf), (uint8_t*)" expected 0x");
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), expected_crc);
|
||||
McuUtility_chcat(buf, sizeof(buf), '\n');
|
||||
McuShell_SendStr(buf, RS485_stdio.stdErr);
|
||||
}
|
||||
return ERR_CRC;
|
||||
}
|
||||
*startCmd = p;
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
static void RS485Task(void *pv) {
|
||||
static uint8_t cmdBuf[McuShell_DEFAULT_SHELL_BUFFER_SIZE]; /* command line and text from the RS-485 bus */
|
||||
const unsigned char *startCmd;
|
||||
uint8_t srcAddr, dstAddr;
|
||||
uint8_t res, crc;
|
||||
uint8_t buf[32];
|
||||
unsigned char hex;
|
||||
bool reply;
|
||||
static uint8_t lastError = ERR_OK;
|
||||
|
||||
(void)pv; /* not used */
|
||||
McuLog_trace("Starting RS485 Task");
|
||||
#if PL_CONFIG_USE_WDT
|
||||
WDT_SetTaskHandle(WDT_REPORT_ID_TASK_RS485, xTaskGetCurrentTaskHandle());
|
||||
#endif
|
||||
cmdBuf[0] = '\0';
|
||||
for(;;) {
|
||||
while (!McuUart485_stdio.keyPressed()) { /* if nothing in input queue, give back some CPU time */
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
#if PL_CONFIG_USE_WDT
|
||||
WDT_Report(WDT_REPORT_ID_TASK_RS485, 10);
|
||||
#endif
|
||||
}
|
||||
if (McuShell_ReadCommandLine(cmdBuf, sizeof(cmdBuf), &RS485Parse_stdio)==ERR_OK) {
|
||||
reply = false;
|
||||
srcAddr = RS485_ILLEGAL_ADDRESS;
|
||||
dstAddr = RS485_ILLEGAL_ADDRESS;
|
||||
if (cmdBuf[0]=='@' && strlen((char*)cmdBuf)>sizeof("@dd ss cc ")-1) { /* have a valid message? */
|
||||
if (RS485_DoLogging) {
|
||||
McuLog_trace("Rx: %s", cmdBuf);
|
||||
}
|
||||
reply = false; /* default */
|
||||
res = CheckHeader(cmdBuf, &startCmd, &srcAddr, &dstAddr);
|
||||
if (res == ERR_CRC) { /* wrong crc */
|
||||
lastError = ERR_CRC;
|
||||
reply = true;
|
||||
} else if (res==ERR_OK) { /* header was ok */
|
||||
res = ERR_FAILED; /* set default return value */
|
||||
if (McuUtility_strcmp((char*)startCmd, (char*)" cmd lastError")==0) {
|
||||
reply = true;
|
||||
res = lastError; /* report back last error */
|
||||
lastError = ERR_OK; /* clear error */
|
||||
} else if (McuUtility_strcmp((char*)startCmd, (char*)" cmd idle")==0) {
|
||||
reply = true;
|
||||
#if 0 /* \TODO */
|
||||
if (STEPPER_IsIdle()) {
|
||||
res = ERR_OK; /* ERR_OK if board is idle */
|
||||
} else {
|
||||
res = ERR_FAILED; /* not idle */
|
||||
}
|
||||
#else
|
||||
res = ERR_FAILED; /* not idle */
|
||||
#endif
|
||||
} else if (McuUtility_strncmp((char*)startCmd, " cmd ", sizeof(" cmd ")-1)==0) { /* shell command? */
|
||||
McuUart485_ClearResponseQueue(); /* clear any pending response: we are going to parse a new command */
|
||||
startCmd += sizeof(" cmd ")-1;
|
||||
if (dstAddr==RS485_BROADCAST_ADDRESS) {
|
||||
res = SHELL_ParseCommandIO(startCmd, &RS485_stdioBroadcast, true); /* do not write anything back if broadcast */
|
||||
} else {
|
||||
res = SHELL_ParseCommandIO(startCmd, &RS485_stdio, true);
|
||||
}
|
||||
lastError = res; /* remember error status if we get asked later on */
|
||||
reply = true;
|
||||
} else if (McuUtility_strcmp((char*)startCmd, (char*)" OK")==0) {
|
||||
reply = false;
|
||||
} else if (McuUtility_strcmp((char*)startCmd, (char*)" NOK")==0) {
|
||||
reply = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* not starting with '@', print it ... */
|
||||
McuUtility_strcat(cmdBuf, sizeof(cmdBuf), (unsigned char*)"\r\n"); /* for the shell parser, the new-line has been removed. Add it again for output */
|
||||
SHELL_SendString((unsigned char *)cmdBuf); /* \TODO do not send directly to UART: instead, use a stdio which buffers the output */
|
||||
}
|
||||
cmdBuf[0] = '\0'; /* reset buffer for next iteration */
|
||||
/* send response back to sender */
|
||||
if (reply && dstAddr!=RS485_BROADCAST_ADDRESS) { /* normal message, send response. For broadcasts it is up to the caller to check the last error */
|
||||
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"@");
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), srcAddr);
|
||||
McuUtility_chcat(buf, sizeof(buf), ' ');
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), RS485_GetAddress());
|
||||
McuUtility_chcat(buf, sizeof(buf), ' ');
|
||||
McuUtility_strcatNum8Hex(buf, sizeof(buf), 0); /* dummy crc, will be replaced later */
|
||||
if (res==ERR_OK) {
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" OK");
|
||||
} else {
|
||||
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" NOK");
|
||||
}
|
||||
crc = CalcMsgCrc(buf);
|
||||
hex = (char)((crc>>4) & 0x0F);
|
||||
buf[sizeof("@dd ss ")-1] = (char)(hex + ((hex <= 9) ? '0' : ('A'-10)));
|
||||
hex = (char)(crc & 0x0F);
|
||||
buf[sizeof("@dd ss c")-1] = (char)(hex + ((hex <= 9) ? '0' : ('A'-10)));
|
||||
McuUtility_chcat(buf, sizeof(buf), '\n');
|
||||
RS485_SendStr(buf);
|
||||
}
|
||||
}
|
||||
} /* for */
|
||||
}
|
||||
|
||||
void RS485_Deinit(void) {
|
||||
McuUart485_Deinit();
|
||||
}
|
||||
|
||||
void RS485_Init(void) {
|
||||
McuUart485_Init();
|
||||
if (xTaskCreate(
|
||||
RS485Task, /* pointer to the task */
|
||||
"RS-485", /* task name for kernel awareness debugging */
|
||||
2000/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+4, /* initial priority */
|
||||
(TaskHandle_t*)NULL /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("Failed creating RS-485 task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
RS485_stdioMutex = xSemaphoreCreateRecursiveMutex();
|
||||
if (RS485_stdioMutex==NULL) { /* creation failed? */
|
||||
McuLog_fatal("Failed creating RS-485 Standard I/O mutex"); // GCOVR_EXCL_LINE
|
||||
for(;;); // GCOVR_EXCL_LINE
|
||||
}
|
||||
vQueueAddToRegistry(RS485_stdioMutex, "RS485StdIoMutex");
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_RS485 */
|
||||
61
pico-sensor/src/rs485.h
Normal file
61
pico-sensor/src/rs485.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef RS485_H_
|
||||
#define RS485_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "McuShell.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! special pre-defined node addresses */
|
||||
#define RS485_BROADCAST_ADDRESS (0x00)
|
||||
/*!< special broadcast address */
|
||||
#define RS485_ILLEGAL_ADDRESS (0xff)
|
||||
/*!< illegal/initialization value */
|
||||
|
||||
/*!
|
||||
* \brief Send a shell command to the RS-485 bus
|
||||
* \param dstAddr Destination node address
|
||||
* \param cmd The shell command string
|
||||
* \param timeoutMs timeout in milliseconds to wait for a response
|
||||
* \param nofRetry Number of retries
|
||||
* \param shellIO I/O handler of the calling shell, used for writing output of the command
|
||||
* \param rsIO I/O handler for the RS-485 bus, used to read incoming characters
|
||||
* \return Error code, or ERR_OK
|
||||
*/
|
||||
uint8_t RS485_SendCommand(uint8_t dstAddr, const unsigned char *cmd, int32_t timeoutMs, uint32_t nofRetry, McuShell_ConstStdIOType *shellIO, McuShell_ConstStdIOType *rsIO);
|
||||
|
||||
/*!
|
||||
* \brief Getter for RS-485 node address
|
||||
* \return address of node
|
||||
*/
|
||||
uint8_t RS485_GetAddress(void);
|
||||
|
||||
/*!
|
||||
* \brief Shell command line parser
|
||||
* \param cmd command to be parsed
|
||||
* \param handled if command was recognized
|
||||
* \param io I/O handler
|
||||
* \return Error code, or ERR_OK
|
||||
*/
|
||||
uint8_t RS485_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
|
||||
/*! \brief Module de-initialization */
|
||||
void RS485_Deinit(void);
|
||||
|
||||
/*! \brief Module initialization */
|
||||
void RS485_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* RS485_H_ */
|
||||
79
pico-sensor/src/sensor.c
Normal file
79
pico-sensor/src/sensor.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
#include "sensor.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuGDisplaySSD1306.h"
|
||||
#include "McuFontDisplay.h"
|
||||
#include "McuFontHelv18Bold.h"
|
||||
#if PL_CONFIG_USE_SHT31
|
||||
#include "McuSHT31.h"
|
||||
#elif PL_CONFIG_USE_SHT40
|
||||
#include "McuSHT40.h"
|
||||
#else
|
||||
#error "unknown sensor?"
|
||||
#endif
|
||||
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
|
||||
#include "McuSystemView.h"
|
||||
#endif
|
||||
|
||||
static float Sensor_temperature, Sensor_humidity;
|
||||
|
||||
float Sensor_GetTemperature(void) {
|
||||
return Sensor_temperature; /* technically no mutex required, as 32bit access in one instruction. But leave at least a comment. Mutex required if both sensor values need to be from the same time */
|
||||
}
|
||||
|
||||
float Sensor_GetHumidity(void) {
|
||||
return Sensor_humidity; /* technically no mutex required, as 32bit access in one instruction */
|
||||
}
|
||||
|
||||
static bool volatile wait = false;
|
||||
|
||||
static void sensorTask(void *pv) {
|
||||
uint8_t res;
|
||||
float temperature, humidity;
|
||||
|
||||
Sensor_temperature = Sensor_humidity = 0.0f; /* init */
|
||||
#if PL_CONFIG_USE_SHT31
|
||||
McuSHT31_Init();
|
||||
#elif PL_CONFIG_USE_SHT40
|
||||
McuSHT40_Init();
|
||||
#endif
|
||||
for(;;) {
|
||||
#if PL_CONFIG_USE_SHT31
|
||||
res = McuSHT31_ReadTempHum(&temperature, &humidity);
|
||||
#elif PL_CONFIG_USE_SHT40
|
||||
res = McuSHT40_ReadTempHum(&temperature, &humidity);
|
||||
#endif
|
||||
if (res==ERR_OK) {
|
||||
Sensor_temperature = temperature;
|
||||
Sensor_humidity = humidity;
|
||||
} else {
|
||||
McuLog_fatal("error reading SHT sensor.");
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void Sensor_Deinit(void) { // GCOVR_EXCL_LINE
|
||||
/* todo */ // GCOVR_EXCL_LINE
|
||||
} // GCOVR_EXCL_LINE
|
||||
|
||||
void Sensor_Init(void) {
|
||||
BaseType_t res;
|
||||
|
||||
res = xTaskCreate(sensorTask, "sensor", (2*1024)/sizeof(StackType_t), NULL, tskIDLE_PRIORITY+1, NULL);
|
||||
if (res!=pdPASS) {
|
||||
/* error! */
|
||||
for(;;) {} // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_SENSOR */
|
||||
32
pico-sensor/src/sensor.h
Normal file
32
pico-sensor/src/sensor.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SENSOR_H_
|
||||
#define SENSOR_H_
|
||||
|
||||
/*!
|
||||
* \brief Getter for the sensor temperature
|
||||
* \return Sensor temperature value in degree C
|
||||
*/
|
||||
float Sensor_GetTemperature(void);
|
||||
|
||||
/*!
|
||||
* \brief Getter for the sensor humidity
|
||||
* \return Sensor humidity value as % RH
|
||||
*/
|
||||
float Sensor_GetHumidity(void);
|
||||
|
||||
/*!
|
||||
* \brief Sensor module de-initialization
|
||||
*/
|
||||
void Sensor_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Sensor module initialization
|
||||
*/
|
||||
void Sensor_Init(void);
|
||||
|
||||
#endif /* SENSOR_H_ */
|
||||
535
pico-sensor/src/shell.c
Normal file
535
pico-sensor/src/shell.c
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
|
||||
#include "shell.h"
|
||||
#include "McuShell.h"
|
||||
#include "McuRTOS.h"
|
||||
#if PL_CONFIG_USE_RTT
|
||||
#include "McuRTT.h"
|
||||
#endif
|
||||
#if McuLib_CONFIG_CPU_IS_ARM_CORTEX_M
|
||||
#include "McuArmTools.h"
|
||||
#endif
|
||||
#include "McuShellUart.h"
|
||||
#include "McuTimeDate.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuUtility.h"
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
#include "buttons.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
#include "leds.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_BLINKY
|
||||
#include "blinky.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_USB_CDC
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_WIFI && McuLib_CONFIG_CPU_IS_ESP32
|
||||
#include "WiFi.h"
|
||||
#elif PL_CONFIG_USE_WIFI && PL_CONFIG_USE_PICO_W
|
||||
#include "PicoWiFi.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_PING
|
||||
#include "ping_shell.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_SERVER
|
||||
#include "udp_server_shell.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_CLIENT
|
||||
#include "udp_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
#include "mqtt_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
#include "ntp_client.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SENSOR
|
||||
#include "sensor.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SENSOR && PL_CONFIG_USE_SHT31
|
||||
#include "McuSHT31.h"
|
||||
#elif PL_CONFIG_USE_SENSOR && PL_CONFIG_USE_SHT40
|
||||
#include "McuSHT40.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NVMC
|
||||
#include "nvmc.h"
|
||||
#endif
|
||||
#if McuFlash_CONFIG_IS_ENABLED
|
||||
#include "McuFlash.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RS485
|
||||
#include "rs485.h"
|
||||
#include "McuUart485.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MININI
|
||||
#include "minIni/McuMinINI.h"
|
||||
#endif
|
||||
#if PL_HAS_RADIO
|
||||
#include "RNet/McuRNet.h"
|
||||
#include "RNet/RStdIO.h"
|
||||
#include "RNet_App.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_ROBO_REMOTE
|
||||
#include "robot.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_CHALLENGE
|
||||
#include "challenge.h"
|
||||
#endif
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MINI
|
||||
#include "minIni/McuMinINI.h"
|
||||
#endif
|
||||
#if PL_CONFIG_USE_TUD_CDC
|
||||
#include "McuShellCdcDevice.h"
|
||||
#endif
|
||||
#include "application.h"
|
||||
|
||||
/* table of shell parsers */
|
||||
static const McuShell_ParseCommandCallback CmdParserTable[] =
|
||||
{
|
||||
McuShell_ParseCommand,
|
||||
McuRTOS_ParseCommand,
|
||||
McuLog_ParseCommand,
|
||||
McuTimeDate_ParseCommand,
|
||||
#if PL_CONFIG_USE_BUTTONS
|
||||
BTN_ParseCommand,
|
||||
#endif
|
||||
#if McuLib_CONFIG_CPU_IS_ARM_CORTEX_M
|
||||
McuArmTools_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_WIFI && McuLib_CONFIG_CPU_IS_ESP32
|
||||
WiFi_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_WIFI && PL_CONFIG_USE_PICO_W
|
||||
PicoWiFi_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_CLIENT
|
||||
UDP_Client_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_UDP_SERVER
|
||||
UDP_Server_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_PING
|
||||
PING_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SENSOR && PL_CONFIG_USE_SHT31
|
||||
McuSHT31_ParseCommand,
|
||||
#elif PL_CONFIG_USE_SENSOR && PL_CONFIG_USE_SHT40
|
||||
McuSHT40_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RS485 && McuUart485_CONFIG_USE_RS_485
|
||||
McuUart485_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RS485 && PL_CONFIG_USE_RS485_SHELL
|
||||
RS485_ParseCommand,
|
||||
#endif
|
||||
#if PL_HAS_RADIO
|
||||
McuRNet_ParseCommand,
|
||||
RNETA_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_LEDS
|
||||
Leds_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_BLINKY
|
||||
Blinky_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_ROBO_REMOTE
|
||||
ROBOT_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_CHALLENGE
|
||||
Challenge_ParseCommand,
|
||||
#endif
|
||||
#if McuFlash_CONFIG_IS_ENABLED
|
||||
McuFlash_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MINI
|
||||
McuMinINI_ParseCommand,
|
||||
ini_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_MQTT_CLIENT
|
||||
MqttClient_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_NTP_CLIENT
|
||||
NtpClient_ParseCommand,
|
||||
#endif
|
||||
#if PL_CONFIG_USE_TUD_CDC
|
||||
McuShellCdcDevice_ParseCommand,
|
||||
#endif
|
||||
NULL /* Sentinel */
|
||||
};
|
||||
|
||||
typedef struct SHELL_IODesc {
|
||||
McuShell_ConstStdIOType *stdio;
|
||||
unsigned char *buf;
|
||||
size_t bufSize;
|
||||
} SHELL_IODesc;
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_RPxxxx && PL_CONFIG_USE_USB_CDC
|
||||
|
||||
static void cdc_StdIOReadChar(uint8_t *c) {
|
||||
int res;
|
||||
|
||||
res = getchar_timeout_us(500);
|
||||
if (res==-1) { /* no character present */
|
||||
*c = '\0';
|
||||
} else {
|
||||
*c = (uint8_t)res; /* return character */
|
||||
}
|
||||
}
|
||||
|
||||
bool cdc_StdIOKeyPressed(void) {
|
||||
return true; /* hack, don't know if there is any other way? */
|
||||
}
|
||||
|
||||
void cdc_StdIOSendChar(uint8_t ch) {
|
||||
putchar_raw(ch);
|
||||
}
|
||||
|
||||
/* default standard I/O struct */
|
||||
static McuShell_ConstStdIOType cdc_stdio = {
|
||||
.stdIn = (McuShell_StdIO_In_FctType)cdc_StdIOReadChar,
|
||||
.stdOut = (McuShell_StdIO_OutErr_FctType)cdc_StdIOSendChar,
|
||||
.stdErr = (McuShell_StdIO_OutErr_FctType)cdc_StdIOSendChar,
|
||||
.keyPressed = cdc_StdIOKeyPressed, /* if input is not empty */
|
||||
#if McuShell_CONFIG_ECHO_ENABLED
|
||||
.echoEnabled = false,
|
||||
#endif
|
||||
};
|
||||
static uint8_t cdc_DefaultShellBuffer[McuShell_DEFAULT_SHELL_BUFFER_SIZE]; /* default buffer which can be used by the application */
|
||||
#endif
|
||||
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
|
||||
#define SHELL_ESP32_UART_DEVICE (UART_NUM_0) /* Uart for bootloader and connection to robot */
|
||||
|
||||
static SemaphoreHandle_t SHELL_stdioMutex; /* mutex to protect access to ESP32 standard I/O */
|
||||
|
||||
static void Uart_SendString(const unsigned char *str) {
|
||||
size_t len;
|
||||
int written;
|
||||
|
||||
len = strlen((const char*)str);
|
||||
written = uart_write_bytes(SHELL_ESP32_UART_DEVICE, (const char*)str, len);
|
||||
if (written!=len) {
|
||||
McuLog_error("failed sending uart bytes");
|
||||
}
|
||||
}
|
||||
|
||||
static void Uart_SendChar(unsigned char ch) {
|
||||
uart_write_bytes(SHELL_ESP32_UART_DEVICE, &ch, 1);
|
||||
}
|
||||
|
||||
static void Uart_ReadChar(uint8_t *c) {
|
||||
unsigned char ch = '\0';
|
||||
int len = 0;
|
||||
|
||||
if (xSemaphoreTakeRecursive(SHELL_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
len = uart_read_bytes(SHELL_ESP32_UART_DEVICE, &ch, 1, 0);
|
||||
(void)xSemaphoreGiveRecursive(SHELL_stdioMutex); /* give back mutex */
|
||||
}
|
||||
if (len==0) {
|
||||
*c = '\0';
|
||||
} else {
|
||||
*c = ch;
|
||||
}
|
||||
}
|
||||
|
||||
static bool Uart_CharPresent(void) {
|
||||
size_t size=0;
|
||||
|
||||
if (xSemaphoreTakeRecursive(SHELL_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
uart_get_buffered_data_len(SHELL_ESP32_UART_DEVICE, &size);
|
||||
(void)xSemaphoreGiveRecursive(SHELL_stdioMutex); /* give back mutex */
|
||||
}
|
||||
return size!=0;
|
||||
}
|
||||
|
||||
static McuShell_ConstStdIOType Uart_stdio = {
|
||||
.stdIn = (McuShell_StdIO_In_FctType)Uart_ReadChar,
|
||||
.stdOut = (McuShell_StdIO_OutErr_FctType)Uart_SendChar,
|
||||
.stdErr = (McuShell_StdIO_OutErr_FctType)Uart_SendChar,
|
||||
.keyPressed = Uart_CharPresent, /* if input is not empty */
|
||||
#if McuShell_CONFIG_ECHO_ENABLED
|
||||
.echoEnabled = true,
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint8_t Uart_DefaultShellBuffer[McuShell_DEFAULT_SHELL_BUFFER_SIZE]; /* default buffer which can be used by the application */
|
||||
#endif /* McuLib_CONFIG_CPU_IS_ESP */
|
||||
|
||||
static const SHELL_IODesc ios[] =
|
||||
{
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
{&Uart_stdio, Uart_DefaultShellBuffer, sizeof(Uart_DefaultShellBuffer)},
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SHELL_UART
|
||||
{&McuShellUart_stdio, McuShellUart_DefaultShellBuffer, sizeof(McuShellUart_DefaultShellBuffer)},
|
||||
#endif
|
||||
#if PL_CONFIG_USE_USB_CDC
|
||||
{&cdc_stdio, cdc_DefaultShellBuffer, sizeof(cdc_DefaultShellBuffer)},
|
||||
#endif
|
||||
#if PL_CONFIG_USE_SHELL_CDC
|
||||
{&McuShellCdcDevice_stdio, McuShellCdcDevice_DefaultShellBuffer, sizeof(McuShellCdcDevice_DefaultShellBuffer)},
|
||||
#endif
|
||||
#if PL_CONFIG_USE_RTT
|
||||
{&McuRTT_stdio, McuRTT_DefaultShellBuffer, sizeof(McuRTT_DefaultShellBuffer)},
|
||||
#endif
|
||||
#if RNET_CONFIG_REMOTE_STDIO
|
||||
{&RSTDIO_stdio, RSTDIO_DefaultShellBuffer, sizeof(RSTDIO_DefaultShellBuffer)},
|
||||
#endif
|
||||
};
|
||||
|
||||
void SHELL_SendChar(unsigned char ch) {
|
||||
for(int i=0;i<sizeof(ios)/sizeof(ios[0]);i++) {
|
||||
McuShell_SendCh(ch, ios[i].stdio->stdOut);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SHELL_ParseCommand(unsigned char *cmd) {
|
||||
return McuShell_ParseWithCommandTable(cmd, McuShell_GetStdio(), CmdParserTable);
|
||||
}
|
||||
|
||||
void SHELL_SendString(const unsigned char *str) {
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
/* need to improve write speed, as writing character by character is too slow */
|
||||
Uart_SendString(str);
|
||||
#else
|
||||
for(int i=0;i<sizeof(ios)/sizeof(ios[0]);i++) {
|
||||
McuShell_SendStr(str, ios[i].stdio->stdOut);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SHELL_SendStringToIO(const unsigned char *str, McuShell_ConstStdIOType *io) {
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
if (io->stdOut == Uart_SendChar) { /* ESP32 UART? */
|
||||
/* if out channel is ESP32 UART: speed it up by sending whole buffer */
|
||||
Uart_SendString(str);
|
||||
} else { /* send it char by char */
|
||||
McuShell_SendStr(str, io->stdOut);
|
||||
}
|
||||
#else
|
||||
McuShell_SendStr(str, io->stdOut);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SHELL_ParseCommandIO(const unsigned char *command, McuShell_ConstStdIOType *io, bool silent) {
|
||||
if (io==NULL) { /* use a default */
|
||||
#if PL_CONFIG_USE_SHELL_UART
|
||||
io = &McuShellUart_stdio;
|
||||
#elif PL_CONFIG_USE_USB_CDC
|
||||
io = &cdc_stdio;
|
||||
#elif PL_CONFIG_USE_RTT
|
||||
io = &McuRTT_stdio;
|
||||
#else
|
||||
#error "no shell std IO?"
|
||||
#endif
|
||||
}
|
||||
return McuShell_ParseWithCommandTableExt(command, io, CmdParserTable, silent);
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_ROTOT_HAT
|
||||
/* ----------------- buffer handling for shell messages sent to ESP32 */
|
||||
static unsigned char *esp_io_buf; /* pointer to buffer */
|
||||
static size_t esp_io_buf_size; /* size of buffer */
|
||||
|
||||
static void esp_io_buf_SendChar(unsigned char ch) {
|
||||
McuUtility_chcat(esp_io_buf, esp_io_buf_size, ch);
|
||||
}
|
||||
|
||||
static void esp_io_buf_ReadChar(uint8_t *c) {
|
||||
*c = '\0';
|
||||
}
|
||||
|
||||
static bool esp_io_buf_CharPresent(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static McuShell_ConstStdIOType esp_stdio = {
|
||||
.stdIn = (McuShell_StdIO_In_FctType)esp_io_buf_ReadChar,
|
||||
.stdOut = (McuShell_StdIO_OutErr_FctType)esp_io_buf_SendChar,
|
||||
.stdErr = (McuShell_StdIO_OutErr_FctType)esp_io_buf_SendChar,
|
||||
.keyPressed = esp_io_buf_CharPresent, /* if input is not empty */
|
||||
#if McuShell_CONFIG_ECHO_ENABLED
|
||||
.echoEnabled = false, /* echo enabled for idf.py monitor */
|
||||
#endif
|
||||
};
|
||||
|
||||
void SHELL_SendToESPAndGetResponse(const unsigned char *msg, unsigned char *response, size_t responseSize) {
|
||||
esp_io_buf = response;
|
||||
esp_io_buf_size = responseSize;
|
||||
esp_io_buf[0] = '\0'; /* initialize buffer */
|
||||
McuLog_info("Sending to ESP Shell: %s", msg);
|
||||
McuShell_ParseWithCommandTableExt(msg, &esp_stdio, CmdParserTable, true); /* send to ESP32 shell */
|
||||
if (response[0]=='\0') { /* empty response? add a default */
|
||||
McuUtility_strcpy(response, responseSize, (unsigned char*)"OK"); /* default response */
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------*/
|
||||
void SHELL_SendToRobotAndGetResponse(const unsigned char *send, unsigned char *response, size_t responseSize) {
|
||||
unsigned char buffer[128]; /* buffer for sending command to robot */
|
||||
|
||||
/* build a frame around the message: that way the robot is able to recognize it */
|
||||
McuUtility_strcpy(buffer, sizeof(buffer), (unsigned char*)"@robot:cmd ");
|
||||
McuUtility_strcat(buffer, sizeof(buffer), send);
|
||||
McuUtility_strcat(buffer, sizeof(buffer), (unsigned char*)"!\r\n");
|
||||
SHELL_SendString(buffer); /* send to UART, which is read by the robot */
|
||||
/* get response */
|
||||
#if 1
|
||||
/* Important: this consumes directly all characters coming from the robot. That way the ESP32 shell does not get it.
|
||||
* A mutex is used to block the shell from getting the UART stream.
|
||||
*/
|
||||
#define TIMEOUT_MS (500) /* stop if we don't get new input after this timeout */
|
||||
int timeoutMs = TIMEOUT_MS;
|
||||
|
||||
*response = '\0';
|
||||
if (xSemaphoreTakeRecursive(SHELL_stdioMutex, portMAX_DELAY)==pdPASS) { /* take mutex */
|
||||
while (true) { /* breaks after timeout */
|
||||
if (!Uart_stdio.keyPressed()) { /* no input: wait for timeout */
|
||||
timeoutMs -= 50;
|
||||
if (timeoutMs<=0) {
|
||||
break; /* timeout */
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
} else { /* character available */
|
||||
unsigned char ch;
|
||||
Uart_stdio.stdIn(&ch);
|
||||
if (ch!='\r') { /* filter out '\r' in "\r\n" */
|
||||
McuUtility_chcat(response, responseSize, ch);
|
||||
}
|
||||
timeoutMs = TIMEOUT_MS; /* reset timeout */
|
||||
} /* if */
|
||||
} /* while */
|
||||
(void)xSemaphoreGiveRecursive(SHELL_stdioMutex); /* give back mutex */
|
||||
}
|
||||
if (*response=='\0') { /* if response is empty, send back at least an acknowledgment */
|
||||
McuUtility_strcpy(response, responseSize, (unsigned char*)"OK"); /* default response */
|
||||
}
|
||||
#else
|
||||
McuUtility_strcpy(response, responseSize, (unsigned char*)"OK"); /* default response */
|
||||
#endif
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_ROTOT_HAT */
|
||||
/* ----------------------------------------------------------------------*/
|
||||
|
||||
static void ShellTask(void *pvParameters) {
|
||||
int i;
|
||||
|
||||
(void)pvParameters; /* not used */
|
||||
McuLog_trace("started shell task");
|
||||
/* initialize buffers */
|
||||
for(i=0;i<sizeof(ios)/sizeof(ios[0]);i++) {
|
||||
ios[i].buf[0] = '\0';
|
||||
}
|
||||
for(;;) {
|
||||
/* process all I/Os */
|
||||
for(i=0;i<sizeof(ios)/sizeof(ios[0]);i++) {
|
||||
(void)McuShell_ReadAndParseWithCommandTable(ios[i].buf, ios[i].bufSize, ios[i].stdio, CmdParserTable);
|
||||
}
|
||||
#if PL_HAS_RADIO && RNET_CONFIG_REMOTE_STDIO
|
||||
#if PL_CONFIG_USE_SHELL_CDC
|
||||
RSTDIO_Print(McuShellCdcDevice_GetStdio()); /* dispatch incoming messages */
|
||||
#elif PL_CONFIG_USE_RTT
|
||||
RSTDIO_Print(McuRTT_GetStdio()); /* dispatch incoming messages */
|
||||
#endif
|
||||
#endif
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
} /* for */
|
||||
}
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
static void InitUart(void) {
|
||||
#define ESP32_UART_BUF_SIZE 512
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 0,
|
||||
};
|
||||
|
||||
/* Configure UART parameters */
|
||||
uart_param_config(SHELL_ESP32_UART_DEVICE, &uart_config);
|
||||
uart_set_pin(SHELL_ESP32_UART_DEVICE, GPIO_NUM_1, GPIO_NUM_3, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
|
||||
/* Install UART driver (we don't need an event queue here) */
|
||||
uart_driver_install(SHELL_ESP32_UART_DEVICE, ESP32_UART_BUF_SIZE*2, ESP32_UART_BUF_SIZE*2, 0, NULL, 0);
|
||||
uart_set_mode(SHELL_ESP32_UART_DEVICE, UART_MODE_UART);
|
||||
}
|
||||
#endif/* McuLib_CONFIG_CPU_IS_ESP32 */
|
||||
|
||||
static void ConfigureLogger(void) {
|
||||
#if McuLog_CONFIG_IS_ENABLED
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
McuLog_set_console(&Uart_stdio, 0);
|
||||
#elif PL_CONFIG_USE_RTT && PL_CONFIG_USE_SHELL_UART && McuLog_CONFIG_NOF_CONSOLE_LOGGER==2 /* both */
|
||||
McuLog_set_console(McuRTT_GetStdio(), 0);
|
||||
McuLog_set_console(&McuShellUart_stdio, 1);
|
||||
#elif PL_CONFIG_USE_RTT && PL_CONFIG_USE_USB_CDC && McuLog_CONFIG_NOF_CONSOLE_LOGGER==2 /* both */
|
||||
McuLog_set_console(McuRTT_GetStdio(), 0);
|
||||
McuLog_set_console(&cdc_stdio, 1);
|
||||
#elif PL_CONFIG_USE_RTT && PL_CONFIG_USE_TUD_CDC && McuLog_CONFIG_NOF_CONSOLE_LOGGER==2 /* both */
|
||||
McuLog_set_console(McuRTT_GetStdio(), 0);
|
||||
McuLog_set_console(McuShellCdcDevice_GetStdio(), 1);
|
||||
#elif PL_CONFIG_USE_RTT /* only RTT */
|
||||
McuLog_set_console(McuRTT_GetStdio(), 0);
|
||||
#elif PL_CONFIG_USE_SHELL_UART /* only UART */
|
||||
McuLog_set_console(&McuShellUart_stdio, 0);
|
||||
#elif PL_CONFIG_USE_TUD_CDC
|
||||
McuLog_set_console(McuShellCdcDevice_GetStdio(), 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void SHELL_Init(void) {
|
||||
BaseType_t res;
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
InitUart();
|
||||
|
||||
SHELL_stdioMutex = xSemaphoreCreateRecursiveMutex();
|
||||
if (SHELL_stdioMutex==NULL) { /* creation failed? */
|
||||
McuLog_fatal("Failed creating mutex");
|
||||
for(;;);
|
||||
}
|
||||
vQueueAddToRegistry(SHELL_stdioMutex, "ShellStdIoMutex");
|
||||
#endif
|
||||
|
||||
#if McuLib_CONFIG_CPU_IS_ESP32
|
||||
McuShell_SetStdio(&Uart_stdio);
|
||||
#elif McuLib_CONFIG_CPU_IS_RPxxxx && PL_CONFIG_USE_USB_CDC
|
||||
McuShell_SetStdio(&cdc_stdio); /* send to USB CDC */
|
||||
#elif McuLib_CONFIG_CPU_IS_RPxxxx && PL_CONFIG_USE_TUD_CDC
|
||||
McuShell_SetStdio(McuShellCdcDevice_GetStdio()); /* send to USB CDC */
|
||||
#elif PL_CONFIG_USE_RTT
|
||||
McuShell_SetStdio(McuRTT_GetStdio()); /* use RTT as the default */
|
||||
#else
|
||||
#error "need a standard I/O defined"
|
||||
#endif
|
||||
ConfigureLogger();
|
||||
res = xTaskCreate(ShellTask, "ShellTask", 4*1024/sizeof(StackType_t), NULL, tskIDLE_PRIORITY+4, NULL);
|
||||
if (res!=pdPASS) {
|
||||
McuLog_fatal("creating ShellTask task failed!"); // GCOVR_EXCL_LINE
|
||||
for(;;) {} // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
void SHELL_Deinit(void) { // GCOVR_EXCL_LINE
|
||||
McuShell_SetStdio(NULL); // GCOVR_EXCL_LINE
|
||||
} // GCOVR_EXCL_LINE
|
||||
|
||||
#endif /* PL_CONFIG_USE_SHELL */
|
||||
74
pico-sensor/src/shell.h
Normal file
74
pico-sensor/src/shell.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SHELL_H_
|
||||
#define SHELL_H_
|
||||
|
||||
#include "McuShell.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Send a string to all supported I/Os
|
||||
* \param str String to send
|
||||
*/
|
||||
void SHELL_SendString(const unsigned char *str);
|
||||
|
||||
/*!
|
||||
* \brief Send a string to a given IO. It tries to accelerate it by sending a buffer instead char by char.
|
||||
* \param str String to be sent.
|
||||
* \param io I/O to be used.
|
||||
*/
|
||||
void SHELL_SendStringToIO(const unsigned char *str, McuShell_ConstStdIOType *io);
|
||||
|
||||
/*!
|
||||
* \brief Send a character to all supported I/Os
|
||||
* \param ch Character to send
|
||||
*/
|
||||
void SHELL_SendChar(unsigned char ch);
|
||||
|
||||
/*!
|
||||
* \brief Parses a command with a given standard I/O channel
|
||||
* \param command Command to be parsed
|
||||
* \param io I/O to be used. If NULL, the standard default I/O will be used
|
||||
* \param silent If parsing shall be silent or not
|
||||
* \return Error code, ERR_OK for no error
|
||||
*/
|
||||
uint8_t SHELL_ParseCommandIO(const unsigned char *command, McuShell_ConstStdIOType *io, bool silent);
|
||||
|
||||
/*!
|
||||
* \brief Send a string to the ESP shell get a response back
|
||||
* \param send Message to send
|
||||
* \param response Where to store the response
|
||||
* \param responseSize Size of the response buffer
|
||||
*/
|
||||
void SHELL_SendToESPAndGetResponse(const unsigned char *send, unsigned char *response, size_t responseSize);
|
||||
|
||||
/*!
|
||||
* \brief Send a string to the robot get a response back
|
||||
* \param send Message to send
|
||||
* \param response Where to store the response
|
||||
* \param responseSize Size of the response buffer
|
||||
*/
|
||||
void SHELL_SendToRobotAndGetResponse(const unsigned char *send, unsigned char *response, size_t responseSize);
|
||||
|
||||
/*!
|
||||
* \brief Module de-initialization
|
||||
*/
|
||||
void SHELL_Deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Module Initialization
|
||||
*/
|
||||
void SHELL_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SHELL_H_ */
|
||||
273
pico-sensor/src/tcp_server.c
Normal file
273
pico-sensor/src/tcp_server.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_TCP_SERVER
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#include "McuRTOS.h"
|
||||
#include "McuLog.h"
|
||||
|
||||
static TaskHandle_t serverTaskHandle = NULL;
|
||||
|
||||
#define TCP_PORT 1234
|
||||
#define BUF_SIZE 8
|
||||
#define TEST_ITERATIONS 10
|
||||
#define POLL_TIME_S 5
|
||||
|
||||
typedef struct TCP_SERVER_T_ {
|
||||
struct tcp_pcb *server_pcb;
|
||||
struct tcp_pcb *client_pcb;
|
||||
bool complete;
|
||||
uint8_t buffer_sent[BUF_SIZE];
|
||||
uint8_t buffer_recv[BUF_SIZE];
|
||||
int sent_len;
|
||||
int recv_len;
|
||||
int run_count;
|
||||
} TCP_SERVER_T;
|
||||
|
||||
static TCP_SERVER_T *tcp_server_init(void) {
|
||||
TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T));
|
||||
if (!state) {
|
||||
McuLog_error("failed to allocate state");
|
||||
return NULL;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static err_t tcp_server_close(void *arg) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
err_t err = ERR_OK;
|
||||
if (state->client_pcb != NULL) {
|
||||
tcp_arg(state->client_pcb, NULL);
|
||||
tcp_poll(state->client_pcb, NULL, 0);
|
||||
tcp_sent(state->client_pcb, NULL);
|
||||
tcp_recv(state->client_pcb, NULL);
|
||||
tcp_err(state->client_pcb, NULL);
|
||||
err = tcp_close(state->client_pcb);
|
||||
if (err != ERR_OK) {
|
||||
McuLog_error("close failed %d, calling abort", err);
|
||||
tcp_abort(state->client_pcb);
|
||||
err = ERR_ABRT;
|
||||
}
|
||||
state->client_pcb = NULL;
|
||||
}
|
||||
if (state->server_pcb) {
|
||||
tcp_arg(state->server_pcb, NULL);
|
||||
tcp_close(state->server_pcb);
|
||||
state->server_pcb = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static err_t tcp_server_result(void *arg, int status) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (status == 0) {
|
||||
McuLog_info("test success");
|
||||
} else {
|
||||
McuLog_error("test failed %d", status);
|
||||
}
|
||||
state->complete = true;
|
||||
return tcp_server_close(arg);
|
||||
}
|
||||
|
||||
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
McuLog_info("tcp_server_sent %u bytes", len);
|
||||
state->sent_len += len;
|
||||
if (state->sent_len >= BUF_SIZE) {
|
||||
// We should get the data back from the client
|
||||
state->recv_len = 0;
|
||||
McuLog_info("Waiting for buffer from client");
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t tcp_server_send_data(void *arg, struct tcp_pcb *tpcb) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
for(int i=0; i< BUF_SIZE; i++) {
|
||||
state->buffer_sent[i] = '0'+i /*rand()*/;
|
||||
}
|
||||
state->sent_len = 0;
|
||||
McuLog_info("Writing %ld bytes to client", BUF_SIZE);
|
||||
// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
|
||||
// can use this method to cause an assertion in debug mode, if this method is called when
|
||||
// cyw43_arch_lwip_begin IS needed
|
||||
cyw43_arch_lwip_check();
|
||||
err_t err = tcp_write(tpcb, state->buffer_sent, BUF_SIZE, TCP_WRITE_FLAG_COPY);
|
||||
if (err != ERR_OK) {
|
||||
McuLog_error("Failed to write data %d", err);
|
||||
return tcp_server_result(arg, -1);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (!p) {
|
||||
return tcp_server_result(arg, -1);
|
||||
}
|
||||
// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
|
||||
// can use this method to cause an assertion in debug mode, if this method is called when
|
||||
// cyw43_arch_lwip_begin IS needed
|
||||
cyw43_arch_lwip_check();
|
||||
if (p->tot_len > 0) {
|
||||
McuLog_info("tcp_server_recv %d/%d err %d", p->tot_len, state->recv_len, err);
|
||||
// Receive the buffer
|
||||
const uint16_t buffer_left = BUF_SIZE - state->recv_len;
|
||||
state->recv_len += pbuf_copy_partial(p, state->buffer_recv + state->recv_len,
|
||||
p->tot_len > buffer_left ? buffer_left : p->tot_len, 0);
|
||||
tcp_recved(tpcb, p->tot_len);
|
||||
}
|
||||
pbuf_free(p);
|
||||
// Have we have received the whole buffer
|
||||
if (state->recv_len == BUF_SIZE) {
|
||||
// check it matches
|
||||
if (memcmp(state->buffer_sent, state->buffer_recv, BUF_SIZE) != 0) {
|
||||
McuLog_fatal("buffer mismatch\n");
|
||||
return tcp_server_result(arg, -1);
|
||||
}
|
||||
McuLog_info("tcp_server_recv buffer ok");
|
||||
// Test complete?
|
||||
state->run_count++;
|
||||
if (state->run_count >= TEST_ITERATIONS) {
|
||||
tcp_server_result(arg, 0);
|
||||
return ERR_OK;
|
||||
}
|
||||
// Send another buffer
|
||||
return tcp_server_send_data(arg, state->client_pcb);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) {
|
||||
McuLog_info("tcp_server_poll_fn");
|
||||
return tcp_server_result(arg, -1); /* no response is an error? */
|
||||
}
|
||||
|
||||
static void tcp_server_err(void *arg, err_t err) {
|
||||
if (err != ERR_ABRT) {
|
||||
McuLog_error("tcp_client_err_fn %d", err);
|
||||
tcp_server_result(arg, err);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
if (err != ERR_OK || client_pcb == NULL) {
|
||||
McuLog_error("Failure in accept");
|
||||
tcp_server_result(arg, err);
|
||||
return ERR_VAL;
|
||||
}
|
||||
McuLog_info("Client connected");
|
||||
state->client_pcb = client_pcb;
|
||||
tcp_arg(client_pcb, state);
|
||||
tcp_sent(client_pcb, tcp_server_sent);
|
||||
tcp_recv(client_pcb, tcp_server_recv);
|
||||
tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2);
|
||||
tcp_err(client_pcb, tcp_server_err);
|
||||
return tcp_server_send_data(arg, state->client_pcb);
|
||||
}
|
||||
|
||||
static bool tcp_server_open(void *arg) {
|
||||
TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
|
||||
McuLog_info("Starting server at %s on port %u", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
|
||||
|
||||
struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (!pcb) {
|
||||
McuLog_error("failed to create pcb");
|
||||
return false;
|
||||
}
|
||||
err_t err = tcp_bind(pcb, NULL, TCP_PORT);
|
||||
if (err) {
|
||||
McuLog_error("failed to bind to port %d\n");
|
||||
return false;
|
||||
}
|
||||
state->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||
if (!state->server_pcb) {
|
||||
McuLog_error("failed to listen\n");
|
||||
if (pcb) {
|
||||
tcp_close(pcb);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
tcp_arg(state->server_pcb, state);
|
||||
tcp_accept(state->server_pcb, tcp_server_accept);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void TcpServerTask(void *pv) {
|
||||
TCP_SERVER_T *state = tcp_server_init();
|
||||
|
||||
vTaskSuspend(NULL); /* suspend ourselves, will get resumed by WiFi task after connection is complete */
|
||||
state = tcp_server_init();
|
||||
if (!state) {
|
||||
McuLog_fatal("failed to initialize TCP server");
|
||||
for(;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
if (!tcp_server_open(state)) {
|
||||
McuLog_fatal("failed to open TCP server");
|
||||
tcp_server_result(state, -1);
|
||||
for(;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
while(!state->complete) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
if (state!=NULL) {
|
||||
free(state);
|
||||
state = NULL;
|
||||
}
|
||||
for(;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
|
||||
void TcpServer_Suspend(void) {
|
||||
if (serverTaskHandle!=NULL) {
|
||||
vTaskSuspend(serverTaskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void TcpServer_Resume(void) {
|
||||
if (serverTaskHandle!=NULL) {
|
||||
vTaskResume(serverTaskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
uint8_t TcpServer_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io) {
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void TcpServer_Init(void) {
|
||||
if (xTaskCreate(
|
||||
TcpServerTask, /* pointer to the task */
|
||||
"TcpServer", /* task name for kernel awareness debugging */
|
||||
4096/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+3, /* initial priority */
|
||||
&serverTaskHandle /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("failed creating task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_TCP_SERVER */
|
||||
39
pico-sensor/src/tcp_server.h
Normal file
39
pico-sensor/src/tcp_server.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef TCP_SERVER_H_
|
||||
#define TCP_SERVER_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PL_CONFIG_USE_SHELL
|
||||
#include "McuShell.h"
|
||||
|
||||
/*!
|
||||
* \brief Command line and shell handler
|
||||
* \param cmd The command to be parsed
|
||||
* \param handled If command has been recognized and handled
|
||||
* \param io I/O handler to be used
|
||||
* \return error code, otherwise ERR_OK
|
||||
*/
|
||||
uint8_t TcpServer_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io);
|
||||
#endif
|
||||
|
||||
void TcpServer_Suspend(void);
|
||||
|
||||
void TcpServer_Resume(void);
|
||||
|
||||
void TcpServer_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* TCP_SERVER_H_ */
|
||||
59
pico-sensor/src/tests/CMakeLists.txt
Normal file
59
pico-sensor/src/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
# file: Collect all files that need to be compiled.
|
||||
# You can use a GLOB function as shown here, or explicitly mention the specific files
|
||||
#file(GLOB FILES *.c *.h)
|
||||
|
||||
# Need to include CTest on every CMakeLists.txt which is going to use tests
|
||||
include(CTest)
|
||||
|
||||
set(THIS_LIBRARY_NAME srcTestsLib)
|
||||
|
||||
file(GLOB FILES
|
||||
*.c
|
||||
)
|
||||
|
||||
# add_library: With this declaration, you express the intent to build a library.
|
||||
# The first argument is the name of the library,
|
||||
# the second argument are the files that will be compiled to create your library.
|
||||
add_library(${THIS_LIBRARY_NAME} ${FILES})
|
||||
|
||||
# target_link_libraries: If you link with other libraries, list them here
|
||||
target_link_libraries(
|
||||
${THIS_LIBRARY_NAME}
|
||||
PRIVATE McuLib
|
||||
PRIVATE unityLib
|
||||
PRIVATE srcLib
|
||||
PRIVATE pico_cyw43_arch_lwip_sys_freertos
|
||||
)
|
||||
|
||||
# target_include_directories: Libraries need to publish their header files
|
||||
# so that you can import them in source code. This statement expresses where to find the files
|
||||
# - typically in an include directory of your projects.
|
||||
target_include_directories(
|
||||
${THIS_LIBRARY_NAME}
|
||||
PUBLIC
|
||||
.
|
||||
)
|
||||
#################################################################################
|
||||
# Note: --pc off --sp off are needed, if application runs from the ROM bootloader, might add --verbose
|
||||
set (JRUN_CTEST_COMMAND "$ENV{SEGGER_PATH}/JRun" --device RP2040_M0_0 --rtt -if SWD --pc off --sp off)
|
||||
|
||||
add_test(
|
||||
NAME Led
|
||||
COMMAND ${JRUN_CTEST_COMMAND} --args "led" ${TEST_EXECUTABLE}
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME Sensor
|
||||
COMMAND ${JRUN_CTEST_COMMAND} --args "sensor" ${TEST_EXECUTABLE}
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME DNS
|
||||
COMMAND ${JRUN_CTEST_COMMAND} --args "dns" ${TEST_EXECUTABLE}
|
||||
)
|
||||
|
||||
set_tests_properties(
|
||||
Led Sensor DNS
|
||||
PROPERTIES
|
||||
TIMEOUT 15
|
||||
)
|
||||
6588
pico-sensor/src/tests/fff.h
Normal file
6588
pico-sensor/src/tests/fff.h
Normal file
File diff suppressed because it is too large
Load Diff
35
pico-sensor/src/tests/test_dns_resolver.c
Normal file
35
pico-sensor/src/tests/test_dns_resolver.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_UNIT_TESTS
|
||||
#include "test_dns_resolver.h"
|
||||
#include "McuUtility.h"
|
||||
#include "dns_resolver.h"
|
||||
#include "unity/unity.h"
|
||||
#include "fff.h"
|
||||
|
||||
DEFINE_FFF_GLOBALS;
|
||||
FAKE_VOID_FUNC(DnsResolver_Init);
|
||||
|
||||
void TestDnsResolver_Test(void) {
|
||||
DnsResolver_info_t info;
|
||||
int res;
|
||||
unsigned char buf[16];
|
||||
|
||||
// DnsResolver_ResolveName(NULL, NULL, 0); // will fail and crash!
|
||||
res = DnsResolver_ResolveName("127.0.0.1", &info, 0);
|
||||
TEST_ASSERT_MESSAGE(res==0, "fixed IP does not need resolving");
|
||||
ip4addr_ntoa_r(&info.resolved_addr, buf, sizeof(buf));
|
||||
TEST_ASSERT(McuUtility_strcmp(buf, "127.0.0.1")==0);
|
||||
|
||||
TEST_ASSERT_MESSAGE(DnsResolver_ResolveName("server", &info, -1)==-2, "negative timeout shall return -2");
|
||||
|
||||
//DnsResolver_Init();
|
||||
//TEST_ASSERT_MESSAGE(DnsResolver_Init_fake.call_count==1, "call count shall be 1");
|
||||
}
|
||||
|
||||
#endif /* PL_CONFIG_USE_UNIT_TESTS */
|
||||
12
pico-sensor/src/tests/test_dns_resolver.h
Normal file
12
pico-sensor/src/tests/test_dns_resolver.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _TEST_DNS_RESOLVER_H__
|
||||
#define _TEST_DNS_RESOLVER_H__
|
||||
|
||||
void TestDnsResolver_Test(void);
|
||||
|
||||
#endif /* _TEST_DNS_RESOLVER_H__ */
|
||||
78
pico-sensor/src/tests/tests.c
Normal file
78
pico-sensor/src/tests/tests.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_UNIT_TESTS
|
||||
#include "tests.h"
|
||||
#include "unity.h"
|
||||
#include "McuUnity.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuShell.h"
|
||||
#include "McuRTT.h"
|
||||
#include "McuUtility.h"
|
||||
#include "McuLog.h"
|
||||
#include "test_sensor.h"
|
||||
#include "test_leds.h"
|
||||
#include "test_dns_resolver.h"
|
||||
|
||||
static void TestArgFailed(void) {
|
||||
TEST_ASSERT_MESSAGE(false, "wrong test_arg value");
|
||||
}
|
||||
|
||||
void Tests_Run(void) {
|
||||
int nofFailures;
|
||||
uint32_t test_arg = -1;
|
||||
int nofBytes;
|
||||
unsigned char buf[32];
|
||||
|
||||
nofBytes = McuUnity_RTT_GetArgs(buf, sizeof(buf));
|
||||
UNITY_BEGIN();
|
||||
if (nofBytes>0) {
|
||||
if (McuUtility_strcmp(buf, "led")==0) {
|
||||
RUN_TEST(TestLeds_OnOff);
|
||||
RUN_TEST(TestLeds_Toggle);
|
||||
} else if (McuUtility_strcmp(buf, "sensor")==0) {
|
||||
RUN_TEST(TestSensor_Temperature);
|
||||
RUN_TEST(TestSensor_Humidity);
|
||||
RUN_TEST(TestSensor_Both);
|
||||
} else if (McuUtility_strcmp(buf, "dns")==0) {
|
||||
RUN_TEST(TestDnsResolver_Test);
|
||||
} else {
|
||||
RUN_TEST(TestArgFailed);
|
||||
}
|
||||
} else {
|
||||
RUN_TEST(TestArgFailed);
|
||||
}
|
||||
nofFailures = UNITY_END();
|
||||
#if PL_CONFIG_USE_RTT
|
||||
McuUnity_Exit_JRun_RTT(nofFailures==0);
|
||||
#else
|
||||
McuUnity_Exit_LinkServer_Log(nofFailures==0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void TestTask(void *pv) {
|
||||
McuLog_info("starting test task");
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); /* give sensor some time */
|
||||
Tests_Run();
|
||||
vTaskDelete(NULL); /* terminate task */
|
||||
}
|
||||
|
||||
void Tests_Init(void) {
|
||||
if (xTaskCreate(
|
||||
TestTask, /* pointer to the task */
|
||||
"Test", /* task name for kernel awareness debugging */
|
||||
1500/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY, /* initial priority */
|
||||
(TaskHandle_t*)NULL /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("Failed creating task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_UNIT_TESTS */
|
||||
14
pico-sensor/src/tests/tests.h
Normal file
14
pico-sensor/src/tests/tests.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef TESTS_H_
|
||||
#define TESTS_H_
|
||||
|
||||
void Tests_Run(void);
|
||||
|
||||
void Tests_Init(void);
|
||||
|
||||
#endif /* TESTS_H_ */
|
||||
29
pico-sensor/src/timer.c
Normal file
29
pico-sensor/src/timer.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_TIME_DATE
|
||||
#include "timer.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuTimeDate.h"
|
||||
|
||||
static TimerHandle_t timer;
|
||||
|
||||
static void timerCallback(TimerHandle_t xTimer) {
|
||||
McuTimeDate_AddTick();
|
||||
}
|
||||
|
||||
void TMR_Init(void) {
|
||||
/* create auto-reload timer to update software RTC */
|
||||
timer = xTimerCreate("timer", pdMS_TO_TICKS(McuTimeDate_CONFIG_TICK_TIME_MS), pdTRUE, NULL, timerCallback);
|
||||
if (timer==NULL) {
|
||||
McuLog_fatal("Failed creating timer"); // GCOVR_EXCL_LINE
|
||||
return; // GCOVR_EXCL_LINE
|
||||
}
|
||||
xTimerStart(timer, 0);
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_TIME_DATE */
|
||||
21
pico-sensor/src/timer.h
Normal file
21
pico-sensor/src/timer.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MAIN_TIMER_H_
|
||||
#define MAIN_TIMER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Module initialization */
|
||||
void TMR_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_TIMER_H_ */
|
||||
143
pico-sensor/src/tusb_config.h
Normal file
143
pico-sensor/src/tusb_config.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "platform.h"
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Specific Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// #if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||
// // change to 1 if using pico-pio-usb as host controller for raspberry rp2040
|
||||
// #define CFG_TUH_RPI_PIO_USB 0
|
||||
// #define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB
|
||||
// #endif
|
||||
|
||||
// RHPort number used for host can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_TUH_RHPORT
|
||||
#define BOARD_TUH_RHPORT 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
#ifndef BOARD_TUH_MAX_SPEED
|
||||
#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#define CFG_TUSB_OS /*OPT_OS_FREERTOS*/ OPT_OS_PICO
|
||||
|
||||
// Enable device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Enable host stack with pio-usb if Pico-PIO-USB library is available
|
||||
#define CFG_TUH_ENABLED 1
|
||||
#define CFG_TUH_RPI_PIO_USB 1
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
// #define CFG_TUSB_DEBUG 0
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 1
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE 256
|
||||
|
||||
// CDC Endpoint transfer buffer size, more is faster
|
||||
#define CFG_TUD_CDC_EP_BUFSIZE 64
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// HOST CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Size of buffer to hold descriptors and other data used for enumeration
|
||||
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
||||
|
||||
#define CFG_TUH_HUB 1 /* number of supported hubs */
|
||||
#define CFG_TUH_MSC 0 /* nof mass storage class */
|
||||
#define CFG_TUH_VENDOR 0
|
||||
|
||||
// max device support (excluding hub device)
|
||||
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
|
||||
|
||||
//------------- HID -------------//
|
||||
#if PL_CONFIG_USE_USB_HOST_HID
|
||||
#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
|
||||
#define CFG_TUH_HID_EPIN_BUFSIZE 64
|
||||
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CDC -------------//
|
||||
#if PL_CONFIG_USE_USB_HOST_CDC
|
||||
#define CFG_TUH_CDC 1 /* nof communication device class */
|
||||
// Set Line Control state on enumeration/mounted:
|
||||
// DTR ( bit 0), RTS (bit 1)
|
||||
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
|
||||
|
||||
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
|
||||
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
|
||||
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
205
pico-sensor/src/udp_server.c
Normal file
205
pico-sensor/src/udp_server.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#if PL_CONFIG_USE_UDP_SERVER
|
||||
#include "udp_server.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#include "McuLib.h"
|
||||
#include "McuRTOS.h"
|
||||
#include "McuLog.h"
|
||||
#include "McuUtility.h"
|
||||
|
||||
#define CONFIG_EXAMPLE_IPV4 (1) /* 0: use IPV6; 1: use IPV4 */
|
||||
|
||||
static TaskHandle_t taskHandle = NULL; /* udp server task handle */
|
||||
|
||||
static int SendToSocket(int sock, const char *msg, const struct sockaddr *to, socklen_t tolen) {
|
||||
return sendto(sock, msg, McuUtility_strlen((char*)msg), 0, to, tolen);
|
||||
}
|
||||
|
||||
#if 1 && McuLib_CONFIG_CPU_IS_ESP32
|
||||
static void HandleIncomingUdpMessage(const char *rxMsg, int sock, struct sockaddr *source_addr_p, socklen_t source_addr_len) {
|
||||
#if 0
|
||||
unsigned char response[128];
|
||||
#else
|
||||
static unsigned char response[10*1024] = ""; // larger buffer for response
|
||||
unsigned char msg[McuShell_DEFAULT_SHELL_BUFFER_SIZE]; /* buffer for message */
|
||||
#define MSG_ESP_PREFIX_STR "@esp:"
|
||||
#endif
|
||||
int err;
|
||||
|
||||
McuLog_info("handling incoming udp message '%s'", rxMsg);
|
||||
McuUtility_strcpy(response, sizeof(response), (unsigned char*)"OK"); /* default response */
|
||||
/* check framing */
|
||||
if (McuUtility_strncmp(rxMsg, MSG_ESP_PREFIX_STR, sizeof(MSG_ESP_PREFIX_STR)-1)==0) { /* check prefix */
|
||||
size_t strLen = McuUtility_strlen(rxMsg);
|
||||
if (rxMsg[strLen-1]=='!') {
|
||||
/* send to ESP32 shell */
|
||||
#if 0
|
||||
SHELL_SendToESPAndGetResponse((unsigned char*)"led status", response, sizeof(response));
|
||||
#else
|
||||
/* copy first command */
|
||||
McuUtility_strcpy(msg, sizeof(msg), (unsigned char*)(rxMsg+strlen(MSG_ESP_PREFIX_STR)));
|
||||
msg[McuUtility_strlen((char*)msg)-1] = '\0'; /* replace '!' at the end */
|
||||
SHELL_SendToESPAndGetResponse(msg, response, sizeof(response));
|
||||
#endif
|
||||
} else {
|
||||
McuUtility_strcpy(response, sizeof(response), (unsigned char*)"'!' missing!");
|
||||
}
|
||||
}
|
||||
/* send back response */
|
||||
McuLog_info("Sending back response");
|
||||
err = SendToSocket(sock, (const char*)response, source_addr_p, source_addr_len);
|
||||
if (err < 0) {
|
||||
McuLog_error("Error occurred during sending: errno %d", errno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void udp_server_task(void *pvParameters) {
|
||||
#if 0
|
||||
char rx_buffer[128];
|
||||
#else
|
||||
static char rx_buffer[10*1024];
|
||||
#endif
|
||||
char addr_str[128];
|
||||
int addr_family;
|
||||
int ip_protocol;
|
||||
|
||||
vTaskSuspend(NULL); /* UDP_Server_Start() will wake me up */
|
||||
for(;;) {
|
||||
#if CONFIG_EXAMPLE_IPV4
|
||||
struct sockaddr_in dest_addr;
|
||||
|
||||
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY); /** 0.0.0.0 */
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = htons(UDP_SERVER_PORT);
|
||||
addr_family = AF_INET;
|
||||
ip_protocol = IPPROTO_IP;
|
||||
inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
|
||||
#else // IPV6
|
||||
struct sockaddr_in6 dest_addr;
|
||||
bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
|
||||
dest_addr.sin6_family = AF_INET6;
|
||||
dest_addr.sin6_port = htons(UDP_SERVER_PORT);PO
|
||||
addr_family = AF_INET6;
|
||||
ip_protocol = IPPROTO_IPV6;
|
||||
inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
|
||||
#endif
|
||||
|
||||
int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
|
||||
if (sock < 0) {
|
||||
McuLog_error("Unable to create socket: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
McuLog_info("Socket created");
|
||||
#if 0
|
||||
/* set a timeout for the socket */
|
||||
struct timeval to;
|
||||
|
||||
to.tv_sec = 5;
|
||||
to.tv_usec = 0;
|
||||
McuLog_info("setting socket timeout to %d sec", to.tv_sec);
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)) < 0) {
|
||||
McuLog_error("setting socket timeout failed");
|
||||
}
|
||||
#endif
|
||||
int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||||
if (err < 0) {
|
||||
McuLog_error("Socket unable to bind: errno %d", errno);
|
||||
}
|
||||
McuLog_info("Socket bound, port %d", UDP_SERVER_PORT);
|
||||
while (1) {
|
||||
McuLog_info("Waiting for data on port %d", UDP_SERVER_PORT);
|
||||
#if CONFIG_EXAMPLE_IPV4
|
||||
struct sockaddr source_addr; /* Large enough for both IPv4 or IPv6 */
|
||||
#else
|
||||
struct sockaddr_in6 source_addr; /* Large enough for IPv4 */
|
||||
#endif
|
||||
socklen_t socklen = sizeof(source_addr);
|
||||
|
||||
/* receive data (blocking): */
|
||||
int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer)-1, 0, (struct sockaddr *)&source_addr, &socklen);
|
||||
|
||||
/* Error occurred during receiving */
|
||||
if (len < 0) {
|
||||
McuLog_error("recvfrom failed: errno %d", errno);
|
||||
break;
|
||||
} else { /* Data received */
|
||||
/* Get the sender's ip address as string */
|
||||
#if CONFIG_EXAMPLE_IPV4
|
||||
if (source_addr.sa_family == PF_INET) {
|
||||
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
|
||||
}
|
||||
#else
|
||||
if (source_addr.sin6_family == PF_INET) {
|
||||
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
|
||||
} else if (source_addr.sin6_family == PF_INET6) {
|
||||
inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
|
||||
}
|
||||
#endif
|
||||
rx_buffer[len] = '\0'; /* Null-terminate whatever we received and treat like a string... */
|
||||
McuLog_info("Received %d bytes from %s:\n%s", len, addr_str, rx_buffer);
|
||||
|
||||
/* \TODO Need to handle messages and send them to the robot */
|
||||
#if 1
|
||||
/* send back response */
|
||||
unsigned char test_response[128];
|
||||
int err;
|
||||
|
||||
McuLog_info("Sending back response");
|
||||
McuUtility_strcpy(test_response, sizeof(test_response), (unsigned char*)"OK"); /* default response */
|
||||
if (McuUtility_strncmp(rx_buffer, "test", sizeof("test")-1)==0) { /* hard-coded command */
|
||||
McuUtility_strcpy(test_response, sizeof(test_response), (unsigned char*)"test_response");
|
||||
}
|
||||
err = SendToSocket(sock, (const char*)test_response, (struct sockaddr *)&source_addr, sizeof(source_addr));
|
||||
if (err < 0) {
|
||||
McuLog_error("Error occurred during sending: errno %d", errno);
|
||||
}
|
||||
#else
|
||||
HandleIncomingUdpMessage(rx_buffer, sock, (struct sockaddr *)&source_addr, sizeof(source_addr));
|
||||
#endif
|
||||
} /* if */
|
||||
} /* while */
|
||||
if (sock != -1) {
|
||||
McuLog_error("Shutting down socket and restarting...");
|
||||
shutdown(sock, 0);
|
||||
close(sock);
|
||||
}
|
||||
} /* for */
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void UdpServer_Resume(void) {
|
||||
if (taskHandle!=NULL) {
|
||||
vTaskResume(taskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void UdpServer_Suspend(void) {
|
||||
if (taskHandle!=NULL) {
|
||||
vTaskSuspend(taskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void UdpServer_Init(void) {
|
||||
if (xTaskCreate(
|
||||
udp_server_task, /* pointer to the task */
|
||||
"UdpServer", /* task name for kernel awareness debugging */
|
||||
(8*1024)/sizeof(StackType_t), /* task stack size */
|
||||
(void*)NULL, /* optional task startup argument */
|
||||
tskIDLE_PRIORITY+3, /* initial priority */
|
||||
&taskHandle /* optional task handle to create */
|
||||
) != pdPASS)
|
||||
{
|
||||
McuLog_fatal("failed creating task");
|
||||
for(;;){} /* error! probably out of memory */
|
||||
}
|
||||
}
|
||||
#endif /* PL_CONFIG_USE_UDP_SERVER */
|
||||
29
pico-sensor/src/udp_server.h
Normal file
29
pico-sensor/src/udp_server.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, 2023, Erich Styger
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SRC_UDP_SERVER_H_
|
||||
#define SRC_UDP_SERVER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UDP_SERVER_PORT (1234) /*!< default UDP server port */
|
||||
|
||||
/*! \brief Resume the UDP server */
|
||||
void UdpServer_Resume(void);
|
||||
|
||||
/*! \brief stop the UDP server */
|
||||
void UdpServer_Suspend(void);
|
||||
|
||||
/*! \brief Module initialization */
|
||||
void UdpServer_Init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SRC_UDP_SERVER_H_ */
|
||||
165
pico-sensor/src/usb_descriptors.c
Normal file
165
pico-sensor/src/usb_descriptors.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
* sekigon-gonnoc
|
||||
*
|
||||
* 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] 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) )
|
||||
|
||||
#define USB_VID 0xCafe
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_desc_device_t const desc_device =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = USB_VID,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
// 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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum
|
||||
{
|
||||
ITF_NUM_CDC = 0,
|
||||
ITF_NUM_CDC_DATA,
|
||||
ITF_NUM_TOTAL
|
||||
};
|
||||
|
||||
#define EPNUM_CDC_NOTIF 0x81
|
||||
#define EPNUM_CDC_OUT 0x02
|
||||
#define EPNUM_CDC_IN 0x82
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
|
||||
// full speed configuration
|
||||
uint8_t const desc_fs_configuration[] =
|
||||
{
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
|
||||
};
|
||||
|
||||
// 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)
|
||||
{
|
||||
(void) index; // for multiple configurations
|
||||
return desc_fs_configuration;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"123456789012", // 3: Serials, should use chip ID
|
||||
"TinyUSB CDC", // 4: CDC Interface
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if ( index == 0)
|
||||
{
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
}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 > 31 ) chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for(uint8_t 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] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
Reference in New Issue
Block a user