From 75d0ff533714631e5cfd1315ec9d227fe8877932 Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Mon, 15 Jun 2026 16:51:26 +0400 Subject: [PATCH 1/9] refactor(stm32f767): restructure project to support scalable demos and default to threadx_basic Signed-off-by: alieissa-commits --- .../STM32F767ZI-Nucleo/CMakeLists.txt | 101 +++++++++++++----- .../app/demos/threadx_basic/CMakeLists.txt | 42 ++++++++ .../app/{ => demos/threadx_basic}/main.c | 0 .../STM32F767ZI-Nucleo/app/ethernet_phy.c | 68 ------------ .../STM32F767ZI-Nucleo/app/ethernet_phy.h | 26 ----- .../STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 | 33 ++++++ .../STM32F767ZI-Nucleo/scripts/fetch_sdk.sh | 23 ++++ 7 files changed, 170 insertions(+), 123 deletions(-) create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt rename STMicroelectronics/STM32F767ZI-Nucleo/app/{ => demos/threadx_basic}/main.c (100%) delete mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.c delete mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.h diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt index 4a562f6e..cd3df456 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt @@ -24,9 +24,8 @@ include(utilities) # Define the Project project(stm32f767_threadx C CXX ASM) -# Define ThreadX User Configurations -set(TX_USER_FILE "${CMAKE_CURRENT_LIST_DIR}/lib/threadx/tx_user.h" CACHE STRING "Enable TX user configuration") -set(TX_USER_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}/lib/threadx") +# Select the active demo to build (threadx_basic) +set(ACTIVE_DEMO "threadx_basic" CACHE STRING "Active demo name to build: threadx_basic") # Set up standard paths for find modules set(STM32_FAMILY "F7") @@ -54,52 +53,96 @@ target_include_directories(${HAL_TARGET} ${CMAKE_CURRENT_LIST_DIR}/app ) +# Dynamic Middleware Auto-Detection +# Check if the active demo uses NetX Duo by looking for nx_user.h +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/app/demos/${ACTIVE_DEMO}/nx_user.h") + set(USE_NETXDUO ON) + set(NX_USER_FILE "${CMAKE_CURRENT_LIST_DIR}/app/demos/${ACTIVE_DEMO}/nx_user.h" CACHE STRING "Enable NetX Duo user configuration" FORCE) +else() + set(USE_NETXDUO OFF) +endif() + +# Check if the active demo has custom tx_user.h; otherwise fallback to app/tx_user.h +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/app/demos/${ACTIVE_DEMO}/tx_user.h") + set(TX_USER_FILE "${CMAKE_CURRENT_LIST_DIR}/app/demos/${ACTIVE_DEMO}/tx_user.h" CACHE STRING "Enable TX user configuration" FORCE) + set(TX_USER_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}/app/demos/${ACTIVE_DEMO}") +else() + set(TX_USER_FILE "${CMAKE_CURRENT_LIST_DIR}/lib/threadx/tx_user.h" CACHE STRING "Enable TX user configuration" FORCE) + set(TX_USER_FILE_DIR "${CMAKE_CURRENT_LIST_DIR}/lib/threadx") +endif() + # Compile ThreadX Kernel from root shared libs submodule set(THREADX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../libs/threadx") add_subdirectory(${THREADX_DIR} threadx) -# Create the Main Executable -set(EXE_TARGET stm32f767_threadx) +if(USE_NETXDUO) + # Compile NetX Duo TCP/IP Stack from root shared libs submodule + set(NXD_ENABLE_FILE_SERVERS OFF CACHE BOOL "Disable FileX dependency in NetX Duo" FORCE) + set(NETXDUO_DIR "${CMAKE_CURRENT_LIST_DIR}/../../libs/netxduo") + add_subdirectory(${NETXDUO_DIR} netxduo) +endif() -add_executable(${EXE_TARGET} +# 1. Define the Board BSP static library +add_library(board_bsp OBJECT app/startup/startup_stm32f767zitx.s app/startup/system_stm32f7xx.c app/startup/tx_initialize_low_level.S app/board_init.c app/console.c - app/ethernet_phy.c - app/main.c app/stm32f7xx_hal_msp.c app/sysmem.c app/syscalls.c ) -# Set compile definitions for our executable -target_compile_definitions(${EXE_TARGET} - PRIVATE - STM32F767xx - USE_HAL_DRIVER - STM32F7 +# Include paths for BSP +target_include_directories(board_bsp PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/app + ${CMSIS_INCLUDE_DIRS} + ${STM32HAL_INCLUDE_DIR} + ${TX_USER_FILE_DIR} +) + +# Compile definitions for BSP +target_compile_definitions(board_bsp PRIVATE + STM32F767xx + USE_HAL_DRIVER + STM32F7 ) -# Include paths -target_include_directories(${EXE_TARGET} - PRIVATE +# Link libraries for BSP (HAL and CMSIS) +target_link_libraries(board_bsp PUBLIC + stm32cubef7 +) + +# 2. Define conditional NetX Duo driver library target +if(USE_NETXDUO) + add_library(netx_stm32_driver OBJECT + lib/netxduo/nx_stm32_eth_driver.c + lib/netxduo/nx_stm32_phy_driver.c + lib/netxduo/lan8742.c + ) + + # NetX driver needs its local files, HAL, CMSIS, ThreadX, NetX Duo and the active demo folder (for nx_stm32_eth_config.h and nx_user.h) + target_include_directories(netx_stm32_driver PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/lib/netxduo + ${CMAKE_CURRENT_LIST_DIR}/app/demos/${ACTIVE_DEMO} ${CMAKE_CURRENT_LIST_DIR}/app ${CMSIS_INCLUDE_DIRS} ${STM32HAL_INCLUDE_DIR} - ${TX_USER_FILE_DIR} -) - -# Link libraries (includes ThreadX kernel and HAL object libraries) -target_link_libraries(${EXE_TARGET} - PRIVATE - threadx + ) + + target_compile_definitions(netx_stm32_driver PRIVATE + STM32F767xx + USE_HAL_DRIVER + STM32F7 + ) + + target_link_libraries(netx_stm32_driver PUBLIC + netxduo stm32cubef7 -) + ) +endif() -# Apply GCC linker script and print memory usage (utilities.cmake function) -set_target_linker(${EXE_TARGET} "${CMAKE_CURRENT_LIST_DIR}/app/startup/STM32F767ZITx_FLASH.ld") +# 3. Add the active demo subdirectory to build the executable target +add_subdirectory(app/demos/${ACTIVE_DEMO}) -# Post-build commands to generate raw .bin and .hex files -post_build(${EXE_TARGET}) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt new file mode 100644 index 00000000..9d269018 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available +# under the terms of the MIT license which is available at +# https://opensource.org/license/mit. +# +# SPDX-License-Identifier: MIT +# +# Contributors: +# Ali Eissa - 2026 version. + +add_executable(${PROJECT_NAME} + main.c +) + +# Set compile definitions for our executable +target_compile_definitions(${PROJECT_NAME} + PRIVATE + STM32F767xx + USE_HAL_DRIVER + STM32F7 +) + +# Include paths for the executable target +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Link libraries +target_link_libraries(${PROJECT_NAME} + PRIVATE + board_bsp + threadx + stm32cubef7 +) + +# Apply GCC linker script and print memory usage (utilities.cmake function) +set_target_linker(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../../startup/STM32F767ZITx_FLASH.ld") + +# Post-build commands to generate raw .bin and .hex files +post_build(${PROJECT_NAME}) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/main.c similarity index 100% rename from STMicroelectronics/STM32F767ZI-Nucleo/app/main.c rename to STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/main.c diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.c deleted file mode 100644 index 2f4649c0..00000000 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2026 Eclipse ThreadX contributors - * - * This program and the accompanying materials are made available - * under the terms of the MIT license which is available at - * https://opensource.org/license/mit. - * - * SPDX-License-Identifier: MIT - * - * Contributors: - * Ali Eissa - 2026 version. - */ - -#include "ethernet_phy.h" -#include "board_init.h" -#include - -/* Global Ethernet descriptors mapped to physical DMA sections */ -ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */ -ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */ - -ETH_TxPacketConfig TxConfig; -ETH_HandleTypeDef heth; - -static void MX_ETH_Init(void); - -/** - * @brief Initialize Ethernet peripheral MAC and RMII interfaces. - * - * @retval None - */ -void ethernet_phy_init(void) -{ - MX_ETH_Init(); -} - -/** - * @brief ETH Initialization Function - * - * @retval None - */ -static void MX_ETH_Init(void) -{ - static uint8_t MACAddr[6]; - - heth.Instance = ETH; - MACAddr[0] = 0x00; - MACAddr[1] = 0x80; - MACAddr[2] = 0xE1; - MACAddr[3] = 0x00; - MACAddr[4] = 0x00; - MACAddr[5] = 0x00; - heth.Init.MACAddr = &MACAddr[0]; - heth.Init.MediaInterface = HAL_ETH_RMII_MODE; - heth.Init.TxDesc = DMATxDscrTab; - heth.Init.RxDesc = DMARxDscrTab; - heth.Init.RxBuffLen = 1524; - - if (HAL_ETH_Init(&heth) != HAL_OK) - { - Error_Handler(); - } - - memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig)); - TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD; - TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; - TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT; -} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.h deleted file mode 100644 index af254b73..00000000 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/ethernet_phy.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2026 Eclipse ThreadX contributors - * - * This program and the accompanying materials are made available - * under the terms of the MIT license which is available at - * https://opensource.org/license/mit. - * - * SPDX-License-Identifier: MIT - * - * Contributors: - * Ali Eissa - 2026 version. - */ - -#ifndef _ETHERNET_PHY_H -#define _ETHERNET_PHY_H - -#include "stm32f7xx_hal.h" - -/* Global Ethernet Handle */ -extern ETH_HandleTypeDef heth; -extern ETH_TxPacketConfig TxConfig; - -/* Function Prototypes */ -void ethernet_phy_init(void); - -#endif // _ETHERNET_PHY_H diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 index 115c1774..a9dad200 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 +++ b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 @@ -15,6 +15,7 @@ $DriversDir = Join-Path $LibDir "Drivers" $HalDest = Join-Path $DriversDir "STM32F7xx_HAL_Driver" $CmsisDeviceDest = Join-Path $DriversDir "CMSIS/Device/ST/STM32F7xx" $CmsisIncludeDest = Join-Path $DriversDir "CMSIS/Include" +$NetxDriverDest = Join-Path $BoardDir "lib/netxduo" Write-Host "==========================================" Write-Host "STM32CubeF7 Standalone Driver Fetcher" @@ -26,10 +27,12 @@ Write-Host "" if (Test-Path $HalDest) { Remove-Item -Path $HalDest -Recurse -Force } if (Test-Path $CmsisDeviceDest) { Remove-Item -Path $CmsisDeviceDest -Recurse -Force } if (Test-Path $CmsisIncludeDest) { Remove-Item -Path $CmsisIncludeDest -Recurse -Force } +if (Test-Path $NetxDriverDest) { Remove-Item -Path $NetxDriverDest -Recurse -Force } New-Item -ItemType Directory -Path $HalDest -Force | Out-Null New-Item -ItemType Directory -Path $CmsisDeviceDest -Force | Out-Null New-Item -ItemType Directory -Path $CmsisIncludeDest -Force | Out-Null +New-Item -ItemType Directory -Path $NetxDriverDest -Force | Out-Null $TempDir = Join-Path $BoardDir "temp_clone" @@ -83,6 +86,36 @@ CleanTemp Write-Host "[OK] Up-to-date CMSIS Core Include headers copied" Write-Host "" +# 4. Fetch NetX Duo STM32 middleware drivers +Write-Host "[INFO] Cloning STM32 NetX Duo middleware drivers (depth=1)..." +git clone --depth 1 https://github.com/STMicroelectronics/stm32-mw-netxduo.git $TempDir +if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] Failed to clone NetX Duo middleware repository!" -ForegroundColor Red + CleanTemp + exit 1 +} +Copy-Item -Path "$TempDir/common/drivers/ethernet/nx_stm32_eth_driver.c" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/common/drivers/ethernet/nx_stm32_eth_driver.h" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/common/drivers/ethernet/nx_stm32_phy_driver.h" -Destination $NetxDriverDest -Force +CleanTemp +Write-Host "[OK] NetX Duo STM32 Ethernet drivers copied" +Write-Host "" + +# 5. Fetch LAN8742 PHY driver +Write-Host "[INFO] Cloning LAN8742 PHY driver (depth=1)..." +git clone --depth 1 https://github.com/STMicroelectronics/stm32-lan8742.git $TempDir +if ($LASTEXITCODE -ne 0) { + Write-Host "[ERROR] Failed to clone LAN8742 PHY repository!" -ForegroundColor Red + CleanTemp + exit 1 +} +Copy-Item -Path "$TempDir/lan8742.c" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/lan8742.h" -Destination $NetxDriverDest -Force +CleanTemp +Write-Host "[OK] LAN8742 PHY drivers copied" +Write-Host "" + Write-Host "==========================================" Write-Host "[SUCCESS] STM32CubeF7 drivers successfully fetched!" Write-Host "==========================================" diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh index b9038950..d9f67601 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh +++ b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh @@ -21,6 +21,7 @@ DRIVERS_DIR="${LIB_DIR}/Drivers" HAL_DEST="${DRIVERS_DIR}/STM32F7xx_HAL_Driver" CMSIS_DEVICE_DEST="${DRIVERS_DIR}/CMSIS/Device/ST/STM32F7xx" CMSIS_INCLUDE_DEST="${DRIVERS_DIR}/CMSIS/Include" +NETX_DRIVER_DEST="${BOARD_DIR}/lib/netxduo" echo "==========================================" echo "STM32CubeF7 Standalone Driver Fetcher (Linux)" @@ -32,11 +33,13 @@ echo "" rm -rf "${HAL_DEST}" rm -rf "${CMSIS_DEVICE_DEST}" rm -rf "${CMSIS_INCLUDE_DEST}" +rm -rf "${NETX_DRIVER_DEST}" # Re-create directories mkdir -p "${HAL_DEST}" mkdir -p "${CMSIS_DEVICE_DEST}" mkdir -p "${CMSIS_INCLUDE_DEST}" +mkdir -p "${NETX_DRIVER_DEST}" TEMP_DIR="${BOARD_DIR}/temp_clone" @@ -77,6 +80,26 @@ clean_temp echo "[OK] Up-to-date CMSIS Core Include headers copied" echo "" +# 4. Fetch NetX Duo STM32 middleware drivers +echo "[INFO] Cloning STM32 NetX Duo middleware drivers (depth=1)..." +git clone --depth 1 https://github.com/STMicroelectronics/stm32-mw-netxduo.git "${TEMP_DIR}" +cp -f "${TEMP_DIR}/common/drivers/ethernet/nx_stm32_eth_driver.c" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/common/drivers/ethernet/nx_stm32_eth_driver.h" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/common/drivers/ethernet/nx_stm32_phy_driver.h" "${NETX_DRIVER_DEST}/" +clean_temp +echo "[OK] NetX Duo STM32 Ethernet drivers copied" +echo "" + +# 5. Fetch LAN8742 PHY driver +echo "[INFO] Cloning LAN8742 PHY driver (depth=1)..." +git clone --depth 1 https://github.com/STMicroelectronics/stm32-lan8742.git "${TEMP_DIR}" +cp -f "${TEMP_DIR}/lan8742.c" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/lan8742.h" "${NETX_DRIVER_DEST}/" +clean_temp +echo "[OK] LAN8742 PHY drivers copied" +echo "" + echo "==========================================" echo "[SUCCESS] STM32CubeF7 drivers successfully fetched!" echo "==========================================" From 60a55be732b5ee3a3c7cd5e6fcf4c451141780af Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Fri, 19 Jun 2026 18:34:39 +0400 Subject: [PATCH 2/9] feat(stm32f767zi): refactored BSP and added NetX Duo Echo demo Signed-off-by: alieissa-commits --- .gitignore | 3 + .../STM32F767ZI-Nucleo/CMakeLists.txt | 3 + .../STM32F767ZI-Nucleo/README.md | 224 ++++++++++++++---- .../STM32F767ZI-Nucleo/app/board_init.c | 121 ++++++++++ .../STM32F767ZI-Nucleo/app/board_init.h | 4 + .../app/demos/netx_echo/CMakeLists.txt | 44 ++++ .../app/demos/netx_echo/main.c | 209 ++++++++++++++++ .../app/demos/netx_echo/nx_stm32_eth_config.h | 30 +++ .../app/demos/netx_echo/nx_user.h | 22 ++ .../app/demos/netx_echo/test_echo_simple.ps1 | 34 +++ .../app/demos/netx_echo/test_echo_simple.sh | 49 ++++ .../app/startup/STM32F767ZITx_FLASH.ld | 14 +- .../app/stm32f7xx_hal_msp.c | 21 +- .../STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 | 15 +- .../STM32F767ZI-Nucleo/scripts/fetch_sdk.sh | 15 +- 15 files changed, 742 insertions(+), 66 deletions(-) create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_stm32_eth_config.h create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_user.h create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.ps1 create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.sh diff --git a/.gitignore b/.gitignore index 9005e0fe..b70e1261 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ CTestTestfile.cmake *.log shared/lib/netxduo/* shared/lib/threadx/* +STMicroelectronics/STM32F767ZI-Nucleo/lib/stm32cubef7/ +STMicroelectronics/STM32F767ZI-Nucleo/lib/netxduo/ + diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt index cd3df456..1aac36be 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt @@ -112,8 +112,10 @@ target_compile_definitions(board_bsp PRIVATE # Link libraries for BSP (HAL and CMSIS) target_link_libraries(board_bsp PUBLIC stm32cubef7 + threadx ) + # 2. Define conditional NetX Duo driver library target if(USE_NETXDUO) add_library(netx_stm32_driver OBJECT @@ -135,6 +137,7 @@ if(USE_NETXDUO) STM32F767xx USE_HAL_DRIVER STM32F7 + STM32_ETH_HAL_LEGACY ) target_link_libraries(netx_stm32_driver PUBLIC diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/README.md b/STMicroelectronics/STM32F767ZI-Nucleo/README.md index d0370f63..1f4c0c57 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/README.md +++ b/STMicroelectronics/STM32F767ZI-Nucleo/README.md @@ -1,8 +1,19 @@ -# STM32F767ZI-Nucleo Board Enablement Demo +# STM32F767ZI-Nucleo Board Enablement Demos -This directory contains the Board Support Package (BSP) and build environment for running the Eclipse ThreadX RTOS on the **STMicroelectronics NUCLEO-F767ZI** evaluation board (ARM Cortex-M7). +This directory contains the Board Support Package (BSP) static library (`board_bsp`) and build configurations for running the **Eclipse ThreadX RTOS** and **NetX Duo TCP/IP stack** on the **STMicroelectronics NUCLEO-F767ZI** evaluation board (ARM Cortex-M7). -The project is structured with an isolated build framework, keeping all platform dependencies localized to ensure clean integration. +The project features a decoupled static BSP library that hides all low-level hardware initializations (clocks, GPIO, MPU, DMA descriptors, and interrupts) from the application code. + +--- + +## Supported Demos + +Use the `ACTIVE_DEMO` CMake variable to select which demo to compile: + +| Demo Name | Description | Targets | +| :--- | :--- | :--- | +| **`netx_echo`** *(Default)* | Dynamic network state machine monitoring cable hot-plugging, DHCP IP configuration, and a TCP Echo Server listening on port 7. | ThreadX, NetX Duo | +| **`threadx_basic`** | Multi-threaded RTOS demo showcasing thread scheduling, mechanical button debouncing, message queue logging, and interrupt-driven UART ring buffers. | ThreadX | --- @@ -10,39 +21,20 @@ The project is structured with an isolated build framework, keeping all platform * **Development Board**: NUCLEO-F767ZI (Nucleo-144) * **Microcontroller**: STM32F767ZIT6 (ARM Cortex-M7 running at 216 MHz) -* **Memory**: 2 MB Flash, 320 KB SRAM +* **Memory Layout**: 2 MB Flash, 512 KB SRAM + * *Note: The MPU maps `128 KB` of SRAM2 (starting at `0x20060000`) as non-cacheable/non-bufferable for Ethernet DMA descriptors and the packet pool.* * **Virtual COM Port**: USART3 (PD8/PD9) connected to ST-LINK debugger (115,200 baud, 8N1) +* **User Button**: PC13 (Blue button, Active High) * **Board LEDs**: * `LD1` (Green) - PB0 * `LD2` (Blue) - PB7 * `LD3` (Red) - PB14 -* **User Button**: PC13 (Blue button, Active High) - ---- - -## Demo Application Architecture - -The application runs a multi-threaded demo showcasing cooperation between ThreadX scheduling, queues, hardware interrupts, and status indicator peripherals: - -1. **Thread 1 (Green LED - Heartbeat)** (Priority 15): - * Toggles the green LED (`LD1`) continuously at `2 Hz` (250 ms active, 250 ms idle) to verify basic scheduler clock ticks. -2. **Thread 2 (User Button Scanner)** (Priority 10): - * Scans the blue User Button (`PC13`) using software-level mechanical debouncing (20 ms). - * Turns the Blue LED (`LD2`) ON when the button is held. - * Sends the current system tick count over a **ThreadX Message Queue** on a button press transition. -3. **Thread 3 (System Logger)** (Priority 10): - * Blocks efficiently on the Message Queue. - * Wakes up when a button press event is queued and prints a timestamped system log over the serial port. -4. **Thread 4 (Serial Terminal Input)** (Priority 5): - * Integrates an asynchronous, non-blocking **Interrupt Service Routine (ISR)** (`USART3_IRQHandler`) and a 256-byte volatile circular **ring buffer** to read keyboard input at 115,200 baud. - * Collects incoming characters, prints the received string on carriage return/newline, and flashes the Red LED (`LD3`) for 50 ms. - * Avoids the use of `HAL_GetTick()` to prevent CPU starvation when idle. --- ## Prerequisites -Before building, ensure you have the following cross-compilation tools installed on your PATH: +Before building, ensure you have the following cross-compilation tools installed on your system PATH: * **ARM GNU Toolchain** (`arm-none-eabi-gcc`) * **CMake** (version 3.5 or higher) @@ -54,42 +46,178 @@ Before building, ensure you have the following cross-compilation tools installed ## Quick Start Guide ### 1. Download SDK Dependencies -Run the driver fetcher script to clone the official, lightweight STMicroelectronics HAL drivers and CMSIS files locally: +Run the driver fetcher script to clone official, stock STMicroelectronics HAL drivers and CMSIS files locally: * **On Windows (PowerShell)**: ```powershell powershell -ExecutionPolicy Bypass -File .\scripts\fetch_sdk.ps1 ``` -* **On Linux (Bash - Ubuntu 24.04)**: +* **On Linux (Bash)**: ```bash chmod +x ./scripts/fetch_sdk.sh ./scripts/fetch_sdk.sh ``` -### 2. Build the Project -Run the compilation script to compile the libraries and application, linking the ThreadX RTOS kernel: +### 2. Configure and Build the Project -* **On Windows (PowerShell)**: - ```powershell - powershell -ExecutionPolicy Bypass -File .\scripts\build.ps1 -Rebuild - ``` -* **On Linux (Bash - Ubuntu 24.04)**: - ```bash - chmod +x ./scripts/build.sh - ./scripts/build.sh --rebuild - ``` +#### Option A: Build `netx_echo` (Default) +```bash +# Configure CMake +cmake -DACTIVE_DEMO=netx_echo -B build + +# Compile +cmake --build build +``` + +#### Option B: Build `threadx_basic` +```bash +# Configure CMake +cmake -DACTIVE_DEMO=threadx_basic -B build + +# Compile +cmake --build build +``` + +The raw binary files will be generated in `build/app/demos//stm32f767_threadx.bin`. --- ## Deployment & Verification -1. **Flash the Board**: - * Connect the NUCLEO-F767ZI board to your computer using a Micro-USB cable via the ST-LINK port. - * The board will mount as an external USB drive (e.g., `NUCLEO_F767ZI`). - * Copy the raw binary output file `build/stm32f767_threadx.bin` and paste it directly onto the board's drive. - * The ST-LINK status LED will blink rapidly while writing, then the board will auto-reboot. +### 1. Flash the Board +1. Connect the Nucleo board to your computer using a Micro-USB cable via the ST-LINK port. +2. The board will mount as an external USB drive (e.g., named `NOD_F767ZI` or `NUCLEO`). +3. Copy the compiled raw binary output file `build/app/demos//stm32f767_threadx.bin` and paste it directly onto the board's drive. +4. The ST-LINK status LED will blink rapidly while writing, then the board will auto-reboot. + +--- + +### 2. How to Run & Verify the `netx_echo` Demo +1. **Set Up Serial Monitor**: Open your serial terminal program (e.g., VS Code Serial Monitor, PuTTY, or Tera Term) to the virtual ST-LINK COM Port at **115,200 baud, 8N1**. +2. **Boot Unplugged**: Reset the board with the Ethernet cable disconnected. You should see the following log confirming the BSP initialization completed successfully and the network monitor is polling: + ```text + ========================================== + NetX Echo Demo Booted! + ========================================== + [HAL] Calling HAL_ETH_Init... + [HAL] HAL_ETH_Init returned status: 0 + [NetX] Initializing PHY transceiver... + [NetX] Waiting for Ethernet link (max 3s)... + [NetX] Ethernet link timeout! Cable connected? + [NetX] Packet pool created + [NetX] IP instance created + [NetX] Enabling ARP... + [NetX] Enabling TCP... + [NetX] Enabling UDP... + [NetX] Enabling ICMP... + [NetX] Creating DHCP Thread... + [NetX] tx_application_define completed + [NetX] Network Monitor Thread Started. + ``` +3. **Connect Cable**: Plug in your network Ethernet cable. The console will report the connection, initiate DHCP, and spawn the TCP Echo Server: + ```text + [NetX] Ethernet cable connected! Enabling link... + [NetX] Ethernet link is UP! Starting DHCP client... + [NetX] DHCP Success! + [NetX] IP Address : + [NetX] Subnet Mask: 255.255.255.0 + [Echo] TCP Echo Server listening on port 7 + ``` +4. **Run the Simple Echo Test**: Open a terminal on your computer and run one of the included scripts: + * **On Windows (PowerShell)**: + ```powershell + powershell -ExecutionPolicy Bypass -File "app/demos/netx_echo/test_echo_simple.ps1" + ``` + * **On Linux (Bash)**: + ```bash + chmod +x app/demos/netx_echo/test_echo_simple.sh + ./app/demos/netx_echo/test_echo_simple.sh + ``` + * **Expected Output**: + ```text + Connecting to on port 7... + Sending: 'Hello ThreadX NetX Echo!' + Received: 'Hello ThreadX NetX Echo!' + ``` +5. **Test Mid-Run Hot-Unplugging**: Disconnect the Ethernet cable. You will see `[NetX] Ethernet cable disconnected! Disabling link...` on the serial console, and the interface IP resets to `0.0.0.0`. Plug the cable back in, and it will re-acquire its configuration dynamically. + +--- + +### 3. How to Run & Verify the `threadx_basic` Demo +1. Open your serial terminal program at **115,200 baud, 8N1**. +2. Flash the `threadx_basic` binary to the board. +3. **Verify Heartbeat**: The Green LED (`LD1`) will blink continuously at `2 Hz` (250ms ON, 250ms OFF). +4. **Verify Button Scanner**: Press and hold the blue User Button on the board. The Blue LED (`LD2`) will light up immediately. In your serial terminal, a log message will print showing the system tick timestamp of the button transition. +5. **Verify UART Echo**: Type a word or string into your serial terminal and press `Enter`. The board will print the string back to you and flash the Red LED (`LD3`) for 50ms. + +--- -2. **Monitor Serial Console**: - * Connect a serial terminal program (VS Code Serial Monitor, PuTTY, or Tera Term) to the virtual ST-LINK COM Port. - * Configuration: **115,200 baud**, **8 data bits**, **1 stop bit**, **no parity**, **CRLF line endings** (`\r\n`). - * Press the blue button to check log telemetry, and type strings into the console to test the interrupt-driven echo thread! +## Developer Guide: How to Add a New Demo + +The decoupled architecture of the BSP (`board_bsp`) makes adding a new application or demo extremely simple: + +### Step 1: Create the Demo Directory +Create a new folder under `app/demos/` (e.g., `app/demos/my_demo/`). + +### Step 2: Write your Application Code +Create your `main.c`. Keep it clean by using the BSP initialization calls: +```c +#include "board_init.h" +#include "tx_api.h" + +int main(void) +{ + /* Initialize MPU, Clocks, GPIOs, and Serial Console */ + board_init(); + + /* Optional: Initialize Ethernet hardware if using networking */ + // board_ethernet_init(); + + /* Enter ThreadX Kernel */ + tx_kernel_enter(); + return 0; +} +``` + +### Step 3: Create `CMakeLists.txt` +Create a `CMakeLists.txt` in your demo folder: +```cmake +add_executable(${PROJECT_NAME} + main.c +) + +# Set compile definitions +target_compile_definitions(${PROJECT_NAME} + PRIVATE + STM32F767xx + USE_HAL_DRIVER + STM32F7 +) + +# Include paths +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Link with BSP, ThreadX, and optionally NetX Duo +target_link_libraries(${PROJECT_NAME} + PRIVATE + board_bsp + threadx + # netxduo # Uncomment if using network + # netx_stm32_driver # Uncomment if using network + stm32cubef7 +) + +# Apply linker script and print size +set_target_linker(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../../startup/STM32F767ZITx_FLASH.ld") +post_build(${PROJECT_NAME}) +``` + +### Step 4: Run your Demo +Configure CMake and build: +```bash +cmake -DACTIVE_DEMO=my_demo -B build +cmake --build build +``` diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c index 8788fbe3..53efb8a2 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c @@ -13,11 +13,20 @@ */ #include "board_init.h" +#include "tx_api.h" #include +#include /* Global UART handler */ UART_HandleTypeDef huart3; +/* Global Ethernet handle */ +ETH_HandleTypeDef heth; + +/* Place the Ethernet DMA descriptors in the .nx_data section (uncacheable memory) */ +__attribute__((section(".RxDecripSection"))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; +__attribute__((section(".TxDecripSection"))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; + void SystemClock_Config(void); void MPU_Config(void); void MX_GPIO_Init(void); @@ -188,8 +197,29 @@ void MPU_Config(void) MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); + + /* Configure the MPU for the NetXDuo/Ethernet DMA buffers in SRAM2 (0x20060000) */ + MPU_InitStruct.Number = MPU_REGION_NUMBER1; + MPU_InitStruct.BaseAddress = 0x20060000; + MPU_InitStruct.Size = MPU_REGION_SIZE_128KB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + + HAL_MPU_ConfigRegion(&MPU_InitStruct); + /* Enables the MPU */ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + + /* Enable I-Cache */ + SCB_EnableICache(); + + /* Enable D-Cache */ + SCB_EnableDCache(); } /** @@ -203,3 +233,94 @@ void Error_Handler(void) { } } + +void ETH_IRQHandler(void) +{ + HAL_ETH_IRQHandler(&heth); +} + + + +void board_ethernet_init(void) +{ + /* Unique MAC address generation based on STM32 96-bit Unique ID (UID) */ + static uint8_t MACAddr[6]; + uint32_t uid0 = HAL_GetUIDw0(); + + MACAddr[0] = 0x02; /* Locally administered unicast MAC address */ + MACAddr[1] = 0x00; + MACAddr[2] = (uint8_t)(uid0 >> 24); + MACAddr[3] = (uint8_t)(uid0 >> 16); + MACAddr[4] = (uint8_t)(uid0 >> 8); + MACAddr[5] = (uint8_t)(uid0); + + heth.Instance = ETH; + heth.Init.MACAddr = MACAddr; + heth.Init.MediaInterface = HAL_ETH_RMII_MODE; + heth.Init.TxDesc = DMATxDscrTab; + heth.Init.RxDesc = DMARxDscrTab; + heth.Init.RxBuffLen = 1524; + + printf("[HAL] Calling HAL_ETH_Init...\r\n"); + HAL_StatusTypeDef status = HAL_ETH_Init(&heth); + printf("[HAL] HAL_ETH_Init returned status: %d\r\n", status); + + /* Initialize the PHY transceiver and wait for the link to be established. + This ensures that when NetX Duo enables the interface during startup, + the hardware link is already up, avoiding driver initialization failures. */ + extern int32_t nx_eth_phy_init(void); + extern int32_t nx_eth_phy_get_link_state(void); + printf("[NetX] Initializing PHY transceiver...\r\n"); + if (nx_eth_phy_init() == 0) + { + printf("[NetX] Waiting for Ethernet link (max 3s)...\r\n"); + uint32_t retries = 300; /* 300 * 10ms = 3 seconds */ + while (nx_eth_phy_get_link_state() <= 1) + { + HAL_Delay(10); + retries--; + if (retries == 0) + { + printf("[NetX] Ethernet link timeout! Cable connected?\r\n"); + break; + } + } + if (nx_eth_phy_get_link_state() > 1) + { + printf("[NetX] Ethernet link up!\r\n"); + } + } + else + { + printf("[NetX] Failed to initialize PHY transceiver!\r\n"); + } +} + +/* Override the weak HAL_GetTick function to provide a working tick source + both before and after the ThreadX scheduler starts. */ +uint32_t HAL_GetTick(void) +{ + /* If the ThreadX scheduler is running, use the ThreadX time */ + if (tx_thread_identify() != TX_NULL) + { + return (uint32_t)tx_time_get(); + } + else + { + /* Return actual elapsed milliseconds based on SysTick hardware counter wrap-around. + Since SysTick counts down from LOAD to 0, a wrap-around occurs when the current + value is greater than the last checked value, or if COUNTFLAG is set. */ + static uint32_t last_val = 0; + static uint32_t ms_ticks = 0; + + uint32_t ctrl = SysTick->CTRL; + uint32_t val = SysTick->VAL; + + if ((ctrl & SysTick_CTRL_COUNTFLAG_Msk) || (val > last_val)) + { + ms_ticks++; + } + last_val = val; + return ms_ticks; + } +} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h index e48dff8a..7cb42fe0 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h @@ -36,7 +36,11 @@ extern UART_HandleTypeDef huart3; #define UartHandle huart3 +/* Global Ethernet handle */ +extern ETH_HandleTypeDef heth; + /* Define prototypes. */ void board_init(void); +void board_ethernet_init(void); #endif // _BOARD_INIT_H diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt new file mode 100644 index 00000000..f3672d6b --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available +# under the terms of the MIT license which is available at +# https://opensource.org/license/mit. +# +# SPDX-License-Identifier: MIT +# +# Contributors: +# Ali Eissa - 2026 version. + +add_executable(${PROJECT_NAME} + main.c +) + +# Set compile definitions for our executable +target_compile_definitions(${PROJECT_NAME} + PRIVATE + STM32F767xx + USE_HAL_DRIVER + STM32F7 +) + +# Include paths for the executable target +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Link libraries +target_link_libraries(${PROJECT_NAME} + PRIVATE + board_bsp + threadx + netxduo + netx_stm32_driver + stm32cubef7 +) + +# Apply GCC linker script and print memory usage (utilities.cmake function) +set_target_linker(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../../startup/STM32F767ZITx_FLASH.ld") + +# Post-build commands to generate raw .bin and .hex files +post_build(${PROJECT_NAME}) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c new file mode 100644 index 00000000..7e762986 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#include "board_init.h" +#include "tx_api.h" +#include "nx_api.h" +#include "nxd_dhcp_client.h" +#include + +#define DEMO_STACK_SIZE 2048 +#define PACKET_SIZE 1536 +#define PACKET_POOL_SIZE (PACKET_SIZE * 20) +#define ECHO_SERVER_PORT 7 + +#define ARP_CACHE_SIZE 1024 + +TX_THREAD dhcp_thread; +uint8_t dhcp_thread_stack[DEMO_STACK_SIZE]; + +TX_THREAD tcp_echo_thread; +uint8_t tcp_echo_stack[DEMO_STACK_SIZE]; + +uint8_t ip_thread_stack[DEMO_STACK_SIZE]; +uint8_t arp_cache_area[ARP_CACHE_SIZE]; + +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_DHCP dhcp_client; + +/* Place the NetX Duo packet pool in the .nx_data section (uncacheable memory) */ +__attribute__((section(".NetXPoolSection"))) uint8_t packet_pool_area[PACKET_POOL_SIZE]; + +extern VOID nx_stm32_eth_driver(NX_IP_DRIVER *driver_req_ptr); + +void dhcp_thread_entry(ULONG thread_input); +void tcp_echo_thread_entry(ULONG thread_input); + +int main(void) +{ + board_init(); + printf("\r\n==========================================\r\n"); + printf("NetX Echo Demo Booted!\r\n"); + printf("==========================================\r\n\r\n"); + + /* Initialize the Ethernet hardware, MAC, and wait for link to be established */ + board_ethernet_init(); + + tx_kernel_enter(); + return 0; +} + +void tx_application_define(void *first_unused_memory) +{ + (void)first_unused_memory; + + nx_system_initialize(); + + /* Create the packet pool in our uncacheable section */ + if (nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", + PACKET_SIZE, packet_pool_area, PACKET_POOL_SIZE) != NX_SUCCESS) { + printf("[NetX] Failed to create packet pool.\r\n"); + return; + } + printf("[NetX] Packet pool created\r\n"); + + /* Create the IP instance using the STM32 Ethernet driver */ + if (nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), + 0xFFFFFF00UL, &pool_0, nx_stm32_eth_driver, + ip_thread_stack, DEMO_STACK_SIZE, 1) != NX_SUCCESS) { + printf("[NetX] Failed to create IP instance.\r\n"); + return; + } + printf("[NetX] IP instance created\r\n"); + + /* Enable ARP, TCP, UDP, and ICMP */ + printf("[NetX] Enabling ARP...\r\n"); + nx_arp_enable(&ip_0, (VOID *)arp_cache_area, ARP_CACHE_SIZE); + printf("[NetX] Enabling TCP...\r\n"); + nx_tcp_enable(&ip_0); + printf("[NetX] Enabling UDP...\r\n"); + nx_udp_enable(&ip_0); + printf("[NetX] Enabling ICMP...\r\n"); + nx_icmp_enable(&ip_0); + + /* Start DHCP Thread */ + printf("[NetX] Creating DHCP Thread...\r\n"); + tx_thread_create(&dhcp_thread, "DHCP Thread", dhcp_thread_entry, 0, + dhcp_thread_stack, DEMO_STACK_SIZE, 2, 2, TX_NO_TIME_SLICE, TX_AUTO_START); + printf("[NetX] tx_application_define completed\r\n"); +} + +void dhcp_thread_entry(ULONG thread_input) +{ + ULONG ip_address; + ULONG network_mask; + ULONG actual_status; + UINT prev_link_up = NX_FALSE; + UINT tcp_server_started = NX_FALSE; + extern int32_t nx_eth_phy_get_link_state(void); + + /* Create the DHCP client instance once */ + nx_dhcp_create(&dhcp_client, &ip_0, "DHCP Client"); + + printf("[NetX] Network Monitor Thread Started.\r\n"); + + while (1) + { + /* Poll the physical link state */ + int32_t phy_state = nx_eth_phy_get_link_state(); + UINT curr_link_up = (phy_state > 1) ? NX_TRUE : NX_FALSE; + + if (curr_link_up != prev_link_up) + { + if (curr_link_up) + { + printf("[NetX] Ethernet cable connected! Enabling link...\r\n"); + UINT status = nx_ip_driver_direct_command(&ip_0, NX_LINK_ENABLE, &actual_status); + if (status == NX_SUCCESS || status == NX_ALREADY_ENABLED) + { + printf("[NetX] Ethernet link is UP! Starting DHCP client...\r\n"); + nx_dhcp_start(&dhcp_client); + + /* Wait up to 10 seconds for IP address resolution */ + if (nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &ip_address, 1000) == NX_SUCCESS) + { + nx_ip_address_get(&ip_0, &ip_address, &network_mask); + printf("[NetX] DHCP Success!\r\n"); + printf("[NetX] IP Address : %lu.%lu.%lu.%lu\r\n", + (ip_address >> 24) & 0xFF, (ip_address >> 16) & 0xFF, + (ip_address >> 8) & 0xFF, ip_address & 0xFF); + printf("[NetX] Subnet Mask: %lu.%lu.%lu.%lu\r\n", + (network_mask >> 24) & 0xFF, (network_mask >> 16) & 0xFF, + (network_mask >> 8) & 0xFF, network_mask & 0xFF); + } + else + { + printf("[NetX] DHCP Timeout! Using static IP 192.168.0.100\r\n"); + nx_dhcp_stop(&dhcp_client); + nx_ip_address_set(&ip_0, IP_ADDRESS(192, 168, 0, 100), 0xFFFFFF00UL); + } + + /* Start the TCP Echo Server thread if not already started */ + if (!tcp_server_started) + { + tx_thread_create(&tcp_echo_thread, "TCP Echo Thread", tcp_echo_thread_entry, 0, + tcp_echo_stack, DEMO_STACK_SIZE, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + tcp_server_started = NX_TRUE; + } + } + else + { + printf("[NetX] Failed to enable driver link: 0x%02x\r\n", status); + } + } + else + { + printf("[NetX] Ethernet cable disconnected! Disabling link...\r\n"); + nx_dhcp_stop(&dhcp_client); + nx_ip_driver_direct_command(&ip_0, NX_LINK_DISABLE, &actual_status); + /* Reset IP address to 0.0.0.0 */ + nx_ip_address_set(&ip_0, IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL); + } + prev_link_up = curr_link_up; + } + + tx_thread_sleep(100); /* Poll every 1 second (100 ticks) */ + } +} + +void tcp_echo_thread_entry(ULONG thread_input) +{ + NX_TCP_SOCKET echo_socket; + NX_PACKET *packet_ptr; + + nx_tcp_socket_create(&ip_0, &echo_socket, "Echo Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 512, NX_NULL, NX_NULL); + + printf("[Echo] TCP Echo Server listening on port %d\r\n", ECHO_SERVER_PORT); + + while (1) { + if (nx_tcp_server_socket_listen(&ip_0, ECHO_SERVER_PORT, &echo_socket, 5, NX_NULL) != NX_SUCCESS) { + nx_tcp_server_socket_unlisten(&ip_0, ECHO_SERVER_PORT); + continue; + } + + if (nx_tcp_server_socket_accept(&echo_socket, NX_WAIT_FOREVER) == NX_SUCCESS) { + printf("[Echo] Client connected.\r\n"); + + while (nx_tcp_socket_receive(&echo_socket, &packet_ptr, NX_WAIT_FOREVER) == NX_SUCCESS) { + /* Echo the packet back */ + nx_tcp_socket_send(&echo_socket, packet_ptr, NX_WAIT_FOREVER); + } + + printf("[Echo] Client disconnected.\r\n"); + nx_tcp_socket_disconnect(&echo_socket, NX_WAIT_FOREVER); + nx_tcp_server_socket_unaccept(&echo_socket); + } + nx_tcp_server_socket_unlisten(&ip_0, ECHO_SERVER_PORT); + } +} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_stm32_eth_config.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_stm32_eth_config.h new file mode 100644 index 00000000..9f64d9f0 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_stm32_eth_config.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#ifndef NX_STM32_ETH_CONFIG_H +#define NX_STM32_ETH_CONFIG_H + +#include "stm32f7xx_hal.h" +#include "lan8742.h" + +extern ETH_HandleTypeDef heth; +#define eth_handle heth + +/* Define the PHY physical address */ +#define LAN8742_PHY_ADDRESS 0 + +/* This define enables the call of nx_eth_init() from the interface layer.*/ +/* #define NX_DRIVER_ETH_HW_IP_INIT */ +void nx_eth_init(void); + +#endif /* NX_STM32_ETH_CONFIG_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_user.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_user.h new file mode 100644 index 00000000..6eb41c8e --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/nx_user.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + + #ifndef NX_USER_H +#define NX_USER_H + +#define NX_DISABLE_IPV6 +#define NX_ENABLE_INTERFACE_CAPABILITY +#define NX_PHYSICAL_HEADER 16 +#define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT + +#endif /* NX_USER_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.ps1 b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.ps1 new file mode 100644 index 00000000..6924b802 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.ps1 @@ -0,0 +1,34 @@ +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available +# under the terms of the MIT license which is available at +# https://opensource.org/license/mit. +# +# SPDX-License-Identifier: MIT +# +# Contributors: +# Ali Eissa - 2026 version. + +param ( + [string]$IP = "192.168.0.100" +) + +Write-Host "Connecting to $IP on port 7..." +try { + $client = New-Object System.Net.Sockets.TcpClient($IP, 7) + $stream = $client.GetStream() + $writer = New-Object System.IO.StreamWriter($stream) + $reader = New-Object System.IO.StreamReader($stream) + + $msg = "Hello ThreadX NetX Echo!" + Write-Host "Sending: '$msg'" + $writer.WriteLine($msg) + $writer.Flush() + + $response = $reader.ReadLine() + Write-Host "Received: '$response'" +} catch { + Write-Error "Failed to connect or communicate: $_" +} finally { + if ($client) { $client.Close() } +} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.sh b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.sh new file mode 100644 index 00000000..986b95ca --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/test_echo_simple.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available +# under the terms of the MIT license which is available at +# https://opensource.org/license/mit. +# +# SPDX-License-Identifier: MIT +# +# Contributors: +# Ali Eissa - 2026 version. + +IP=${1:-"192.168.0.100"} +PORT=7 +MSG="Hello ThreadX NetX Echo!" + +echo "Connecting to $IP on port $PORT..." + +# Check if netcat is installed +if command -v nc >/dev/null 2>&1; then + # Use netcat with a 2-second timeout to send the message and read the echo + RESPONSE=$(echo "$MSG" | nc -w 2 "$IP" "$PORT") + if [ $? -eq 0 ] && [ ! -z "$RESPONSE" ]; then + echo "Sending: '$MSG'" + echo "Received: '$RESPONSE'" + else + echo "Error: Failed to receive echo response. Is the server running?" + exit 1 + fi +else + # Fallback to Python if netcat is not available (standard on almost all Linux distros) + echo "netcat (nc) not found, falling back to python3..." + python3 -c " +import socket, sys +try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(2.0) + s.connect(('$IP', $PORT)) + s.sendall(b'$MSG\n') + data = s.recv(1024) + print('Sending: $MSG') + print('Received: ' + data.decode().strip()) +except Exception as e: + print('Error:', e) + sys.exit(1) +finally: + s.close() +" +fi diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/startup/STM32F767ZITx_FLASH.ld b/STMicroelectronics/STM32F767ZI-Nucleo/app/startup/STM32F767ZITx_FLASH.ld index ad892409..2d3db60d 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/startup/STM32F767ZITx_FLASH.ld +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/startup/STM32F767ZITx_FLASH.ld @@ -31,7 +31,7 @@ ENTRY(Reset_Handler) _vectors = g_pfnVectors; /* Highest address of the user mode stack */ -_estack = 0x20050000; /* end of RAM */ +_estack = 0x20080000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ _Min_Heap_Size = 0x200; /* required amount of heap */ _Min_Stack_Size = 0x400; /* required amount of stack */ @@ -40,7 +40,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K -RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K } /* Define output sections */ @@ -141,6 +141,16 @@ SECTIONS __RAM_segment_used_end__ = _ebss; } >RAM + .nx_data 0x20060000 (NOLOAD): + { + . = ALIGN(4); + *(.RxDecripSection) + *(.TxDecripSection) + *(.RxArraySection) + *(.NetXPoolSection) + . = ALIGN(4); + } >RAM + /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : { diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c index 9ae84075..d17dc1da 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c @@ -90,8 +90,16 @@ void HAL_ETH_MspInit(ETH_HandleTypeDef* heth) /* USER CODE BEGIN ETH_MspInit 0 */ /* USER CODE END ETH_MspInit 0 */ + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + /* Select RMII Mode */ + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; + /* Peripheral clock enable */ - __HAL_RCC_ETH_CLK_ENABLE(); + __HAL_RCC_ETHMAC_CLK_ENABLE(); + __HAL_RCC_ETHMACTX_CLK_ENABLE(); + __HAL_RCC_ETHMACRX_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); @@ -111,33 +119,34 @@ void HAL_ETH_MspInit(ETH_HandleTypeDef* heth) GPIO_InitStruct.Pin = RMII_MDC_Pin|RMII_RXD0_Pin|RMII_RXD1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = RMII_REF_CLK_Pin|RMII_MDIO_Pin|RMII_CRS_DV_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = RMII_TXD1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = RMII_TX_EN_Pin|RMII_TXD0_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /* USER CODE BEGIN ETH_MspInit 1 */ - + HAL_NVIC_SetPriority(ETH_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); /* USER CODE END ETH_MspInit 1 */ } diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 index a9dad200..3f7102c1 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 +++ b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 @@ -88,16 +88,21 @@ Write-Host "" # 4. Fetch NetX Duo STM32 middleware drivers Write-Host "[INFO] Cloning STM32 NetX Duo middleware drivers (depth=1)..." -git clone --depth 1 https://github.com/STMicroelectronics/stm32-mw-netxduo.git $TempDir +git clone --depth 1 https://github.com/STMicroelectronics/x-cube-azrtos-f7.git $TempDir if ($LASTEXITCODE -ne 0) { Write-Host "[ERROR] Failed to clone NetX Duo middleware repository!" -ForegroundColor Red CleanTemp exit 1 } -Copy-Item -Path "$TempDir/common/drivers/ethernet/nx_stm32_eth_driver.c" -Destination $NetxDriverDest -Force -Copy-Item -Path "$TempDir/common/drivers/ethernet/nx_stm32_eth_driver.h" -Destination $NetxDriverDest -Force -Copy-Item -Path "$TempDir/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" -Destination $NetxDriverDest -Force -Copy-Item -Path "$TempDir/common/drivers/ethernet/nx_stm32_phy_driver.h" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_driver.c" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_driver.h" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_phy_driver.h" -Destination $NetxDriverDest -Force + +# ST modified the HAL ETH driver to match the new H7-style API for NetX Duo, so we must overwrite the default ones +Copy-Item -Path "$TempDir/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_eth.c" -Destination "$HalDest/Src" -Force +Copy-Item -Path "$TempDir/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_eth.h" -Destination "$HalDest/Inc" -Force + CleanTemp Write-Host "[OK] NetX Duo STM32 Ethernet drivers copied" Write-Host "" diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh index d9f67601..443db778 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh +++ b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh @@ -82,11 +82,16 @@ echo "" # 4. Fetch NetX Duo STM32 middleware drivers echo "[INFO] Cloning STM32 NetX Duo middleware drivers (depth=1)..." -git clone --depth 1 https://github.com/STMicroelectronics/stm32-mw-netxduo.git "${TEMP_DIR}" -cp -f "${TEMP_DIR}/common/drivers/ethernet/nx_stm32_eth_driver.c" "${NETX_DRIVER_DEST}/" -cp -f "${TEMP_DIR}/common/drivers/ethernet/nx_stm32_eth_driver.h" "${NETX_DRIVER_DEST}/" -cp -f "${TEMP_DIR}/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" "${NETX_DRIVER_DEST}/" -cp -f "${TEMP_DIR}/common/drivers/ethernet/nx_stm32_phy_driver.h" "${NETX_DRIVER_DEST}/" +git clone --depth 1 https://github.com/STMicroelectronics/x-cube-azrtos-f7.git "${TEMP_DIR}" +cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_driver.c" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_driver.h" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_phy_driver.h" "${NETX_DRIVER_DEST}/" + +# ST modified the HAL ETH driver to match the new H7-style API for NetX Duo, so we must overwrite the default ones +cp -f "${TEMP_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_eth.c" "${HAL_DEST}/Src/" +cp -f "${TEMP_DIR}/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_eth.h" "${HAL_DEST}/Inc/" + clean_temp echo "[OK] NetX Duo STM32 Ethernet drivers copied" echo "" From 94db1fa034296e82e1addafc547c43b74972972f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Tue, 30 Jun 2026 17:30:44 -0400 Subject: [PATCH 3/9] Updated security policy (#43) Co-authored-by: Codex Signed-off-by: alieissa-commits --- SECURITY.md | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index f77818b2..79dfb729 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,21 +1,39 @@ # Security Policy -## Supported Versions +This Eclipse Foundation Project adheres to the [Eclipse Foundation Vulnerability Reporting Policy](https://www.eclipse.org/security/policy/). -For the time being, the contents of this repository are not in scope for quarterly releases. New versions will be published as needed to address bugs, vulnerabilities, or integrated updated third-party components. +## How To Report a Vulnerability -## Reporting a Vulnerability +If you think you have found a vulnerability in this repository, please report it to us through coordinated disclosure. -If you think you have found a vulnerability in Eclipse ThreadX or one of its companion components, you can report it using one of the following ways: +**Please do not report security vulnerabilities through public issues, discussions, or change requests.** -* Contact the [Eclipse Foundation Security Team](mailto:security@eclipse-foundation.org) -* [Report a Vulnerability](https://github.com/eclipse-threadx/threadx/security/advisories/new) +Instead, [report it privately here](https://github.com/eclipse-threadx/samplex/security/advisories/new) on GitHub You can find more information about reporting and disclosure at the [Eclipse Foundation Security page](https://www.eclipse.org/security/). -## Security Policy +Please include as much of the information listed below as you can to help us better understand and resolve the issue: + +* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) +* Affected version(s) +* Impact of the issue, including how an attacker might exploit the issue +* Step-by-step instructions to reproduce the issue +* The location of the affected source code (tag/branch/commit or direct URL) +* Full paths of source file(s) related to the manifestation of the issue +* Configuration required to reproduce the issue +* Log files that are related to this issue (if possible) +* Proof-of-concept or exploit code (if possible) + +This information will help us triage your report more quickly. + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 6.5.x | :white_check_mark: | + +Eclipse ThreadX publishes a release every quarter. There are no long-term support branches or backports to older releases. -This project follows [Eclipse Foundation Vulnerability Reporting Policy](https://www.eclipse.org/security/policy/). +Normally, fixes for non-critical vulnerabilities will ship in a regularly scheduled quarterly release. If fixes for an urgent or critical vulnerability must ship quickly, then the project will publish a hotfix release of the affected component(s) without waiting for the next quarterly release. -## About this repository -This repository contains only sample code for learning and evaluation purposes. It is not part of the core Eclipse ThreadX release process. +You can learn more about the [project's release cadence in this blog post](https://blogs.eclipse.org/post/fr%C3%A9d%C3%A9ric-desbiens/eclipse-threadx-more-predictable-more-open). From 691b3c6f2f9cd97c88ebe54bed55ee98c870f2ee Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Sun, 5 Jul 2026 19:30:57 +0400 Subject: [PATCH 4/9] feat: initial network_station demo sensor and filex support Signed-off-by: alieissa-commits --- .../STM32F767ZI-Nucleo/CMakeLists.txt | 7 +- .../STM32F767ZI-Nucleo/app/board_init.c | 37 + .../STM32F767ZI-Nucleo/app/board_init.h | 5 + .../app/demos/network_station/CMakeLists.txt | 45 + .../app/demos/network_station/hts221_reg.c | 945 ++++++++++++++++++ .../app/demos/network_station/hts221_reg.h | 336 +++++++ .../app/demos/network_station/main.c | 284 ++++++ .../app/demos/network_station/sensor.h | 36 + .../app/demos/network_station/sensor_driver.c | 206 ++++ .../app/stm32f7xx_hal_conf.h | 2 +- .../app/stm32f7xx_hal_msp.c | 45 + 11 files changed, 1946 insertions(+), 2 deletions(-) create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.c create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.h create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt index 1aac36be..8e09bab7 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt @@ -11,6 +11,7 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR) set(CMAKE_C_STANDARD 99) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Set the toolchain if not defined if(NOT CMAKE_TOOLCHAIN_FILE) @@ -33,7 +34,7 @@ set(STM32Cube_DIR "${CMAKE_CURRENT_LIST_DIR}/lib/stm32cubef7") # Find CMSIS and HAL driver packages find_package(CMSIS REQUIRED) -find_package(STM32HAL REQUIRED COMPONENTS cortex pwr rcc gpio uart dma eth) +find_package(STM32HAL REQUIRED COMPONENTS cortex pwr rcc gpio uart dma eth i2c) # Compile the STM32F7xx HAL Driver Library as an Object Library set(HAL_TARGET stm32cubef7) @@ -75,6 +76,10 @@ endif() set(THREADX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../libs/threadx") add_subdirectory(${THREADX_DIR} threadx) +# Compile FileX Filesystem from root shared libs submodule +set(FILEX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../libs/filex") +add_subdirectory(${FILEX_DIR} filex) + if(USE_NETXDUO) # Compile NetX Duo TCP/IP Stack from root shared libs submodule set(NXD_ENABLE_FILE_SERVERS OFF CACHE BOOL "Disable FileX dependency in NetX Duo" FORCE) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c index 53efb8a2..a753db19 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c @@ -53,6 +53,9 @@ void board_init(void) /* Initialize USART3 console */ MX_USART3_UART_Init(); + + /* Initialize I2C1 for environmental sensors */ + board_i2c_init(); } /** @@ -324,3 +327,37 @@ uint32_t HAL_GetTick(void) return ms_ticks; } } + +/* Global I2C handler */ +I2C_HandleTypeDef hi2c1; + +void board_i2c_init(void) +{ + hi2c1.Instance = I2C1; + hi2c1.Init.Timing = 0x20404768; /* 100 kHz standard mode timing value at 54 MHz I2C clock */ + hi2c1.Init.OwnAddress1 = 0; + hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c1.Init.OwnAddress2 = 0; + hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK; + hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + if (HAL_I2C_Init(&hi2c1) != HAL_OK) + { + Error_Handler(); + } + + /* Configure Analogue filter */ + if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK) + { + Error_Handler(); + } + + /* Configure Digital filter */ + if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK) + { + Error_Handler(); + } +} + diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h index 7cb42fe0..64a9728a 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.h @@ -39,8 +39,13 @@ extern UART_HandleTypeDef huart3; /* Global Ethernet handle */ extern ETH_HandleTypeDef heth; +/* Global I2C handle */ +extern I2C_HandleTypeDef hi2c1; + /* Define prototypes. */ void board_init(void); void board_ethernet_init(void); +void board_i2c_init(void); + #endif // _BOARD_INIT_H diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt new file mode 100644 index 00000000..63eb512a --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available +# under the terms of the MIT license which is available at +# https://opensource.org/license/mit. +# +# SPDX-License-Identifier: MIT +# +# Contributors: +# Ali Eissa - 2026 version. + +add_executable(${PROJECT_NAME} + main.c + sensor_driver.c + hts221_reg.c +) + +# Set compile definitions for our executable +target_compile_definitions(${PROJECT_NAME} + PRIVATE + STM32F767xx + USE_HAL_DRIVER + STM32F7 +) + +# Include paths for the executable target +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Link libraries +target_link_libraries(${PROJECT_NAME} + PRIVATE + board_bsp + threadx + filex + stm32cubef7 +) + +# Apply GCC linker script and print memory usage (utilities.cmake function) +set_target_linker(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../../startup/STM32F767ZITx_FLASH.ld") + +# Post-build commands to generate raw .bin and .hex files +post_build(${PROJECT_NAME}) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.c new file mode 100644 index 00000000..88656cc3 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.c @@ -0,0 +1,945 @@ +/* + ****************************************************************************** + * @file hts221_reg.c + * @author Sensors Software Solution Team + * @brief HTS221 driver file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +#include "hts221_reg.h" + +/** + * @defgroup HTS221 + * @brief This file provides a set of functions needed to drive the + * hts221 enhanced inertial module. + * @{ + * + */ + +/** + * @defgroup HTS221_interfaces_functions + * @brief This section provide a set of functions used to read and write + * a generic register of the device. + * @{ + * + */ + +/** + * @brief Read generic device register + * + * @param ctx read / write interface definitions(ptr) + * @param reg register to read + * @param data pointer to buffer that store the data read(ptr) + * @param len number of consecutive register to read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_read_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data, + uint16_t len) +{ + int32_t ret; + ret = ctx->read_reg(ctx->handle, reg, data, len); + return ret; +} + +/** + * @brief Write generic device register + * + * @param ctx read / write interface definitions(ptr) + * @param reg register to write + * @param data pointer to data to write in register reg(ptr) + * @param len number of consecutive register to write + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_write_reg(stmdev_ctx_t* ctx, uint8_t reg, uint8_t* data, + uint16_t len) +{ + int32_t ret; + ret = ctx->write_reg(ctx->handle, reg, data, len); + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup HTS221_Data_Generation + * @brief This section group all the functions concerning data generation + * @{ + * + */ + +/** + * @brief The numbers of averaged humidity samples.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of avgh in reg AV_CONF + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_humidity_avg_set(stmdev_ctx_t *ctx, hts221_avgh_t val) +{ + hts221_av_conf_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_AV_CONF, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.avgh = (uint8_t)val; + ret = hts221_write_reg(ctx, HTS221_AV_CONF, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief The numbers of averaged humidity samples.[get] + * + * @param ctx read / write interface definitions + * @param val Get the values of avgh in reg AV_CONF + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_humidity_avg_get(stmdev_ctx_t *ctx, hts221_avgh_t *val) +{ + hts221_av_conf_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_AV_CONF, (uint8_t*) ®, 1); + + switch (reg.avgh) { + case HTS221_H_AVG_4: + *val = HTS221_H_AVG_4; + break; + case HTS221_H_AVG_8: + *val = HTS221_H_AVG_8; + break; + case HTS221_H_AVG_16: + *val = HTS221_H_AVG_16; + break; + case HTS221_H_AVG_32: + *val = HTS221_H_AVG_32; + break; + case HTS221_H_AVG_64: + *val = HTS221_H_AVG_64; + break; + case HTS221_H_AVG_128: + *val = HTS221_H_AVG_128; + break; + case HTS221_H_AVG_256: + *val = HTS221_H_AVG_256; + break; + case HTS221_H_AVG_512: + *val = HTS221_H_AVG_512; + break; + default: + *val = HTS221_H_AVG_ND; + break; + } + + return ret; +} + +/** + * @brief The numbers of averaged temperature samples.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of avgt in reg AV_CONF + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temperature_avg_set(stmdev_ctx_t *ctx, hts221_avgt_t val) +{ + hts221_av_conf_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_AV_CONF, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.avgt = (uint8_t)val; + ret = hts221_write_reg(ctx, HTS221_AV_CONF, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief The numbers of averaged temperature samples.[get] + * + * @param ctx read / write interface definitions + * @param val Get the values of avgt in reg AV_CONF + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temperature_avg_get(stmdev_ctx_t *ctx, hts221_avgt_t *val) +{ + hts221_av_conf_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_AV_CONF, (uint8_t*) ®, 1); + + switch (reg.avgh) { + case HTS221_T_AVG_2: + *val = HTS221_T_AVG_2; + break; + case HTS221_T_AVG_4: + *val = HTS221_T_AVG_4; + break; + case HTS221_T_AVG_8: + *val = HTS221_T_AVG_8; + break; + case HTS221_T_AVG_16: + *val = HTS221_T_AVG_16; + break; + case HTS221_T_AVG_32: + *val = HTS221_T_AVG_32; + break; + case HTS221_T_AVG_64: + *val = HTS221_T_AVG_64; + break; + case HTS221_T_AVG_128: + *val = HTS221_T_AVG_128; + break; + case HTS221_T_AVG_256: + *val = HTS221_T_AVG_256; + break; + default: + *val = HTS221_T_AVG_ND; + break; + } + + return ret; +} + +/** + * @brief Output data rate selection.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of odr in reg CTRL_REG1 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_data_rate_set(stmdev_ctx_t *ctx, hts221_odr_t val) +{ + hts221_ctrl_reg1_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.odr = (uint8_t)val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Output data rate selection.[get] + * + * @param ctx read / write interface definitions + * @param val Get the values of odr in reg CTRL_REG1 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_data_rate_get(stmdev_ctx_t *ctx, hts221_odr_t *val) +{ + hts221_ctrl_reg1_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + + switch (reg.odr) { + case HTS221_ONE_SHOT: + *val = HTS221_ONE_SHOT; + break; + case HTS221_ODR_1Hz: + *val = HTS221_ODR_1Hz; + break; + case HTS221_ODR_7Hz: + *val = HTS221_ODR_7Hz; + break; + case HTS221_ODR_12Hz5: + *val = HTS221_ODR_12Hz5; + break; + default: + *val = HTS221_ODR_ND; + break; + } + + return ret; +} + +/** + * @brief Block data update.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of bdu in reg CTRL_REG1 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_block_data_update_set(stmdev_ctx_t *ctx, uint8_t val) +{ + hts221_ctrl_reg1_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.bdu = val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Block data update.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of bdu in reg CTRL_REG1 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_block_data_update_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_ctrl_reg1_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + *val = reg.bdu; + + return ret; +} + +/** + * @brief One-shot mode. Device perform a single measure.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of one_shot in reg CTRL_REG2 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_one_shoot_trigger_set(stmdev_ctx_t *ctx, uint8_t val) +{ + hts221_ctrl_reg2_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.one_shot = val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief One-shot mode. Device perform a single measure.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of one_shot in reg CTRL_REG2 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_one_shoot_trigger_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_ctrl_reg2_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + *val = reg.one_shot; + + return ret; +} + +/** + * @brief Temperature data available.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of t_da in reg STATUS_REG + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temp_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_status_reg_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_STATUS_REG, (uint8_t*) ®, 1); + *val = reg.t_da; + + return ret; +} + +/** + * @brief Humidity data available.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of h_da in reg STATUS_REG + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_hum_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_status_reg_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_STATUS_REG, (uint8_t*) ®, 1); + *val = reg.h_da; + + return ret; +} + +/** + * @brief Humidity output value[get] + * + * @param ctx read / write interface definitions + * @param buff buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_humidity_raw_get(stmdev_ctx_t *ctx, uint8_t *buff) +{ + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_HUMIDITY_OUT_L, buff, 2); + return ret; +} + +/** + * @brief Temperature output value[get] + * + * @param ctx read / write interface definitions + * @param buff buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temperature_raw_get(stmdev_ctx_t *ctx, uint8_t *buff) +{ + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_TEMP_OUT_L, buff, 2); + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup HTS221_common + * @brief This section group common usefull functions + * @{ + * + */ + +/** + * @brief Device Who amI.[get] + * + * @param ctx read / write interface definitions + * @param buff buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff) +{ + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_WHO_AM_I, buff, 1); + return ret; +} + +/** + * @brief Switch device on/off.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of pd in reg CTRL_REG1 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_power_on_set(stmdev_ctx_t *ctx, uint8_t val) +{ + hts221_ctrl_reg1_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.pd = val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + } + return ret; +} + +/** + * @brief Switch device on/off.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of pd in reg CTRL_REG1 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_power_on_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_ctrl_reg1_t reg; + int32_t mm_error; + + mm_error = hts221_read_reg(ctx, HTS221_CTRL_REG1, (uint8_t*) ®, 1); + *val = reg.pd; + + return mm_error; +} + +/** + * @brief Heater enable / disable.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of heater in reg CTRL_REG2 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_heater_set(stmdev_ctx_t *ctx, uint8_t val) +{ + hts221_ctrl_reg2_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.heater = val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Heater enable / disable.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of heater in reg CTRL_REG2 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_heater_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_ctrl_reg2_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + *val = reg.heater; + + return ret; +} + +/** + * @brief Reboot memory content. Reload the calibration parameters.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of boot in reg CTRL_REG2 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_boot_set(stmdev_ctx_t *ctx, uint8_t val) +{ + hts221_ctrl_reg2_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.boot = val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Reboot memory content. Reload the calibration parameters.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of boot in reg CTRL_REG2 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_boot_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_ctrl_reg2_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG2, (uint8_t*) ®, 1); + *val = reg.boot; + + return ret; +} + +/** + * @brief Info about device status.[get] + * + * @param ctx read / write interface definitions + * @param val Registers STATUS_REG + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_status_get(stmdev_ctx_t *ctx, hts221_status_reg_t *val) +{ + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_STATUS_REG, (uint8_t*) val, 1); + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup HTS221_interrupts + * @brief This section group all the functions that manage interrupts + * @{ + * + */ + +/** + * @brief Data-ready signal on INT_DRDY pin.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of drdy in reg CTRL_REG3 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_drdy_on_int_set(stmdev_ctx_t *ctx, uint8_t val) +{ + hts221_ctrl_reg3_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.drdy = val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Data-ready signal on INT_DRDY pin.[get] + * + * @param ctx read / write interface definitions + * @param val change the values of drdy in reg CTRL_REG3 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_drdy_on_int_get(stmdev_ctx_t *ctx, uint8_t *val) +{ + hts221_ctrl_reg3_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + *val = reg.drdy; + + return ret; +} + +/** + * @brief Push-pull/open drain selection on interrupt pads.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of pp_od in reg CTRL_REG3 + * + */ +int32_t hts221_pin_mode_set(stmdev_ctx_t *ctx, hts221_pp_od_t val) +{ + hts221_ctrl_reg3_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.pp_od = (uint8_t)val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Push-pull/open drain selection on interrupt pads.[get] + * + * @param ctx read / write interface definitions + * @param val Get the values of pp_od in reg CTRL_REG3 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_pin_mode_get(stmdev_ctx_t *ctx, hts221_pp_od_t *val) +{ + hts221_ctrl_reg3_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + + switch (reg.pp_od) { + case HTS221_PUSH_PULL: + *val = HTS221_PUSH_PULL; + break; + case HTS221_OPEN_DRAIN: + *val = HTS221_OPEN_DRAIN; + break; + default: + *val = HTS221_PIN_MODE_ND; + break; + } + + return ret; +} + +/** + * @brief Interrupt active-high/low.[set] + * + * @param ctx read / write interface definitions + * @param val change the values of drdy_h_l in reg CTRL_REG3 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_int_polarity_set(stmdev_ctx_t *ctx, hts221_drdy_h_l_t val) +{ + hts221_ctrl_reg3_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + + if(ret == 0){ + reg.drdy_h_l = (uint8_t)val; + ret = hts221_write_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + } + + return ret; +} + +/** + * @brief Interrupt active-high/low.[get] + * + * @param ctx read / write interface definitions + * @param val Get the values of drdy_h_l in reg CTRL_REG3 + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_int_polarity_get(stmdev_ctx_t *ctx, hts221_drdy_h_l_t *val) +{ + hts221_ctrl_reg3_t reg; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_CTRL_REG3, (uint8_t*) ®, 1); + + switch (reg.drdy_h_l) { + case HTS221_ACTIVE_HIGH: + *val = HTS221_ACTIVE_HIGH; + break; + case HTS221_ACTIVE_LOW: + *val = HTS221_ACTIVE_LOW; + break; + default: + *val = HTS221_ACTIVE_ND; + break; + } + + return ret; +} + +/** + * @} + * + */ + +/** + * @defgroup HTS221_calibration + * @brief This section group all the calibration coefficients need + * for reading data + * @{ + * + */ + +/** + * @brief First calibration point for Rh Humidity.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_hum_rh_point_0_get(stmdev_ctx_t *ctx, float_t *val) +{ + uint8_t coeff; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_H0_RH_X2, &coeff, 1); + *val = coeff / 2.0f; + + return ret; +} + +/** + * @brief Second calibration point for Rh Humidity.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_hum_rh_point_1_get(stmdev_ctx_t *ctx, float_t *val) +{ + uint8_t coeff; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_H1_RH_X2, &coeff, 1); + *val = coeff / 2.0f; + + return ret; +} + +/** + * @brief First calibration point for degC temperature.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temp_deg_point_0_get(stmdev_ctx_t *ctx, float_t *val) +{ + hts221_t1_t0_msb_t reg; + uint8_t coeff_h, coeff_l; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_T0_DEGC_X8, &coeff_l, 1); + + if(ret == 0){ + ret = hts221_read_reg(ctx, HTS221_T1_T0_MSB, (uint8_t*) ®, 1); + coeff_h = reg.t0_msb; + *val = ((coeff_h * 256) + coeff_l) / 8.0f; + } + + return ret; +} + +/** + * @brief Second calibration point for degC temperature.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temp_deg_point_1_get(stmdev_ctx_t *ctx, float_t *val) +{ + hts221_t1_t0_msb_t reg; + uint8_t coeff_h, coeff_l; + int32_t ret; + + ret = hts221_read_reg(ctx, HTS221_T1_DEGC_X8, &coeff_l, 1); + + if(ret == 0){ + ret = hts221_read_reg(ctx, HTS221_T1_T0_MSB, (uint8_t*) ®, 1); + coeff_h = reg.t1_msb; + *val = ((coeff_h * 256) + coeff_l) / 8.0f; + } + + return ret; +} + +/** + * @brief First calibration point for humidity in LSB.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_hum_adc_point_0_get(stmdev_ctx_t *ctx, float_t *val) +{ + uint8_t coeff_p[2]; + int16_t coeff; + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_H0_T0_OUT_L, coeff_p, 2); + coeff = (coeff_p[1] * 256) + coeff_p[0]; + *val = coeff * 1.0f; + return ret; +} + +/** + * @brief Second calibration point for humidity in LSB.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_hum_adc_point_1_get(stmdev_ctx_t *ctx, float_t *val) +{ + uint8_t coeff_p[2]; + int16_t coeff; + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_H1_T0_OUT_L, coeff_p, 2); + coeff = (coeff_p[1] * 256) + coeff_p[0]; + *val = coeff * 1.0f; + return ret; +} + +/** + * @brief First calibration point for temperature in LSB.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temp_adc_point_0_get(stmdev_ctx_t *ctx, float_t *val) +{ + uint8_t coeff_p[2]; + int16_t coeff; + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_T0_OUT_L, coeff_p, 2); + coeff = (coeff_p[1] * 256) + coeff_p[0]; + *val = coeff * 1.0f; + return ret; +} + +/** + * @brief Second calibration point for temperature in LSB.[get] + * + * @param ctx read / write interface definitions + * @param val buffer that stores data read + * @retval interface status (MANDATORY: return 0 -> no Error) + * + */ +int32_t hts221_temp_adc_point_1_get(stmdev_ctx_t *ctx, float_t *val) +{ + uint8_t coeff_p[2]; + int16_t coeff; + int32_t ret; + ret = hts221_read_reg(ctx, HTS221_T1_OUT_L, coeff_p, 2); + coeff = (coeff_p[1] * 256) + coeff_p[0]; + *val = coeff * 1.0f; + return ret; +} + +/** + * @} + * + */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.h new file mode 100644 index 00000000..95d1bf21 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/hts221_reg.h @@ -0,0 +1,336 @@ +/* + ****************************************************************************** + * @file hts221_reg.h + * @author Sensors Software Solution Team + * @brief This file contains all the functions prototypes for the + * hts221_reg.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef HTS221_REGS_H +#define HTS221_REGS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include + +/** @addtogroup HTS221 + * @{ + * + */ + +/** @defgroup STMicroelectronics sensors common types + * @{ + * + */ + +#ifndef MEMS_SHARED_TYPES +#define MEMS_SHARED_TYPES + +typedef struct{ + uint8_t bit0 : 1; + uint8_t bit1 : 1; + uint8_t bit2 : 1; + uint8_t bit3 : 1; + uint8_t bit4 : 1; + uint8_t bit5 : 1; + uint8_t bit6 : 1; + uint8_t bit7 : 1; +} bitwise_t; + +#define PROPERTY_DISABLE (0U) +#define PROPERTY_ENABLE (1U) + +/** @addtogroup Interfaces_Functions + * @brief This section provide a set of functions used to read and + * write a generic register of the device. + * MANDATORY: return 0 -> no Error. + * @{ + * + */ + +typedef int32_t (*stmdev_write_ptr)(void *, uint8_t, uint8_t*, uint16_t); +typedef int32_t (*stmdev_read_ptr) (void *, uint8_t, uint8_t*, uint16_t); + +typedef struct { + /** Component mandatory fields **/ + stmdev_write_ptr write_reg; + stmdev_read_ptr read_reg; + /** Customizable optional pointer **/ + void *handle; +} stmdev_ctx_t; + +/** + * @} + * + */ + +#endif /* MEMS_SHARED_TYPES */ + +#ifndef MEMS_UCF_SHARED_TYPES +#define MEMS_UCF_SHARED_TYPES + +/** @defgroup Generic address-data structure definition + * @brief This structure is useful to load a predefined configuration + * of a sensor. + * You can create a sensor configuration by your own or using + * Unico / Unicleo tools available on STMicroelectronics + * web site. + * + * @{ + * + */ + +typedef struct { + uint8_t address; + uint8_t data; +} ucf_line_t; + +/** + * @} + * + */ + +#endif /* MEMS_UCF_SHARED_TYPES */ + +/** + * @} + * + */ + +/** @defgroup HTS221_Infos + * @{ + * + */ + +/** I2C Device Address 8 bit format **/ +#define HTS221_I2C_ADDRESS 0xBFU + +/** Device Identification (Who am I) **/ +#define HTS221_ID 0xBCU + +/** + * @} + * + */ + +#define HTS221_WHO_AM_I 0x0FU +#define HTS221_AV_CONF 0x10U +typedef struct { + uint8_t avgh : 3; + uint8_t avgt : 3; + uint8_t not_used_01 : 2; +} hts221_av_conf_t; + +#define HTS221_CTRL_REG1 0x20U +typedef struct { + uint8_t odr : 2; + uint8_t bdu : 1; + uint8_t not_used_01 : 4; + uint8_t pd : 1; +} hts221_ctrl_reg1_t; + +#define HTS221_CTRL_REG2 0x21U +typedef struct { + uint8_t one_shot : 1; + uint8_t heater : 1; + uint8_t not_used_01 : 5; + uint8_t boot : 1; +} hts221_ctrl_reg2_t; + +#define HTS221_CTRL_REG3 0x22U +typedef struct { + uint8_t not_used_01 : 2; + uint8_t drdy : 1; + uint8_t not_used_02 : 3; + uint8_t pp_od : 1; + uint8_t drdy_h_l : 1; +} hts221_ctrl_reg3_t; + +#define HTS221_STATUS_REG 0x27U +typedef struct { + uint8_t t_da : 1; + uint8_t h_da : 1; + uint8_t not_used_01 : 6; +} hts221_status_reg_t; + +#define HTS221_HUMIDITY_OUT_L 0x28U +#define HTS221_HUMIDITY_OUT_H 0x29U +#define HTS221_TEMP_OUT_L 0x2AU +#define HTS221_TEMP_OUT_H 0x2BU +#define HTS221_H0_RH_X2 0x30U +#define HTS221_H1_RH_X2 0x31U +#define HTS221_T0_DEGC_X8 0x32U +#define HTS221_T1_DEGC_X8 0x33U +#define HTS221_T1_T0_MSB 0x35U +typedef struct { + uint8_t t0_msb : 2; + uint8_t t1_msb : 2; + uint8_t not_used_01 : 4; +} hts221_t1_t0_msb_t; + +#define HTS221_H0_T0_OUT_L 0x36U +#define HTS221_H0_T0_OUT_H 0x37U +#define HTS221_H1_T0_OUT_L 0x3AU +#define HTS221_H1_T0_OUT_H 0x3BU +#define HTS221_T0_OUT_L 0x3CU +#define HTS221_T0_OUT_H 0x3DU +#define HTS221_T1_OUT_L 0x3EU +#define HTS221_T1_OUT_H 0x3FU + +/** + * @defgroup HTS221_Register_Union + * @brief This union group all the registers that has a bitfield + * description. + * This union is useful but not need by the driver. + * + * REMOVING this union you are compliant with: + * MISRA-C 2012 [Rule 19.2] -> " Union are not allowed " + * + * @{ + * + */ +typedef union{ + hts221_av_conf_t av_conf; + hts221_ctrl_reg1_t ctrl_reg1; + hts221_ctrl_reg2_t ctrl_reg2; + hts221_ctrl_reg3_t ctrl_reg3; + hts221_status_reg_t status_reg; + hts221_t1_t0_msb_t t1_t0_msb; + bitwise_t bitwise; + uint8_t byte; +} hts221_reg_t; + +/** + * @} + * + */ + +int32_t hts221_read_reg(stmdev_ctx_t *ctx, uint8_t reg, uint8_t* data, + uint16_t len); +int32_t hts221_write_reg(stmdev_ctx_t *ctx, uint8_t reg, uint8_t* data, + uint16_t len); + +typedef enum { + HTS221_H_AVG_4 = 0, + HTS221_H_AVG_8 = 1, + HTS221_H_AVG_16 = 2, + HTS221_H_AVG_32 = 3, + HTS221_H_AVG_64 = 4, + HTS221_H_AVG_128 = 5, + HTS221_H_AVG_256 = 6, + HTS221_H_AVG_512 = 7, + HTS221_H_AVG_ND = 8, +} hts221_avgh_t; +int32_t hts221_humidity_avg_set(stmdev_ctx_t *ctx, hts221_avgh_t val); +int32_t hts221_humidity_avg_get(stmdev_ctx_t *ctx, hts221_avgh_t *val); + +typedef enum { + HTS221_T_AVG_2 = 0, + HTS221_T_AVG_4 = 1, + HTS221_T_AVG_8 = 2, + HTS221_T_AVG_16 = 3, + HTS221_T_AVG_32 = 4, + HTS221_T_AVG_64 = 5, + HTS221_T_AVG_128 = 6, + HTS221_T_AVG_256 = 7, + HTS221_T_AVG_ND = 8, +} hts221_avgt_t; +int32_t hts221_temperature_avg_set(stmdev_ctx_t *ctx, hts221_avgt_t val); +int32_t hts221_temperature_avg_get(stmdev_ctx_t *ctx, hts221_avgt_t *val); + +typedef enum { + HTS221_ONE_SHOT = 0, + HTS221_ODR_1Hz = 1, + HTS221_ODR_7Hz = 2, + HTS221_ODR_12Hz5 = 3, + HTS221_ODR_ND = 4, +} hts221_odr_t; +int32_t hts221_data_rate_set(stmdev_ctx_t *ctx, hts221_odr_t val); +int32_t hts221_data_rate_get(stmdev_ctx_t *ctx, hts221_odr_t *val); + +int32_t hts221_block_data_update_set(stmdev_ctx_t *ctx, uint8_t val); +int32_t hts221_block_data_update_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_one_shoot_trigger_set(stmdev_ctx_t *ctx, uint8_t val); +int32_t hts221_one_shoot_trigger_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_temp_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_hum_data_ready_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_humidity_raw_get(stmdev_ctx_t *ctx, uint8_t *buff); + +int32_t hts221_temperature_raw_get(stmdev_ctx_t *ctx, uint8_t *buff); + +int32_t hts221_device_id_get(stmdev_ctx_t *ctx, uint8_t *buff); + +int32_t hts221_power_on_set(stmdev_ctx_t *ctx, uint8_t val); + +int32_t hts221_power_on_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_heater_set(stmdev_ctx_t *ctx, uint8_t val); +int32_t hts221_heater_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_boot_set(stmdev_ctx_t *ctx, uint8_t val); +int32_t hts221_boot_get(stmdev_ctx_t *ctx, uint8_t *val); + +int32_t hts221_status_get(stmdev_ctx_t *ctx, hts221_status_reg_t *val); + +int32_t hts221_drdy_on_int_set(stmdev_ctx_t *ctx, uint8_t val); +int32_t hts221_drdy_on_int_get(stmdev_ctx_t *ctx, uint8_t *val); + +typedef enum { + HTS221_PUSH_PULL = 0, + HTS221_OPEN_DRAIN = 1, + HTS221_PIN_MODE_ND = 2, +} hts221_pp_od_t; +int32_t hts221_pin_mode_set(stmdev_ctx_t *ctx, hts221_pp_od_t val); +int32_t hts221_pin_mode_get(stmdev_ctx_t *ctx, hts221_pp_od_t *val); + +typedef enum { + HTS221_ACTIVE_HIGH = 0, + HTS221_ACTIVE_LOW = 1, + HTS221_ACTIVE_ND = 2, +} hts221_drdy_h_l_t; +int32_t hts221_int_polarity_set(stmdev_ctx_t *ctx, hts221_drdy_h_l_t val); +int32_t hts221_int_polarity_get(stmdev_ctx_t *ctx, hts221_drdy_h_l_t *val); + +int32_t hts221_hum_rh_point_0_get(stmdev_ctx_t *ctx, float_t *val); +int32_t hts221_hum_rh_point_1_get(stmdev_ctx_t *ctx, float_t *val); + +int32_t hts221_temp_deg_point_0_get(stmdev_ctx_t *ctx, float_t *val); +int32_t hts221_temp_deg_point_1_get(stmdev_ctx_t *ctx, float_t *val); + +int32_t hts221_hum_adc_point_0_get(stmdev_ctx_t *ctx, float_t *val); +int32_t hts221_hum_adc_point_1_get(stmdev_ctx_t *ctx, float_t *val); + +int32_t hts221_temp_adc_point_0_get(stmdev_ctx_t *ctx, float_t *val); +int32_t hts221_temp_adc_point_1_get(stmdev_ctx_t *ctx, float_t *val); + +/** + * @} + * + */ + +#ifdef __cplusplus +} +#endif + +#endif /*HTS221_REGS_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c new file mode 100644 index 00000000..dddf408b --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#include "tx_api.h" +#include "fx_api.h" +#include "board_init.h" +#include "sensor.h" +#include + +#define DEMO_STACK_SIZE 2048 +#define DEMO_BYTE_POOL_SIZE 20480 /* Increased byte pool size to accommodate FileX memory allocations */ +#define SENSOR_QUEUE_MAX_MSGS 10 +#define SENSOR_MSG_WORDS 3 /* 12 bytes = 3 ULONGs */ +#define RAM_DISK_SIZE 32768 /* 32 KB RAM Disk */ +#define RAM_DISK_SECTOR_SIZE 512 + +/* Thread X objects */ +TX_THREAD sensor_thread; +TX_THREAD logger_thread; +TX_QUEUE sensor_queue; +TX_BYTE_POOL byte_pool_sensor; + +/* FileX objects */ +FX_MEDIA ram_disk; +FX_FILE log_file; + +/* Memory area for byte pool */ +static uint8_t pool_memory[DEMO_BYTE_POOL_SIZE]; + +/* Statically allocated memory for RAM disk and sector cache */ +static uint8_t ram_disk_memory[RAM_DISK_SIZE]; +static uint8_t cache_buffer[RAM_DISK_SECTOR_SIZE]; + +/* External FileX RAM driver prototype */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +/* Thread entry prototypes */ +static void sensor_thread_entry(ULONG thread_input); +static void logger_thread_entry(ULONG thread_input); + +int main(void) +{ + /* Initialize Board Support Package (BSP) - clock, GPIO, UART, I2C, etc. */ + board_init(); + + printf("\r\n==================================================\r\n"); + printf(" Network Environmental Station Demo - Phase 2 \r\n"); + printf("==================================================\r\n"); + + /* Enter the ThreadX kernel */ + tx_kernel_enter(); + + return 0; +} + +void tx_application_define(void *first_unused_memory) +{ + CHAR *pointer; + + /* Create a byte memory pool from which to allocate the thread stacks and queues */ + if (tx_byte_pool_create(&byte_pool_sensor, "sensor_pool", pool_memory, DEMO_BYTE_POOL_SIZE) != TX_SUCCESS) + { + printf("[System] Error: Failed to create sensor byte pool\r\n"); + Error_Handler(); + } + + /* Allocate the message queue memory */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, + SENSOR_QUEUE_MAX_MSGS * SENSOR_MSG_WORDS * sizeof(ULONG), TX_NO_WAIT) != TX_SUCCESS) + { + printf("[System] Error: Failed to allocate queue memory\r\n"); + Error_Handler(); + } + + /* Create the sensor message queue */ + if (tx_queue_create(&sensor_queue, "sensor_queue", SENSOR_MSG_WORDS, pointer, + SENSOR_QUEUE_MAX_MSGS * SENSOR_MSG_WORDS * sizeof(ULONG)) != TX_SUCCESS) + { + printf("[System] Error: Failed to create sensor message queue\r\n"); + Error_Handler(); + } + + /* Allocate the stack for the sensor thread */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) + { + printf("[System] Error: Failed to allocate sensor thread stack\r\n"); + Error_Handler(); + } + + /* Create the sensor thread */ + if (tx_thread_create(&sensor_thread, "sensor_thread", sensor_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) + { + printf("[System] Error: Failed to create sensor thread\r\n"); + Error_Handler(); + } + + /* Allocate the stack for the logger thread */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) + { + printf("[System] Error: Failed to allocate logger thread stack\r\n"); + Error_Handler(); + } + + /* Create the logger thread (Priority 5, lower priority than sensor_thread) */ + if (tx_thread_create(&logger_thread, "logger_thread", logger_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) + { + printf("[System] Error: Failed to create logger thread\r\n"); + Error_Handler(); + } + + printf("[System] ThreadX and FileX objects created successfully.\r\n"); +} + +static void sensor_thread_entry(ULONG thread_input) +{ + (void)thread_input; + float temp = 0.0f; + float hum = 0.0f; + sensor_msg_t msg; + + /* Initialize sensor hardware (or fallback to mock) */ + if (sensor_init() != SENSOR_OK) + { + printf("[Sensor Thread] Critical Error: Sensor initialization failed!\r\n"); + Error_Handler(); + } + + printf("[Sensor Thread] Started polling loop (every 2 seconds).\r\n"); + + while (1) + { + /* Read sensor data */ + if (sensor_read(&temp, &hum) == SENSOR_OK) + { + /* Pack the message */ + msg.temperature = temp; + msg.humidity = hum; + msg.timestamp = HAL_GetTick(); + + /* Send the message to the queue */ + if (tx_queue_send(&sensor_queue, &msg, TX_NO_WAIT) == TX_SUCCESS) + { + float temp_abs = (temp < 0.0f) ? -temp : temp; + int temp_dec = (int)temp_abs; + int temp_frac = (int)((temp_abs - (float)temp_dec) * 100.0f); + + int hum_dec = (int)hum; + int hum_frac = (int)((hum - (float)hum_dec) * 100.0f); + + printf("[Sensor Thread] Temp: %s%d.%02d C, Hum: %d.%02d %%, Time: %lu ms (Sent to Queue)\r\n", + (temp < 0.0f) ? "-" : "", temp_dec, temp_frac, hum_dec, hum_frac, (unsigned long)msg.timestamp); + } + else + { + printf("[Sensor Thread] WARNING: Queue is full, message dropped.\r\n"); + } + } + else + { + printf("[Sensor Thread] Error: Failed to read sensor data.\r\n"); + } + + /* Sleep for 2 seconds (assuming 100 ticks per second) */ + tx_thread_sleep(2 * TX_TIMER_TICKS_PER_SECOND); + } +} + +static void logger_thread_entry(ULONG thread_input) +{ + (void)thread_input; + UINT status; + sensor_msg_t msg; + char write_buffer[64]; + + printf("[Logger Thread] Starting FileX RAM Disk Logger...\r\n"); + + /* Initialize FileX system */ + fx_system_initialize(); + + /* Format the RAM disk. This is required before opening it. */ + status = fx_media_format(&ram_disk, + _fx_ram_driver, + ram_disk_memory, + cache_buffer, + sizeof(cache_buffer), + "RAM DISK", + 1, + 32, + 0, + RAM_DISK_SIZE / RAM_DISK_SECTOR_SIZE, + RAM_DISK_SECTOR_SIZE, + 1, + 1, + 1); + if (status != FX_SUCCESS) + { + printf("[Logger Thread] Error: RAM Disk format failed! (0x%02X)\r\n", status); + Error_Handler(); + } + + /* Open the RAM Disk */ + status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, + cache_buffer, sizeof(cache_buffer)); + if (status != FX_SUCCESS) + { + printf("[Logger Thread] Error: RAM Disk open failed! (0x%02X)\r\n", status); + Error_Handler(); + } + + /* Create the log file */ + status = fx_file_create(&ram_disk, "sensor_log.txt"); + if (status != FX_SUCCESS && status != FX_ALREADY_CREATED) + { + printf("[Logger Thread] Error: Failed to create log file! (0x%02X)\r\n", status); + Error_Handler(); + } + + /* Open the log file for writing */ + status = fx_file_open(&ram_disk, &log_file, "sensor_log.txt", FX_OPEN_FOR_WRITE); + if (status != FX_SUCCESS) + { + printf("[Logger Thread] Error: Failed to open log file! (0x%02X)\r\n", status); + Error_Handler(); + } + + /* Move the write pointer to the end of the file to append new data */ + fx_file_seek(&log_file, log_file.fx_file_current_file_size); + + printf("[Logger Thread] RAM Disk initialized. Logging 'sensor_log.txt'...\r\n"); + + while (1) + { + /* Retrieve the next sensor reading from the queue (blocks until a message is available) */ + if (tx_queue_receive(&sensor_queue, &msg, TX_WAIT_FOREVER) == TX_SUCCESS) + { + /* Format the sensor reading as a CSV line: timestamp,temp,hum */ + float temp_abs = (msg.temperature < 0.0f) ? -msg.temperature : msg.temperature; + int temp_dec = (int)temp_abs; + int temp_frac = (int)((temp_abs - (float)temp_dec) * 100.0f); + + int hum_dec = (int)msg.humidity; + int hum_frac = (int)((msg.humidity - (float)hum_dec) * 100.0f); + + int len = snprintf(write_buffer, sizeof(write_buffer), "%lu,%s%d.%02d,%d.%02d\n", + (unsigned long)msg.timestamp, + (msg.temperature < 0.0f) ? "-" : "", temp_dec, temp_frac, + hum_dec, hum_frac); + + if (len > 0) + { + /* Write the CSV line to the file */ + status = fx_file_write(&log_file, write_buffer, (ULONG)len); + if (status == FX_SUCCESS) + { + /* Flush the media to commit changes to the RAM Disk immediately */ + fx_media_flush(&ram_disk); + + printf("[Logger Thread] Logged to RAM Disk: %lu,%s%d.%02d,%d.%02d\r\n", + (unsigned long)msg.timestamp, + (msg.temperature < 0.0f) ? "-" : "", temp_dec, temp_frac, + hum_dec, hum_frac); + } + else + { + printf("[Logger Thread] Error: Failed to write to log file! (0x%02X)\r\n", status); + } + } + } + } +} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h new file mode 100644 index 00000000..2fe39a13 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#ifndef SENSOR_H +#define SENSOR_H + +#include + +/* Sensor reading message structure sent through ThreadX queue */ +typedef struct { + float temperature; + float humidity; + uint32_t timestamp; +} sensor_msg_t; + +/* Sensor status enum */ +typedef enum { + SENSOR_OK = 0, + SENSOR_ERROR = 1 +} sensor_status_t; + +/* Public API */ +sensor_status_t sensor_init(void); +sensor_status_t sensor_read(float *temp, float *hum); + +#endif /* SENSOR_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c new file mode 100644 index 00000000..7f139c19 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#include "sensor.h" +#include "hts221_reg.h" +#include "board_init.h" +#include +#include +#include + +/* Private variables */ +static uint8_t mock_mode_active = 0; +static uint8_t whoamI = 0; + +/* Calibration coefficients for HTS221 */ +typedef struct { + float x0; + float y0; + float x1; + float y1; +} lin_t; + +static lin_t lin_hum; +static lin_t lin_temp; + +/* Linear interpolation helper */ +static float linear_interpolation(lin_t *lin, int16_t x) +{ + if (fabsf(lin->x1 - lin->x0) < 0.001f) + { + return lin->y0; + } + return ((lin->y1 - lin->y0) * x + ((lin->x1 * lin->y0) - (lin->x0 * lin->y1))) / (lin->x1 - lin->x0); +} + +/* Platform I2C read/write callbacks */ +static int32_t platform_write(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len) +{ + /* HTS221 requires setting the MSB (0x80) of the register address for multi-byte writes */ + if (len > 1) + { + reg |= 0x80; + } + if (HAL_I2C_Mem_Write((I2C_HandleTypeDef*)handle, HTS221_I2C_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, bufp, len, 100) == HAL_OK) + { + return 0; + } + return -1; +} + +static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len) +{ + /* HTS221 requires setting the MSB (0x80) of the register address for multi-byte reads */ + if (len > 1) + { + reg |= 0x80; + } + if (HAL_I2C_Mem_Read((I2C_HandleTypeDef*)handle, HTS221_I2C_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, bufp, len, 100) == HAL_OK) + { + return 0; + } + return -1; +} + +/* Initialize ST device context */ +static stmdev_ctx_t dev_ctx = { + .write_reg = platform_write, + .read_reg = platform_read, + .handle = &hi2c1 +}; + +/* Initialize the sensor */ +sensor_status_t sensor_init(void) +{ + printf("[Sensor] Initializing I2C sensor...\r\n"); + + /* Check if the physical device is responsive on the I2C bus */ + if (HAL_I2C_IsDeviceReady(&hi2c1, HTS221_I2C_ADDRESS, 3, 100) != HAL_OK) + { + printf("[Sensor] WARNING: Physical HTS221 not detected on I2C1 (no ack). Switching to MOCK mode.\r\n"); + mock_mode_active = 1; + return SENSOR_OK; + } + + /* Read WHO_AM_I register */ + whoamI = 0; + if (hts221_device_id_get(&dev_ctx, &whoamI) != 0 || whoamI != HTS221_ID) + { + printf("[Sensor] WARNING: WHO_AM_I failed (got 0x%02X, expected 0x%02X). Switching to MOCK mode.\r\n", whoamI, HTS221_ID); + mock_mode_active = 1; + return SENSOR_OK; + } + + printf("[Sensor] Physical HTS221 detected (WHO_AM_I = 0x%02X).\r\n", whoamI); + + /* Read humidity calibration coefficients */ + hts221_hum_adc_point_0_get(&dev_ctx, &lin_hum.x0); + hts221_hum_rh_point_0_get(&dev_ctx, &lin_hum.y0); + hts221_hum_adc_point_1_get(&dev_ctx, &lin_hum.x1); + hts221_hum_rh_point_1_get(&dev_ctx, &lin_hum.y1); + + /* Read temperature calibration coefficients */ + hts221_temp_adc_point_0_get(&dev_ctx, &lin_temp.x0); + hts221_temp_deg_point_0_get(&dev_ctx, &lin_temp.y0); + hts221_temp_adc_point_1_get(&dev_ctx, &lin_temp.x1); + hts221_temp_deg_point_1_get(&dev_ctx, &lin_temp.y1); + + /* Enable Block Data Update (BDU) - prevents reading partial data */ + hts221_block_data_update_set(&dev_ctx, PROPERTY_ENABLE); + + /* Set Output Data Rate to 1Hz */ + hts221_data_rate_set(&dev_ctx, HTS221_ODR_1Hz); + + /* Power on the device */ + hts221_power_on_set(&dev_ctx, PROPERTY_ENABLE); + + printf("[Sensor] Physical HTS221 initialized successfully.\r\n"); + mock_mode_active = 0; + return SENSOR_OK; +} + +/* Read sensor data */ +sensor_status_t sensor_read(float *temp, float *hum) +{ + if (mock_mode_active) + { + /* Generate simulated values using a slow sine wave + small noise */ + uint32_t tick = HAL_GetTick(); + + /* Simulated temperature: 22.0°C base + 3.0°C variation */ + float sim_temp = 22.0f + 3.0f * sinf((float)tick / 10000.0f); + + /* Simulated humidity: 55.0% base + 10.0% variation */ + float sim_hum = 55.0f + 10.0f * cosf((float)tick / 15000.0f); + + /* Add a tiny bit of noise (pseudo-random based on tick) */ + float noise = (float)(tick % 100) / 500.0f - 0.1f; // -0.1 to +0.1 + sim_temp += noise; + sim_hum += noise * 5.0f; // humidity noise is larger + + /* Keep humidity within physical limits */ + if (sim_hum < 0.0f) sim_hum = 0.0f; + if (sim_hum > 100.0f) sim_hum = 100.0f; + + *temp = sim_temp; + *hum = sim_hum; + return SENSOR_OK; + } + + /* Physical sensor read */ + hts221_status_reg_t status; + int32_t ret = hts221_status_get(&dev_ctx, &status); + if (ret != 0) + { + return SENSOR_ERROR; + } + + /* Wait/check if new data is ready */ + if (status.t_da && status.h_da) + { + union { + int16_t i16; + uint8_t u8[2]; + } raw_data; + + /* Read raw humidity */ + memset(raw_data.u8, 0, sizeof(raw_data.u8)); + if (hts221_humidity_raw_get(&dev_ctx, raw_data.u8) == 0) + { + float rh = linear_interpolation(&lin_hum, raw_data.i16); + if (rh < 0.0f) rh = 0.0f; + if (rh > 100.0f) rh = 100.0f; + *hum = rh; + } + else + { + return SENSOR_ERROR; + } + + /* Read raw temperature */ + memset(raw_data.u8, 0, sizeof(raw_data.u8)); + if (hts221_temperature_raw_get(&dev_ctx, raw_data.u8) == 0) + { + *temp = linear_interpolation(&lin_temp, raw_data.i16); + } + else + { + return SENSOR_ERROR; + } + + return SENSOR_OK; + } + + /* If data wasn't ready yet, return last known values or wait */ + return SENSOR_ERROR; +} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_conf.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_conf.h index 0f275c74..4f134d9b 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_conf.h +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_conf.h @@ -52,7 +52,7 @@ /* #define HAL_SRAM_MODULE_ENABLED */ /* #define HAL_SDRAM_MODULE_ENABLED */ /* #define HAL_HASH_MODULE_ENABLED */ -/* #define HAL_I2C_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED /* #define HAL_I2S_MODULE_ENABLED */ /* #define HAL_IWDG_MODULE_ENABLED */ /* #define HAL_LPTIM_MODULE_ENABLED */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c index d17dc1da..d8c3a429 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/stm32f7xx_hal_msp.c @@ -361,5 +361,50 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd) } /* USER CODE BEGIN 1 */ +void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + if(hi2c->Instance==I2C1) + { + /* Initializes the peripherals clock */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1; + PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) + { + Error_Handler(); + } + + __HAL_RCC_GPIOB_CLK_ENABLE(); + + /**I2C1 GPIO Configuration + PB8 ------> I2C1_SCL + PB9 ------> I2C1_SDA + */ + GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_I2C1_CLK_ENABLE(); + } +} + +void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) +{ + if(hi2c->Instance==I2C1) + { + /* Peripheral clock disable */ + __HAL_RCC_I2C1_CLK_DISABLE(); + /**I2C1 GPIO Configuration + PB8 ------> I2C1_SCL + PB9 ------> I2C1_SDA + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9); + } +} /* USER CODE END 1 */ From 12b21de4d0ef7f518acee38b84528e68329b4884 Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Sun, 5 Jul 2026 19:52:05 +0400 Subject: [PATCH 5/9] refactored sensor driver and mock sensor for network_station demo Signed-off-by: alieissa-commits --- .../STM32F767ZI-Nucleo/CMakeLists.txt | 2 +- .../app/demos/network_station/CMakeLists.txt | 1 + .../app/demos/network_station/mock_sensor.c | 49 +++++++++++++++++++ .../app/demos/network_station/sensor.h | 4 ++ .../app/demos/network_station/sensor_driver.c | 26 ++-------- 5 files changed, 58 insertions(+), 24 deletions(-) create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mock_sensor.c diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt index 8e09bab7..82974ee9 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt @@ -9,7 +9,7 @@ # Contributors: # Ali Eissa - 2026 version. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) set(CMAKE_C_STANDARD 99) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt index 63eb512a..4df0338b 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(${PROJECT_NAME} main.c sensor_driver.c + mock_sensor.c hts221_reg.c ) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mock_sensor.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mock_sensor.c new file mode 100644 index 00000000..a5f5fdb5 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mock_sensor.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#include "sensor.h" +#include "stm32f7xx_hal.h" +#include + +/* Initialize mock sensor */ +sensor_status_t mock_sensor_init(void) +{ + /* No hardware initialization needed for mock sensor */ + return SENSOR_OK; +} + +/* Read mock sensor data */ +sensor_status_t mock_sensor_read(float *temp, float *hum) +{ + /* Generate simulated values using a slow sine wave + small noise */ + uint32_t tick = HAL_GetTick(); + + /* Simulated temperature: 22.0°C base + 3.0°C variation */ + float sim_temp = 22.0f + 3.0f * sinf((float)tick / 10000.0f); + + /* Simulated humidity: 55.0% base + 10.0% variation */ + float sim_hum = 55.0f + 10.0f * cosf((float)tick / 15000.0f); + + /* Add a tiny bit of noise (pseudo-random based on tick) */ + float noise = (float)(tick % 100) / 500.0f - 0.1f; // -0.1 to +0.1 + sim_temp += noise; + sim_hum += noise * 5.0f; // humidity noise is larger + + /* Keep humidity within physical limits */ + if (sim_hum < 0.0f) sim_hum = 0.0f; + if (sim_hum > 100.0f) sim_hum = 100.0f; + + *temp = sim_temp; + *hum = sim_hum; + return SENSOR_OK; +} diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h index 2fe39a13..fa83a174 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor.h @@ -33,4 +33,8 @@ typedef enum { sensor_status_t sensor_init(void); sensor_status_t sensor_read(float *temp, float *hum); +/* Mock Sensor API (used internally by sensor_driver when physical sensor is missing) */ +sensor_status_t mock_sensor_init(void); +sensor_status_t mock_sensor_read(float *temp, float *hum); + #endif /* SENSOR_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c index 7f139c19..aacc9403 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/sensor_driver.c @@ -89,7 +89,7 @@ sensor_status_t sensor_init(void) { printf("[Sensor] WARNING: Physical HTS221 not detected on I2C1 (no ack). Switching to MOCK mode.\r\n"); mock_mode_active = 1; - return SENSOR_OK; + return mock_sensor_init(); } /* Read WHO_AM_I register */ @@ -98,7 +98,7 @@ sensor_status_t sensor_init(void) { printf("[Sensor] WARNING: WHO_AM_I failed (got 0x%02X, expected 0x%02X). Switching to MOCK mode.\r\n", whoamI, HTS221_ID); mock_mode_active = 1; - return SENSOR_OK; + return mock_sensor_init(); } printf("[Sensor] Physical HTS221 detected (WHO_AM_I = 0x%02X).\r\n", whoamI); @@ -134,27 +134,7 @@ sensor_status_t sensor_read(float *temp, float *hum) { if (mock_mode_active) { - /* Generate simulated values using a slow sine wave + small noise */ - uint32_t tick = HAL_GetTick(); - - /* Simulated temperature: 22.0°C base + 3.0°C variation */ - float sim_temp = 22.0f + 3.0f * sinf((float)tick / 10000.0f); - - /* Simulated humidity: 55.0% base + 10.0% variation */ - float sim_hum = 55.0f + 10.0f * cosf((float)tick / 15000.0f); - - /* Add a tiny bit of noise (pseudo-random based on tick) */ - float noise = (float)(tick % 100) / 500.0f - 0.1f; // -0.1 to +0.1 - sim_temp += noise; - sim_hum += noise * 5.0f; // humidity noise is larger - - /* Keep humidity within physical limits */ - if (sim_hum < 0.0f) sim_hum = 0.0f; - if (sim_hum > 100.0f) sim_hum = 100.0f; - - *temp = sim_temp; - *hum = sim_hum; - return SENSOR_OK; + return mock_sensor_read(temp, hum); } /* Physical sensor read */ From 25025e4a6f2de8aa4370af0560f5c3dc78b383a1 Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Sun, 5 Jul 2026 21:01:12 +0400 Subject: [PATCH 6/9] feat: added MQTT data communication over the internet. Signed-off-by: alieissa-commits --- .../app/demos/network_station/CMakeLists.txt | 2 + .../app/demos/network_station/main.c | 416 +++++++++++++++++- .../app/demos/network_station/mqtt_config.h | 21 + .../app/demos/network_station/nx_user.h | 22 + .../STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 | 1 + 5 files changed, 442 insertions(+), 20 deletions(-) create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mqtt_config.h create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/nx_user.h diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt index 4df0338b..0ea1210b 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt @@ -36,6 +36,8 @@ target_link_libraries(${PROJECT_NAME} board_bsp threadx filex + netxduo + netx_stm32_driver stm32cubef7 ) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c index dddf408b..827efe45 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c @@ -13,27 +13,59 @@ #include "tx_api.h" #include "fx_api.h" +#include "nx_api.h" +#include "nxd_dhcp_client.h" +#include "nxd_dns.h" +#include "nxd_mqtt_client.h" #include "board_init.h" #include "sensor.h" +#include "mqtt_config.h" #include +#include #define DEMO_STACK_SIZE 2048 -#define DEMO_BYTE_POOL_SIZE 20480 /* Increased byte pool size to accommodate FileX memory allocations */ +#define DEMO_BYTE_POOL_SIZE 65536 /* Increased byte pool size to accommodate NetX Duo and ThreadX stacks */ #define SENSOR_QUEUE_MAX_MSGS 10 -#define SENSOR_MSG_WORDS 3 /* 12 bytes = 3 ULONGs */ +#define SENSOR_MSG_WORDS 3 /* 12 bytes = 3 ULONGs */ #define RAM_DISK_SIZE 32768 /* 32 KB RAM Disk */ #define RAM_DISK_SECTOR_SIZE 512 -/* Thread X objects */ +/* NetX Duo Configuration Constants */ +#define PACKET_SIZE 1536 +#define PACKET_POOL_SIZE (PACKET_SIZE * 20) +#define ARP_CACHE_SIZE 1024 + +/* ThreadX objects */ TX_THREAD sensor_thread; TX_THREAD logger_thread; +TX_THREAD network_thread; +TX_THREAD status_thread; +TX_THREAD dhcp_thread; + TX_QUEUE sensor_queue; +TX_QUEUE network_queue; TX_BYTE_POOL byte_pool_sensor; /* FileX objects */ FX_MEDIA ram_disk; FX_FILE log_file; +/* NetX Duo objects */ +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_DHCP dhcp_client; +NX_DNS dns_client; +NXD_MQTT_CLIENT mqtt_client; + +/* Connection States shared with Status Thread */ +static volatile UINT ip_resolved = NX_FALSE; +static volatile UINT mqtt_connected = NX_FALSE; +static char mqtt_topic[64]; + +/* Place the NetX Duo packet pool in the .nx_data section (uncacheable memory) */ +__attribute__((section(".NetXPoolSection"))) uint8_t packet_pool_area[PACKET_POOL_SIZE]; +static uint8_t arp_cache_area[ARP_CACHE_SIZE]; + /* Memory area for byte pool */ static uint8_t pool_memory[DEMO_BYTE_POOL_SIZE]; @@ -41,12 +73,16 @@ static uint8_t pool_memory[DEMO_BYTE_POOL_SIZE]; static uint8_t ram_disk_memory[RAM_DISK_SIZE]; static uint8_t cache_buffer[RAM_DISK_SECTOR_SIZE]; -/* External FileX RAM driver prototype */ +/* External FileX and NetX driver prototypes */ VOID _fx_ram_driver(FX_MEDIA *media_ptr); +extern VOID nx_stm32_eth_driver(NX_IP_DRIVER *driver_req_ptr); /* Thread entry prototypes */ static void sensor_thread_entry(ULONG thread_input); static void logger_thread_entry(ULONG thread_input); +static void network_thread_entry(ULONG thread_input); +static void status_thread_entry(ULONG thread_input); +static void dhcp_thread_entry(ULONG thread_input); int main(void) { @@ -54,9 +90,12 @@ int main(void) board_init(); printf("\r\n==================================================\r\n"); - printf(" Network Environmental Station Demo - Phase 2 \r\n"); + printf(" Network Environmental Station Demo - Phase 3 \r\n"); printf("==================================================\r\n"); + /* Initialize the Ethernet hardware, MAC, and wait for link to be established */ + board_ethernet_init(); + /* Enter the ThreadX kernel */ tx_kernel_enter(); @@ -66,63 +105,134 @@ int main(void) void tx_application_define(void *first_unused_memory) { CHAR *pointer; + (void)first_unused_memory; /* Create a byte memory pool from which to allocate the thread stacks and queues */ if (tx_byte_pool_create(&byte_pool_sensor, "sensor_pool", pool_memory, DEMO_BYTE_POOL_SIZE) != TX_SUCCESS) { - printf("[System] Error: Failed to create sensor byte pool\r\n"); Error_Handler(); } - /* Allocate the message queue memory */ + /* Allocate and create sensor message queue */ if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, SENSOR_QUEUE_MAX_MSGS * SENSOR_MSG_WORDS * sizeof(ULONG), TX_NO_WAIT) != TX_SUCCESS) { - printf("[System] Error: Failed to allocate queue memory\r\n"); Error_Handler(); } - - /* Create the sensor message queue */ if (tx_queue_create(&sensor_queue, "sensor_queue", SENSOR_MSG_WORDS, pointer, SENSOR_QUEUE_MAX_MSGS * SENSOR_MSG_WORDS * sizeof(ULONG)) != TX_SUCCESS) { - printf("[System] Error: Failed to create sensor message queue\r\n"); + Error_Handler(); + } + + /* Allocate and create network message queue */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, + SENSOR_QUEUE_MAX_MSGS * SENSOR_MSG_WORDS * sizeof(ULONG), TX_NO_WAIT) != TX_SUCCESS) + { + Error_Handler(); + } + if (tx_queue_create(&network_queue, "network_queue", SENSOR_MSG_WORDS, pointer, + SENSOR_QUEUE_MAX_MSGS * SENSOR_MSG_WORDS * sizeof(ULONG)) != TX_SUCCESS) + { Error_Handler(); } /* Allocate the stack for the sensor thread */ if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) { - printf("[System] Error: Failed to allocate sensor thread stack\r\n"); Error_Handler(); } - - /* Create the sensor thread */ + /* Create the sensor thread (Priority 3) */ if (tx_thread_create(&sensor_thread, "sensor_thread", sensor_thread_entry, 0, pointer, DEMO_STACK_SIZE, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) { - printf("[System] Error: Failed to create sensor thread\r\n"); Error_Handler(); } /* Allocate the stack for the logger thread */ if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) { - printf("[System] Error: Failed to allocate logger thread stack\r\n"); Error_Handler(); } - - /* Create the logger thread (Priority 5, lower priority than sensor_thread) */ + /* Create the logger thread (Priority 5) */ if (tx_thread_create(&logger_thread, "logger_thread", logger_thread_entry, 0, pointer, DEMO_STACK_SIZE, 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) { - printf("[System] Error: Failed to create logger thread\r\n"); Error_Handler(); } - printf("[System] ThreadX and FileX objects created successfully.\r\n"); + /* Allocate the stack for the network telemetry thread */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) + { + Error_Handler(); + } + /* Create the network thread (Priority 4) */ + if (tx_thread_create(&network_thread, "network_thread", network_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) + { + Error_Handler(); + } + + /* Allocate the stack for the status monitor thread */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, 1024, TX_NO_WAIT) != TX_SUCCESS) + { + Error_Handler(); + } + /* Create the status thread (Priority 6) */ + if (tx_thread_create(&status_thread, "status_thread", status_thread_entry, 0, + pointer, 1024, + 6, 6, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) + { + Error_Handler(); + } + + /* Initialize NetX Duo System */ + nx_system_initialize(); + + /* Create the packet pool in our uncacheable section */ + if (nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", + PACKET_SIZE, packet_pool_area, PACKET_POOL_SIZE) != NX_SUCCESS) { + printf("[NetX] Failed to create packet pool.\r\n"); + Error_Handler(); + } + + /* Allocate the stack for NetX IP thread */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) + { + Error_Handler(); + } + + /* Create the IP instance using the STM32 Ethernet driver */ + if (nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), + 0xFFFFFF00UL, &pool_0, nx_stm32_eth_driver, + pointer, DEMO_STACK_SIZE, 1) != NX_SUCCESS) { + printf("[NetX] Failed to create IP instance.\r\n"); + Error_Handler(); + } + + /* Enable ARP, TCP, UDP, and ICMP */ + nx_arp_enable(&ip_0, (VOID *)arp_cache_area, ARP_CACHE_SIZE); + nx_tcp_enable(&ip_0); + nx_udp_enable(&ip_0); + nx_icmp_enable(&ip_0); + + /* Allocate the stack for the DHCP client thread */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) + { + Error_Handler(); + } + + /* Create DHCP/Link Monitor Thread (Priority 2) */ + if (tx_thread_create(&dhcp_thread, "DHCP/Link Thread", dhcp_thread_entry, 0, + pointer, DEMO_STACK_SIZE, 2, 2, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS) + { + Error_Handler(); + } + + printf("[System] ThreadX, FileX, and NetX objects initialized successfully.\r\n"); } static void sensor_thread_entry(ULONG thread_input) @@ -279,6 +389,272 @@ static void logger_thread_entry(ULONG thread_input) printf("[Logger Thread] Error: Failed to write to log file! (0x%02X)\r\n", status); } } + + /* Forward the sensor reading to the network telemetry queue */ + if (tx_queue_send(&network_queue, &msg, TX_NO_WAIT) != TX_SUCCESS) + { + printf("[Logger Thread] WARNING: Network queue is full, telemetry message dropped.\r\n"); + } + } + } +} + +static void dhcp_thread_entry(ULONG thread_input) +{ + (void)thread_input; + ULONG ip_address; + ULONG network_mask; + ULONG actual_status; + UINT prev_link_up = NX_FALSE; + extern int32_t nx_eth_phy_get_link_state(void); + + /* Create the DHCP client instance once */ + nx_dhcp_create(&dhcp_client, &ip_0, "DHCP Client"); + + printf("[NetX] Network Monitor Thread Started.\r\n"); + + while (1) + { + /* Poll the physical link state */ + int32_t phy_state = nx_eth_phy_get_link_state(); + UINT curr_link_up = (phy_state > 1) ? NX_TRUE : NX_FALSE; + + if (curr_link_up != prev_link_up) + { + if (curr_link_up) + { + printf("[NetX] Ethernet cable connected! Enabling link...\r\n"); + UINT status = nx_ip_driver_direct_command(&ip_0, NX_LINK_ENABLE, &actual_status); + if (status == NX_SUCCESS || status == NX_ALREADY_ENABLED) + { + printf("[NetX] Ethernet link is UP! Starting DHCP client...\r\n"); + nx_dhcp_start(&dhcp_client); + + /* Wait up to 10 seconds for IP address resolution */ + if (nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &ip_address, 1000) == NX_SUCCESS) + { + nx_ip_address_get(&ip_0, &ip_address, &network_mask); + printf("[NetX] DHCP Success!\r\n"); + printf("[NetX] IP Address : %lu.%lu.%lu.%lu\r\n", + (ip_address >> 24) & 0xFF, (ip_address >> 16) & 0xFF, + (ip_address >> 8) & 0xFF, ip_address & 0xFF); + ip_resolved = NX_TRUE; + } + else + { + printf("[NetX] DHCP Timeout! Using static IP 192.168.0.100\r\n"); + nx_dhcp_stop(&dhcp_client); + nx_ip_address_set(&ip_0, IP_ADDRESS(192, 168, 0, 100), 0xFFFFFF00UL); + ip_resolved = NX_TRUE; + } + } + else + { + printf("[NetX] Failed to enable driver link: 0x%02x\r\n", status); + } + } + else + { + printf("[NetX] Ethernet cable disconnected! Disabling link...\r\n"); + ip_resolved = NX_FALSE; + nx_dhcp_stop(&dhcp_client); + nx_ip_driver_direct_command(&ip_0, NX_LINK_DISABLE, &actual_status); + /* Reset IP address to 0.0.0.0 */ + nx_ip_address_set(&ip_0, IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL); + } + prev_link_up = curr_link_up; } + + tx_thread_sleep(100); /* Poll every 1 second (100 ticks) */ + } +} + +static void network_thread_entry(ULONG thread_input) +{ + (void)thread_input; + UINT status; + sensor_msg_t msg; + char payload[128]; + NXD_ADDRESS broker_ip; + VOID *mqtt_stack; + char client_id[32]; + uint32_t uid_w0 = HAL_GetUIDw0(); + + /* Format unique topic and client ID using board's hardware unique ID */ + snprintf(client_id, sizeof(client_id), "stm32f767_%08lX", (unsigned long)uid_w0); + snprintf(mqtt_topic, sizeof(mqtt_topic), "samplex/env_station/%s/telemetry", client_id); + + printf("[Network Thread] Starting Network Telemetry Thread...\r\n"); + + /* Allocate stack for internal MQTT thread from our byte memory pool */ + if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &mqtt_stack, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) + { + Error_Handler(); + } + + /* Create the NetX Duo MQTT Client Instance */ + status = nxd_mqtt_client_create(&mqtt_client, "Samplex Client", client_id, strlen(client_id), + &ip_0, &pool_0, mqtt_stack, DEMO_STACK_SIZE, 4, NX_NULL, 0); + if (status != NX_SUCCESS) + { + printf("[MQTT] Error: Failed to create MQTT client (0x%02X)\r\n", status); + Error_Handler(); + } + + /* Reconnection/Publish state machine */ + while (1) + { + /* 1. Wait until network link is established and IP is resolved */ + while (!ip_resolved) + { + tx_thread_sleep(100); + } + + /* 2. Initialize DNS Client if not already running */ + static UINT dns_initialized = NX_FALSE; + if (!dns_initialized) + { + ULONG dns_server = IP_ADDRESS(8, 8, 8, 8); /* Fallback to Google DNS */ + UINT size; + nx_dhcp_user_option_retrieve(&dhcp_client, NX_DHCP_OPTION_DNS_SVR, (UCHAR *)&dns_server, &size); + + if (nx_dns_create(&dns_client, &ip_0, (UCHAR *)"DNS Client") == NX_SUCCESS) + { + nx_dns_server_add(&dns_client, dns_server); + dns_initialized = NX_TRUE; + printf("[DNS] DNS Client initialized. Server: %lu.%lu.%lu.%lu\r\n", + (dns_server >> 24) & 0xFF, (dns_server >> 16) & 0xFF, + (dns_server >> 8) & 0xFF, dns_server & 0xFF); + } + else + { + printf("[DNS] Error: Failed to create DNS client! Retrying...\r\n"); + tx_thread_sleep(200); + continue; + } + } + + /* 3. Resolve DNS name of the Mosquitto broker */ + broker_ip.nxd_ip_version = 4; + status = nxd_dns_host_by_name_get(&dns_client, (UCHAR *)MQTT_BROKER_HOST, &broker_ip, 500, 4); + if (status != NX_SUCCESS) + { + printf("[DNS] Error: Failed to resolve broker '%s' (0x%02X). Retrying...\r\n", MQTT_BROKER_HOST, status); + tx_thread_sleep(500); + continue; + } + + printf("[DNS] Resolved '%s' to %lu.%lu.%lu.%lu\r\n", MQTT_BROKER_HOST, + (broker_ip.nxd_ip_address.v4 >> 24) & 0xFF, + (broker_ip.nxd_ip_address.v4 >> 16) & 0xFF, + (broker_ip.nxd_ip_address.v4 >> 8) & 0xFF, + broker_ip.nxd_ip_address.v4 & 0xFF); + + /* 4. Connect to Mosquitto Broker */ + printf("[MQTT] Connecting to broker %s:%d...\r\n", MQTT_BROKER_HOST, MQTT_BROKER_PORT); + status = nxd_mqtt_client_connect(&mqtt_client, &broker_ip, MQTT_BROKER_PORT, + 60, 1, 1000); /* 60s keepalive, clean session, 10s wait */ + if (status != NX_SUCCESS) + { + printf("[MQTT] Error: Connection failed (0x%02X). Retrying...\r\n", status); + tx_thread_sleep(500); + continue; + } + + printf("[MQTT] Connected successfully to Mosquitto broker!\r\n"); + printf("[MQTT] Publishing to topic: %s\r\n", mqtt_topic); + mqtt_connected = NX_TRUE; + + /* 5. Publish Telemetry Loop */ + while (ip_resolved && mqtt_connected) + { + /* Retrieve messages from the network forwarding queue (blocks until available) */ + if (tx_queue_receive(&network_queue, &msg, 500) == TX_SUCCESS) + { + float temp_abs = (msg.temperature < 0.0f) ? -msg.temperature : msg.temperature; + int temp_dec = (int)temp_abs; + int temp_frac = (int)((temp_abs - (float)temp_dec) * 100.0f); + + int hum_dec = (int)msg.humidity; + int hum_frac = (int)((msg.humidity - (float)hum_dec) * 100.0f); + + /* Create JSON payload */ + snprintf(payload, sizeof(payload), + "{\"temp\":%s%d.%02d,\"hum\":%d.%02d,\"ts\":%lu}", + (msg.temperature < 0.0f) ? "-" : "", temp_dec, temp_frac, + hum_dec, hum_frac, (unsigned long)msg.timestamp); + + /* Publish telemetry QoS 0 */ + status = nxd_mqtt_client_publish(&mqtt_client, mqtt_topic, strlen(mqtt_topic), + payload, strlen(payload), 0, 0, 500); + if (status == NX_SUCCESS) + { + printf("[Network Thread] MQTT Published: %s\r\n", payload); + } + else + { + printf("[Network Thread] Error: Publish failed (0x%02X)\r\n", status); + nxd_mqtt_client_disconnect(&mqtt_client); + mqtt_connected = NX_FALSE; + } + } + } + + mqtt_connected = NX_FALSE; + } +} + +static void status_thread_entry(ULONG thread_input) +{ + (void)thread_input; + UINT state = 0; + + printf("[Status Thread] Status Monitor Thread Started.\r\n"); + + while (1) + { + /* 1. Heartbeat Toggle (Green LED1) */ + if (state) + { + LED1_ON(); + } + else + { + LED1_OFF(); + } + state = !state; + + /* 2. Ethernet Connection Indicator (Blue LED2) */ + if (ip_resolved) + { + LED2_ON(); + } + else + { + LED2_OFF(); + } + + /* 3. MQTT Connection / Network Fault Indicator (Red LED3) */ + if (!ip_resolved || !mqtt_connected) + { + /* Blink Red LED if we have no connection */ + static UINT red_state = 0; + if (red_state) + { + LED3_ON(); + } + else + { + LED3_OFF(); + } + red_state = !red_state; + } + else + { + LED3_OFF(); + } + + /* Sleep 500ms */ + tx_thread_sleep(50); } } diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mqtt_config.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mqtt_config.h new file mode 100644 index 00000000..b7dda99d --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/mqtt_config.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#ifndef MQTT_CONFIG_H +#define MQTT_CONFIG_H + +/* Eclipse Foundation Mosquitto test broker as default sandbox */ +#define MQTT_BROKER_HOST "test.mosquitto.org" +#define MQTT_BROKER_PORT 1883 + +#endif /* MQTT_CONFIG_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/nx_user.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/nx_user.h new file mode 100644 index 00000000..48c024c1 --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/nx_user.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#ifndef NX_USER_H +#define NX_USER_H + +#define NX_DISABLE_IPV6 +#define NX_ENABLE_INTERFACE_CAPABILITY +#define NX_PHYSICAL_HEADER 16 +#define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT + +#endif /* NX_USER_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 index 3f7102c1..d0d2f0a1 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 +++ b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.ps1 @@ -98,6 +98,7 @@ Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm3 Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_driver.h" -Destination $NetxDriverDest -Force Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" -Destination $NetxDriverDest -Force Copy-Item -Path "$TempDir/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_phy_driver.h" -Destination $NetxDriverDest -Force +Copy-Item -Path "$TempDir/Projects/STM32F767ZI-Nucleo/Applications/NetXDuo/Nx_TCP_Echo_Client/NetXDuo/Target/nx_stm32_eth_config.h" -Destination $NetxDriverDest -Force # ST modified the HAL ETH driver to match the new H7-style API for NetX Duo, so we must overwrite the default ones Copy-Item -Path "$TempDir/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_eth.c" -Destination "$HalDest/Src" -Force From 5252b6fe47c5b779cf2a2713087a755efa2f9f3a Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Sun, 5 Jul 2026 21:37:44 +0400 Subject: [PATCH 7/9] bug fixes in fetch_sdk.sh Signed-off-by: alieissa-commits --- .../app/demos/network_station/main.c | 17 +++++++++++++---- .../STM32F767ZI-Nucleo/scripts/fetch_sdk.sh | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c index 827efe45..6e5ff8ad 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c @@ -390,10 +390,19 @@ static void logger_thread_entry(ULONG thread_input) } } - /* Forward the sensor reading to the network telemetry queue */ + /* Forward the sensor reading to the network telemetry queue (Evict Oldest policy) */ if (tx_queue_send(&network_queue, &msg, TX_NO_WAIT) != TX_SUCCESS) { - printf("[Logger Thread] WARNING: Network queue is full, telemetry message dropped.\r\n"); + sensor_msg_t discarded_msg; + /* Evict the oldest item at the front of the queue to make room */ + if (tx_queue_receive(&network_queue, &discarded_msg, TX_NO_WAIT) == TX_SUCCESS) + { + printf("[Logger Thread] WARNING: Network queue full. Evicting oldest message (Time: %lu ms).\r\n", + (unsigned long)discarded_msg.timestamp); + } + + /* Try sending the new message again */ + tx_queue_send(&network_queue, &msg, TX_NO_WAIT); } } } @@ -535,8 +544,8 @@ static void network_thread_entry(ULONG thread_input) } /* 3. Resolve DNS name of the Mosquitto broker */ - broker_ip.nxd_ip_version = 4; - status = nxd_dns_host_by_name_get(&dns_client, (UCHAR *)MQTT_BROKER_HOST, &broker_ip, 500, 4); + broker_ip.nxd_ip_version = NX_IP_VERSION_V4; + status = nxd_dns_host_by_name_get(&dns_client, (UCHAR *)MQTT_BROKER_HOST, &broker_ip, 500, NX_IP_VERSION_V4); if (status != NX_SUCCESS) { printf("[DNS] Error: Failed to resolve broker '%s' (0x%02X). Retrying...\r\n", MQTT_BROKER_HOST, status); diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh index 443db778..82b8866e 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh +++ b/STMicroelectronics/STM32F767ZI-Nucleo/scripts/fetch_sdk.sh @@ -87,6 +87,7 @@ cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_d cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_eth_driver.h" "${NETX_DRIVER_DEST}/" cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/lan8742/nx_stm32_phy_driver.c" "${NETX_DRIVER_DEST}/" cp -f "${TEMP_DIR}/Middlewares/ST/netxduo/common/drivers/ethernet/nx_stm32_phy_driver.h" "${NETX_DRIVER_DEST}/" +cp -f "${TEMP_DIR}/Projects/STM32F767ZI-Nucleo/Applications/NetXDuo/Nx_TCP_Echo_Client/NetXDuo/Target/nx_stm32_eth_config.h" "${NETX_DRIVER_DEST}/" # ST modified the HAL ETH driver to match the new H7-style API for NetX Duo, so we must overwrite the default ones cp -f "${TEMP_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_eth.c" "${HAL_DEST}/Src/" From 6498e5215b24717a4f3d35209c251cd75ccca8a2 Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Tue, 7 Jul 2026 20:24:00 +0400 Subject: [PATCH 8/9] feat(stm32f767zi): unified colorized logging and finished network_station demo Signed-off-by: alieissa-commits --- .../STM32F767ZI-Nucleo/CMakeLists.txt | 1 - .../STM32F767ZI-Nucleo/app/ansi_colors.h | 49 +++++++++++ .../STM32F767ZI-Nucleo/app/board_init.c | 20 +++-- .../app/demos/network_station/CMakeLists.txt | 1 + .../app/demos/network_station/main.c | 83 ++++++++++--------- .../app/demos/netx_echo/CMakeLists.txt | 1 + .../app/demos/netx_echo/main.c | 51 ++++++------ .../app/demos/threadx_basic/CMakeLists.txt | 1 + .../app/demos/threadx_basic/main.c | 11 +-- 9 files changed, 140 insertions(+), 78 deletions(-) create mode 100644 STMicroelectronics/STM32F767ZI-Nucleo/app/ansi_colors.h diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt index 82974ee9..bbaef3e8 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/CMakeLists.txt @@ -142,7 +142,6 @@ if(USE_NETXDUO) STM32F767xx USE_HAL_DRIVER STM32F7 - STM32_ETH_HAL_LEGACY ) target_link_libraries(netx_stm32_driver PUBLIC diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/ansi_colors.h b/STMicroelectronics/STM32F767ZI-Nucleo/app/ansi_colors.h new file mode 100644 index 00000000..c1bb61db --- /dev/null +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/ansi_colors.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available + * under the terms of the MIT license which is available at + * https://opensource.org/license/mit. + * + * SPDX-License-Identifier: MIT + * + * Contributors: + * Ali Eissa - 2026 version. + */ + +#ifndef ANSI_COLORS_H +#define ANSI_COLORS_H + +/* ANSI Terminal Escape Codes for Colored Serial Output */ +#define ANSI_RESET "\x1b[0m" +#define ANSI_BOLD "\x1b[1m" + +/* Standard Primary Colors for Banners */ +#define ANSI_RED "\x1b[31m" +#define ANSI_GREEN "\x1b[32m" +#define ANSI_YELLOW "\x1b[33m" +#define ANSI_BLUE "\x1b[34m" +#define ANSI_MAGENTA "\x1b[35m" +#define ANSI_CYAN "\x1b[36m" +#define ANSI_WHITE "\x1b[37m" + +/* Subsystem Tags: Muted Slate Gray (256-color 243) to push them into visual background */ +#define TAG_SYSTEM "\x1b[38;5;243m[System]" +#define TAG_HAL "\x1b[38;5;243m[HAL]" +#define TAG_SENSOR "\x1b[38;5;243m[Sensor Thread]" +#define TAG_LOGGER "\x1b[38;5;243m[Logger Thread]" +#define TAG_NETWORK "\x1b[38;5;243m[NetX]" +#define TAG_NET_THREAD "\x1b[38;5;243m[Network Thread]" +#define TAG_DNS "\x1b[38;5;243m[DNS]" +#define TAG_MQTT "\x1b[38;5;243m[MQTT]" +#define TAG_STATUS "\x1b[38;5;243m[Status Thread]" +#define TAG_ECHO "\x1b[38;5;243m[Echo]" + +/* Message Colors: Soft, pastel feedback colors */ +#define MSG_INFO "\x1b[38;5;250m" /* Soft White/Gray for normal logs */ +#define MSG_SUCCESS "\x1b[38;5;114m" /* Soft Pastel Green for success */ +#define MSG_WARNING "\x1b[38;5;215m" /* Muted Gold/Orange for warnings */ +#define MSG_ERROR "\x1b[38;5;203m" /* Muted Coral/Red for failures */ +#define MSG_METRIC "\x1b[38;5;111m" /* Soft Sky Blue for data/measurements */ + +#endif /* ANSI_COLORS_H */ diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c index a753db19..f944d272 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/board_init.c @@ -16,6 +16,7 @@ #include "tx_api.h" #include #include +#include "ansi_colors.h" /* Global UART handler */ UART_HandleTypeDef huart3; @@ -264,19 +265,26 @@ void board_ethernet_init(void) heth.Init.RxDesc = DMARxDscrTab; heth.Init.RxBuffLen = 1524; - printf("[HAL] Calling HAL_ETH_Init...\r\n"); + printf(TAG_HAL " " MSG_INFO "Calling HAL_ETH_Init...\r\n" ANSI_RESET); HAL_StatusTypeDef status = HAL_ETH_Init(&heth); - printf("[HAL] HAL_ETH_Init returned status: %d\r\n", status); + if (status == HAL_OK) + { + printf(TAG_HAL " " MSG_SUCCESS "HAL_ETH_Init succeeded (status: %d)\r\n" ANSI_RESET, status); + } + else + { + printf(TAG_HAL " " MSG_ERROR "HAL_ETH_Init failed (status: %d)\r\n" ANSI_RESET, status); + } /* Initialize the PHY transceiver and wait for the link to be established. This ensures that when NetX Duo enables the interface during startup, the hardware link is already up, avoiding driver initialization failures. */ extern int32_t nx_eth_phy_init(void); extern int32_t nx_eth_phy_get_link_state(void); - printf("[NetX] Initializing PHY transceiver...\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Initializing PHY transceiver...\r\n" ANSI_RESET); if (nx_eth_phy_init() == 0) { - printf("[NetX] Waiting for Ethernet link (max 3s)...\r\n"); + printf(TAG_NETWORK " " MSG_WARNING "Waiting for Ethernet link (max 3s)...\r\n" ANSI_RESET); uint32_t retries = 300; /* 300 * 10ms = 3 seconds */ while (nx_eth_phy_get_link_state() <= 1) { @@ -284,13 +292,13 @@ void board_ethernet_init(void) retries--; if (retries == 0) { - printf("[NetX] Ethernet link timeout! Cable connected?\r\n"); + printf(TAG_NETWORK " " MSG_ERROR "Ethernet link timeout! Cable connected?\r\n" ANSI_RESET); break; } } if (nx_eth_phy_get_link_state() > 1) { - printf("[NetX] Ethernet link up!\r\n"); + printf(TAG_NETWORK " " MSG_SUCCESS "Ethernet link up!\r\n" ANSI_RESET); } } else diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt index 0ea1210b..1b57b7d6 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/CMakeLists.txt @@ -28,6 +28,7 @@ target_compile_definitions(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) # Link libraries diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c index 6e5ff8ad..bf248063 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/network_station/main.c @@ -22,6 +22,7 @@ #include "mqtt_config.h" #include #include +#include "ansi_colors.h" #define DEMO_STACK_SIZE 2048 #define DEMO_BYTE_POOL_SIZE 65536 /* Increased byte pool size to accommodate NetX Duo and ThreadX stacks */ @@ -89,9 +90,9 @@ int main(void) /* Initialize Board Support Package (BSP) - clock, GPIO, UART, I2C, etc. */ board_init(); - printf("\r\n==================================================\r\n"); - printf(" Network Environmental Station Demo - Phase 3 \r\n"); - printf("==================================================\r\n"); + printf(ANSI_BOLD ANSI_CYAN "\r\n==================================================\r\n" ANSI_RESET); + printf(ANSI_BOLD ANSI_CYAN " Network Environmental Station Demo - Phase 3 \r\n" ANSI_RESET); + printf(ANSI_BOLD ANSI_CYAN "==================================================\r\n" ANSI_RESET); /* Initialize the Ethernet hardware, MAC, and wait for link to be established */ board_ethernet_init(); @@ -195,7 +196,7 @@ void tx_application_define(void *first_unused_memory) /* Create the packet pool in our uncacheable section */ if (nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, packet_pool_area, PACKET_POOL_SIZE) != NX_SUCCESS) { - printf("[NetX] Failed to create packet pool.\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_RED "Failed to create packet pool.\r\n" ANSI_RESET); Error_Handler(); } @@ -209,7 +210,7 @@ void tx_application_define(void *first_unused_memory) if (nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &pool_0, nx_stm32_eth_driver, pointer, DEMO_STACK_SIZE, 1) != NX_SUCCESS) { - printf("[NetX] Failed to create IP instance.\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_RED "Failed to create IP instance.\r\n" ANSI_RESET); Error_Handler(); } @@ -232,7 +233,7 @@ void tx_application_define(void *first_unused_memory) Error_Handler(); } - printf("[System] ThreadX, FileX, and NetX objects initialized successfully.\r\n"); + printf(ANSI_BOLD ANSI_WHITE "[System] " ANSI_GREEN "ThreadX, FileX, and NetX objects initialized successfully.\r\n" ANSI_RESET); } static void sensor_thread_entry(ULONG thread_input) @@ -245,11 +246,11 @@ static void sensor_thread_entry(ULONG thread_input) /* Initialize sensor hardware (or fallback to mock) */ if (sensor_init() != SENSOR_OK) { - printf("[Sensor Thread] Critical Error: Sensor initialization failed!\r\n"); + printf(ANSI_CYAN "[Sensor Thread] " ANSI_RED "Critical Error: Sensor initialization failed!\r\n" ANSI_RESET); Error_Handler(); } - printf("[Sensor Thread] Started polling loop (every 2 seconds).\r\n"); + printf(ANSI_CYAN "[Sensor Thread] " ANSI_WHITE "Started polling loop (every 2 seconds).\r\n" ANSI_RESET); while (1) { @@ -271,17 +272,17 @@ static void sensor_thread_entry(ULONG thread_input) int hum_dec = (int)hum; int hum_frac = (int)((hum - (float)hum_dec) * 100.0f); - printf("[Sensor Thread] Temp: %s%d.%02d C, Hum: %d.%02d %%, Time: %lu ms (Sent to Queue)\r\n", + printf(ANSI_CYAN "[Sensor Thread] " ANSI_WHITE "Temp: %s%d.%02d C, Hum: %d.%02d %%, Time: %lu ms (Sent to Queue)\r\n" ANSI_RESET, (temp < 0.0f) ? "-" : "", temp_dec, temp_frac, hum_dec, hum_frac, (unsigned long)msg.timestamp); } else { - printf("[Sensor Thread] WARNING: Queue is full, message dropped.\r\n"); + printf(ANSI_CYAN "[Sensor Thread] " ANSI_YELLOW "WARNING: Queue is full, message dropped.\r\n" ANSI_RESET); } } else { - printf("[Sensor Thread] Error: Failed to read sensor data.\r\n"); + printf(ANSI_CYAN "[Sensor Thread] " ANSI_RED "Error: Failed to read sensor data.\r\n" ANSI_RESET); } /* Sleep for 2 seconds (assuming 100 ticks per second) */ @@ -296,7 +297,7 @@ static void logger_thread_entry(ULONG thread_input) sensor_msg_t msg; char write_buffer[64]; - printf("[Logger Thread] Starting FileX RAM Disk Logger...\r\n"); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_WHITE "Starting FileX RAM Disk Logger...\r\n" ANSI_RESET); /* Initialize FileX system */ fx_system_initialize(); @@ -318,7 +319,7 @@ static void logger_thread_entry(ULONG thread_input) 1); if (status != FX_SUCCESS) { - printf("[Logger Thread] Error: RAM Disk format failed! (0x%02X)\r\n", status); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_RED "Error: RAM Disk format failed! (0x%02X)\r\n" ANSI_RESET, status); Error_Handler(); } @@ -327,7 +328,7 @@ static void logger_thread_entry(ULONG thread_input) cache_buffer, sizeof(cache_buffer)); if (status != FX_SUCCESS) { - printf("[Logger Thread] Error: RAM Disk open failed! (0x%02X)\r\n", status); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_RED "Error: RAM Disk open failed! (0x%02X)\r\n" ANSI_RESET, status); Error_Handler(); } @@ -335,7 +336,7 @@ static void logger_thread_entry(ULONG thread_input) status = fx_file_create(&ram_disk, "sensor_log.txt"); if (status != FX_SUCCESS && status != FX_ALREADY_CREATED) { - printf("[Logger Thread] Error: Failed to create log file! (0x%02X)\r\n", status); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_RED "Error: Failed to create log file! (0x%02X)\r\n" ANSI_RESET, status); Error_Handler(); } @@ -343,14 +344,14 @@ static void logger_thread_entry(ULONG thread_input) status = fx_file_open(&ram_disk, &log_file, "sensor_log.txt", FX_OPEN_FOR_WRITE); if (status != FX_SUCCESS) { - printf("[Logger Thread] Error: Failed to open log file! (0x%02X)\r\n", status); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_RED "Error: Failed to open log file! (0x%02X)\r\n" ANSI_RESET, status); Error_Handler(); } /* Move the write pointer to the end of the file to append new data */ fx_file_seek(&log_file, log_file.fx_file_current_file_size); - printf("[Logger Thread] RAM Disk initialized. Logging 'sensor_log.txt'...\r\n"); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_GREEN "RAM Disk initialized. Logging 'sensor_log.txt'...\r\n" ANSI_RESET); while (1) { @@ -379,14 +380,14 @@ static void logger_thread_entry(ULONG thread_input) /* Flush the media to commit changes to the RAM Disk immediately */ fx_media_flush(&ram_disk); - printf("[Logger Thread] Logged to RAM Disk: %lu,%s%d.%02d,%d.%02d\r\n", + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_WHITE "Logged to RAM Disk: %lu,%s%d.%02d,%d.%02d\r\n" ANSI_RESET, (unsigned long)msg.timestamp, (msg.temperature < 0.0f) ? "-" : "", temp_dec, temp_frac, hum_dec, hum_frac); } else { - printf("[Logger Thread] Error: Failed to write to log file! (0x%02X)\r\n", status); + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_RED "Error: Failed to write to log file! (0x%02X)\r\n" ANSI_RESET, status); } } @@ -397,7 +398,7 @@ static void logger_thread_entry(ULONG thread_input) /* Evict the oldest item at the front of the queue to make room */ if (tx_queue_receive(&network_queue, &discarded_msg, TX_NO_WAIT) == TX_SUCCESS) { - printf("[Logger Thread] WARNING: Network queue full. Evicting oldest message (Time: %lu ms).\r\n", + printf(ANSI_MAGENTA "[Logger Thread] " ANSI_YELLOW "WARNING: Network queue full. Evicting oldest message (Time: %lu ms).\r\n" ANSI_RESET, (unsigned long)discarded_msg.timestamp); } @@ -420,7 +421,7 @@ static void dhcp_thread_entry(ULONG thread_input) /* Create the DHCP client instance once */ nx_dhcp_create(&dhcp_client, &ip_0, "DHCP Client"); - printf("[NetX] Network Monitor Thread Started.\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_WHITE "Network Monitor Thread Started.\r\n" ANSI_RESET); while (1) { @@ -432,26 +433,26 @@ static void dhcp_thread_entry(ULONG thread_input) { if (curr_link_up) { - printf("[NetX] Ethernet cable connected! Enabling link...\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_YELLOW "Ethernet cable connected! Enabling link...\r\n" ANSI_RESET); UINT status = nx_ip_driver_direct_command(&ip_0, NX_LINK_ENABLE, &actual_status); if (status == NX_SUCCESS || status == NX_ALREADY_ENABLED) { - printf("[NetX] Ethernet link is UP! Starting DHCP client...\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_GREEN "Ethernet link is UP! Starting DHCP client...\r\n" ANSI_RESET); nx_dhcp_start(&dhcp_client); /* Wait up to 10 seconds for IP address resolution */ if (nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &ip_address, 1000) == NX_SUCCESS) { nx_ip_address_get(&ip_0, &ip_address, &network_mask); - printf("[NetX] DHCP Success!\r\n"); - printf("[NetX] IP Address : %lu.%lu.%lu.%lu\r\n", + printf(ANSI_BLUE "[NetX] " ANSI_BOLD ANSI_GREEN "DHCP Success!\r\n" ANSI_RESET); + printf(ANSI_BLUE "[NetX] " ANSI_GREEN "IP Address : %lu.%lu.%lu.%lu\r\n" ANSI_RESET, (ip_address >> 24) & 0xFF, (ip_address >> 16) & 0xFF, (ip_address >> 8) & 0xFF, ip_address & 0xFF); ip_resolved = NX_TRUE; } else { - printf("[NetX] DHCP Timeout! Using static IP 192.168.0.100\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_YELLOW "DHCP Timeout! Using static IP 192.168.0.100\r\n" ANSI_RESET); nx_dhcp_stop(&dhcp_client); nx_ip_address_set(&ip_0, IP_ADDRESS(192, 168, 0, 100), 0xFFFFFF00UL); ip_resolved = NX_TRUE; @@ -459,12 +460,12 @@ static void dhcp_thread_entry(ULONG thread_input) } else { - printf("[NetX] Failed to enable driver link: 0x%02x\r\n", status); + printf(ANSI_BLUE "[NetX] " ANSI_RED "Failed to enable driver link: 0x%02x\r\n" ANSI_RESET, status); } } else { - printf("[NetX] Ethernet cable disconnected! Disabling link...\r\n"); + printf(ANSI_BLUE "[NetX] " ANSI_RED "Ethernet cable disconnected! Disabling link...\r\n" ANSI_RESET); ip_resolved = NX_FALSE; nx_dhcp_stop(&dhcp_client); nx_ip_driver_direct_command(&ip_0, NX_LINK_DISABLE, &actual_status); @@ -493,7 +494,7 @@ static void network_thread_entry(ULONG thread_input) snprintf(client_id, sizeof(client_id), "stm32f767_%08lX", (unsigned long)uid_w0); snprintf(mqtt_topic, sizeof(mqtt_topic), "samplex/env_station/%s/telemetry", client_id); - printf("[Network Thread] Starting Network Telemetry Thread...\r\n"); + printf(ANSI_BLUE "[Network Thread] " ANSI_WHITE "Starting Network Telemetry Thread...\r\n" ANSI_RESET); /* Allocate stack for internal MQTT thread from our byte memory pool */ if (tx_byte_allocate(&byte_pool_sensor, (VOID **) &mqtt_stack, DEMO_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) @@ -506,7 +507,7 @@ static void network_thread_entry(ULONG thread_input) &ip_0, &pool_0, mqtt_stack, DEMO_STACK_SIZE, 4, NX_NULL, 0); if (status != NX_SUCCESS) { - printf("[MQTT] Error: Failed to create MQTT client (0x%02X)\r\n", status); + printf(ANSI_BLUE "[MQTT] " ANSI_RED "Error: Failed to create MQTT client (0x%02X)\r\n" ANSI_RESET, status); Error_Handler(); } @@ -531,13 +532,13 @@ static void network_thread_entry(ULONG thread_input) { nx_dns_server_add(&dns_client, dns_server); dns_initialized = NX_TRUE; - printf("[DNS] DNS Client initialized. Server: %lu.%lu.%lu.%lu\r\n", + printf(ANSI_BLUE "[DNS] " ANSI_GREEN "DNS Client initialized. Server: %lu.%lu.%lu.%lu\r\n" ANSI_RESET, (dns_server >> 24) & 0xFF, (dns_server >> 16) & 0xFF, (dns_server >> 8) & 0xFF, dns_server & 0xFF); } else { - printf("[DNS] Error: Failed to create DNS client! Retrying...\r\n"); + printf(ANSI_BLUE "[DNS] " ANSI_RED "Error: Failed to create DNS client! Retrying...\r\n" ANSI_RESET); tx_thread_sleep(200); continue; } @@ -548,30 +549,30 @@ static void network_thread_entry(ULONG thread_input) status = nxd_dns_host_by_name_get(&dns_client, (UCHAR *)MQTT_BROKER_HOST, &broker_ip, 500, NX_IP_VERSION_V4); if (status != NX_SUCCESS) { - printf("[DNS] Error: Failed to resolve broker '%s' (0x%02X). Retrying...\r\n", MQTT_BROKER_HOST, status); + printf(ANSI_BLUE "[DNS] " ANSI_RED "Error: Failed to resolve broker '%s' (0x%02X). Retrying...\r\n" ANSI_RESET, MQTT_BROKER_HOST, status); tx_thread_sleep(500); continue; } - printf("[DNS] Resolved '%s' to %lu.%lu.%lu.%lu\r\n", MQTT_BROKER_HOST, + printf(ANSI_BLUE "[DNS] " ANSI_GREEN "Resolved '%s' to %lu.%lu.%lu.%lu\r\n" ANSI_RESET, MQTT_BROKER_HOST, (broker_ip.nxd_ip_address.v4 >> 24) & 0xFF, (broker_ip.nxd_ip_address.v4 >> 16) & 0xFF, (broker_ip.nxd_ip_address.v4 >> 8) & 0xFF, broker_ip.nxd_ip_address.v4 & 0xFF); /* 4. Connect to Mosquitto Broker */ - printf("[MQTT] Connecting to broker %s:%d...\r\n", MQTT_BROKER_HOST, MQTT_BROKER_PORT); + printf(ANSI_BLUE "[MQTT] " ANSI_YELLOW "Connecting to broker %s:%d...\r\n" ANSI_RESET, MQTT_BROKER_HOST, MQTT_BROKER_PORT); status = nxd_mqtt_client_connect(&mqtt_client, &broker_ip, MQTT_BROKER_PORT, 60, 1, 1000); /* 60s keepalive, clean session, 10s wait */ if (status != NX_SUCCESS) { - printf("[MQTT] Error: Connection failed (0x%02X). Retrying...\r\n", status); + printf(ANSI_BLUE "[MQTT] " ANSI_RED "Error: Connection failed (0x%02X). Retrying...\r\n" ANSI_RESET, status); tx_thread_sleep(500); continue; } - printf("[MQTT] Connected successfully to Mosquitto broker!\r\n"); - printf("[MQTT] Publishing to topic: %s\r\n", mqtt_topic); + printf(ANSI_BLUE "[MQTT] " ANSI_BOLD ANSI_GREEN "Connected successfully to Mosquitto broker!\r\n" ANSI_RESET); + printf(ANSI_BLUE "[MQTT] " ANSI_WHITE "Publishing to topic: %s\r\n" ANSI_RESET, mqtt_topic); mqtt_connected = NX_TRUE; /* 5. Publish Telemetry Loop */ @@ -598,11 +599,11 @@ static void network_thread_entry(ULONG thread_input) payload, strlen(payload), 0, 0, 500); if (status == NX_SUCCESS) { - printf("[Network Thread] MQTT Published: %s\r\n", payload); + printf(ANSI_BLUE "[Network Thread] " ANSI_GREEN "MQTT Published: %s\r\n" ANSI_RESET, payload); } else { - printf("[Network Thread] Error: Publish failed (0x%02X)\r\n", status); + printf(ANSI_BLUE "[Network Thread] " ANSI_RED "Error: Publish failed (0x%02X)\r\n" ANSI_RESET, status); nxd_mqtt_client_disconnect(&mqtt_client); mqtt_connected = NX_FALSE; } @@ -618,7 +619,7 @@ static void status_thread_entry(ULONG thread_input) (void)thread_input; UINT state = 0; - printf("[Status Thread] Status Monitor Thread Started.\r\n"); + printf(ANSI_YELLOW "[Status Thread] " ANSI_WHITE "Status Monitor Thread Started.\r\n" ANSI_RESET); while (1) { diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt index f3672d6b..c946ce03 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/CMakeLists.txt @@ -25,6 +25,7 @@ target_compile_definitions(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) # Link libraries diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c index 7e762986..13c7ea90 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/netx_echo/main.c @@ -16,6 +16,7 @@ #include "nx_api.h" #include "nxd_dhcp_client.h" #include +#include "ansi_colors.h" #define DEMO_STACK_SIZE 2048 #define PACKET_SIZE 1536 @@ -48,9 +49,9 @@ void tcp_echo_thread_entry(ULONG thread_input); int main(void) { board_init(); - printf("\r\n==========================================\r\n"); - printf("NetX Echo Demo Booted!\r\n"); - printf("==========================================\r\n\r\n"); + printf(ANSI_BOLD ANSI_CYAN "\r\n==========================================\r\n" ANSI_RESET); + printf(ANSI_BOLD ANSI_CYAN "NetX Echo Demo Booted!\r\n" ANSI_RESET); + printf(ANSI_BOLD ANSI_CYAN "==========================================\r\n\r\n" ANSI_RESET); /* Initialize the Ethernet hardware, MAC, and wait for link to be established */ board_ethernet_init(); @@ -68,35 +69,35 @@ void tx_application_define(void *first_unused_memory) /* Create the packet pool in our uncacheable section */ if (nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, packet_pool_area, PACKET_POOL_SIZE) != NX_SUCCESS) { - printf("[NetX] Failed to create packet pool.\r\n"); + printf(TAG_NETWORK " " MSG_ERROR "Failed to create packet pool.\r\n" ANSI_RESET); return; } - printf("[NetX] Packet pool created\r\n"); + printf(TAG_NETWORK " " MSG_SUCCESS "Packet pool created\r\n" ANSI_RESET); /* Create the IP instance using the STM32 Ethernet driver */ if (nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &pool_0, nx_stm32_eth_driver, ip_thread_stack, DEMO_STACK_SIZE, 1) != NX_SUCCESS) { - printf("[NetX] Failed to create IP instance.\r\n"); + printf(TAG_NETWORK " " MSG_ERROR "Failed to create IP instance.\r\n" ANSI_RESET); return; } - printf("[NetX] IP instance created\r\n"); + printf(TAG_NETWORK " " MSG_SUCCESS "IP instance created\r\n" ANSI_RESET); /* Enable ARP, TCP, UDP, and ICMP */ - printf("[NetX] Enabling ARP...\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Enabling ARP...\r\n" ANSI_RESET); nx_arp_enable(&ip_0, (VOID *)arp_cache_area, ARP_CACHE_SIZE); - printf("[NetX] Enabling TCP...\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Enabling TCP...\r\n" ANSI_RESET); nx_tcp_enable(&ip_0); - printf("[NetX] Enabling UDP...\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Enabling UDP...\r\n" ANSI_RESET); nx_udp_enable(&ip_0); - printf("[NetX] Enabling ICMP...\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Enabling ICMP...\r\n" ANSI_RESET); nx_icmp_enable(&ip_0); /* Start DHCP Thread */ - printf("[NetX] Creating DHCP Thread...\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Creating DHCP Thread...\r\n" ANSI_RESET); tx_thread_create(&dhcp_thread, "DHCP Thread", dhcp_thread_entry, 0, dhcp_thread_stack, DEMO_STACK_SIZE, 2, 2, TX_NO_TIME_SLICE, TX_AUTO_START); - printf("[NetX] tx_application_define completed\r\n"); + printf(TAG_NETWORK " " MSG_SUCCESS "tx_application_define completed\r\n" ANSI_RESET); } void dhcp_thread_entry(ULONG thread_input) @@ -111,7 +112,7 @@ void dhcp_thread_entry(ULONG thread_input) /* Create the DHCP client instance once */ nx_dhcp_create(&dhcp_client, &ip_0, "DHCP Client"); - printf("[NetX] Network Monitor Thread Started.\r\n"); + printf(TAG_NETWORK " " MSG_INFO "Network Monitor Thread Started.\r\n" ANSI_RESET); while (1) { @@ -123,28 +124,28 @@ void dhcp_thread_entry(ULONG thread_input) { if (curr_link_up) { - printf("[NetX] Ethernet cable connected! Enabling link...\r\n"); + printf(TAG_NETWORK " " MSG_WARNING "Ethernet cable connected! Enabling link...\r\n" ANSI_RESET); UINT status = nx_ip_driver_direct_command(&ip_0, NX_LINK_ENABLE, &actual_status); if (status == NX_SUCCESS || status == NX_ALREADY_ENABLED) { - printf("[NetX] Ethernet link is UP! Starting DHCP client...\r\n"); + printf(TAG_NETWORK " " MSG_SUCCESS "Ethernet link is UP! Starting DHCP client...\r\n" ANSI_RESET); nx_dhcp_start(&dhcp_client); /* Wait up to 10 seconds for IP address resolution */ if (nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &ip_address, 1000) == NX_SUCCESS) { nx_ip_address_get(&ip_0, &ip_address, &network_mask); - printf("[NetX] DHCP Success!\r\n"); - printf("[NetX] IP Address : %lu.%lu.%lu.%lu\r\n", + printf(TAG_NETWORK " " ANSI_BOLD MSG_SUCCESS "DHCP Success!\r\n" ANSI_RESET); + printf(TAG_NETWORK " " MSG_SUCCESS "IP Address : %lu.%lu.%lu.%lu\r\n" ANSI_RESET, (ip_address >> 24) & 0xFF, (ip_address >> 16) & 0xFF, (ip_address >> 8) & 0xFF, ip_address & 0xFF); - printf("[NetX] Subnet Mask: %lu.%lu.%lu.%lu\r\n", + printf(TAG_NETWORK " " MSG_SUCCESS "Subnet Mask: %lu.%lu.%lu.%lu\r\n" ANSI_RESET, (network_mask >> 24) & 0xFF, (network_mask >> 16) & 0xFF, (network_mask >> 8) & 0xFF, network_mask & 0xFF); } else { - printf("[NetX] DHCP Timeout! Using static IP 192.168.0.100\r\n"); + printf(TAG_NETWORK " " MSG_WARNING "DHCP Timeout! Using static IP 192.168.0.100\r\n" ANSI_RESET); nx_dhcp_stop(&dhcp_client); nx_ip_address_set(&ip_0, IP_ADDRESS(192, 168, 0, 100), 0xFFFFFF00UL); } @@ -159,12 +160,12 @@ void dhcp_thread_entry(ULONG thread_input) } else { - printf("[NetX] Failed to enable driver link: 0x%02x\r\n", status); + printf(TAG_NETWORK " " MSG_ERROR "Failed to enable driver link: 0x%02x\r\n" ANSI_RESET, status); } } else { - printf("[NetX] Ethernet cable disconnected! Disabling link...\r\n"); + printf(TAG_NETWORK " " MSG_ERROR "Ethernet cable disconnected! Disabling link...\r\n" ANSI_RESET); nx_dhcp_stop(&dhcp_client); nx_ip_driver_direct_command(&ip_0, NX_LINK_DISABLE, &actual_status); /* Reset IP address to 0.0.0.0 */ @@ -184,7 +185,7 @@ void tcp_echo_thread_entry(ULONG thread_input) nx_tcp_socket_create(&ip_0, &echo_socket, "Echo Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 512, NX_NULL, NX_NULL); - printf("[Echo] TCP Echo Server listening on port %d\r\n", ECHO_SERVER_PORT); + printf(TAG_ECHO " " MSG_INFO "TCP Echo Server listening on port %d\r\n" ANSI_RESET, ECHO_SERVER_PORT); while (1) { if (nx_tcp_server_socket_listen(&ip_0, ECHO_SERVER_PORT, &echo_socket, 5, NX_NULL) != NX_SUCCESS) { @@ -193,14 +194,14 @@ void tcp_echo_thread_entry(ULONG thread_input) } if (nx_tcp_server_socket_accept(&echo_socket, NX_WAIT_FOREVER) == NX_SUCCESS) { - printf("[Echo] Client connected.\r\n"); + printf(TAG_ECHO " " MSG_SUCCESS "Client connected.\r\n" ANSI_RESET); while (nx_tcp_socket_receive(&echo_socket, &packet_ptr, NX_WAIT_FOREVER) == NX_SUCCESS) { /* Echo the packet back */ nx_tcp_socket_send(&echo_socket, packet_ptr, NX_WAIT_FOREVER); } - printf("[Echo] Client disconnected.\r\n"); + printf(TAG_ECHO " " MSG_WARNING "Client disconnected.\r\n" ANSI_RESET); nx_tcp_socket_disconnect(&echo_socket, NX_WAIT_FOREVER); nx_tcp_server_socket_unaccept(&echo_socket); } diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt index 9d269018..b1b76fe6 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/CMakeLists.txt @@ -25,6 +25,7 @@ target_compile_definitions(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) # Link libraries diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/main.c b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/main.c index ff5fb791..2ecd58cf 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/main.c +++ b/STMicroelectronics/STM32F767ZI-Nucleo/app/demos/threadx_basic/main.c @@ -14,6 +14,7 @@ #include "board_init.h" #include "tx_api.h" #include +#include "ansi_colors.h" /* --- ThreadX Resource Definitions --- */ @@ -138,9 +139,9 @@ void green_thread_entry(ULONG thread_input) { (void)thread_input; - printf("\r\n==========================================\r\n"); - printf("ThreadX Multitasking Edge Node Demo Booted!\r\n"); - printf("==========================================\r\n\r\n"); + printf(ANSI_BOLD ANSI_CYAN "\r\n==========================================\r\n" ANSI_RESET); + printf(ANSI_BOLD ANSI_CYAN "ThreadX Multitasking Edge Node Demo Booted!\r\n" ANSI_RESET); + printf(ANSI_BOLD ANSI_CYAN "==========================================\r\n\r\n" ANSI_RESET); while (1) { @@ -210,7 +211,7 @@ void logger_thread_entry(ULONG thread_input) /* Block until a message arrives in the queue */ if (tx_queue_receive(&msg_queue, &received_ticks, TX_WAIT_FOREVER) == TX_SUCCESS) { - printf("[LOG] Button Pressed! System Tick Count: %lu\r\n", received_ticks); + printf("\x1b[38;5;243m[LOG]" ANSI_RESET " " MSG_SUCCESS "Button Pressed! System Tick Count: %lu\r\n" ANSI_RESET, received_ticks); } } } @@ -304,7 +305,7 @@ void input_thread_entry(ULONG thread_input) if (line_index > 0) { line_buffer[line_index] = '\0'; - printf(" -> [CONSOLE] Received string: \"%s\"\r\n", line_buffer); + printf(" -> \x1b[38;5;243m[CONSOLE]" ANSI_RESET " " MSG_INFO "Received string: \"%s\"\r\n" ANSI_RESET, line_buffer); /* Flash LD3 to signal successful reception */ LED3_ON(); From 606576b7fc26b826d9b5b5075c1175735e85e034 Mon Sep 17 00:00:00 2001 From: alieissa-commits Date: Tue, 7 Jul 2026 20:52:57 +0400 Subject: [PATCH 9/9] modified readme.md Signed-off-by: alieissa-commits --- .../STM32F767ZI-Nucleo/README.md | 88 ++++++++++--------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/STMicroelectronics/STM32F767ZI-Nucleo/README.md b/STMicroelectronics/STM32F767ZI-Nucleo/README.md index 1f4c0c57..6d00171e 100644 --- a/STMicroelectronics/STM32F767ZI-Nucleo/README.md +++ b/STMicroelectronics/STM32F767ZI-Nucleo/README.md @@ -1,6 +1,6 @@ # STM32F767ZI-Nucleo Board Enablement Demos -This directory contains the Board Support Package (BSP) static library (`board_bsp`) and build configurations for running the **Eclipse ThreadX RTOS** and **NetX Duo TCP/IP stack** on the **STMicroelectronics NUCLEO-F767ZI** evaluation board (ARM Cortex-M7). +This directory contains the Board Support Package (BSP) static library (`board_bsp`) and build configurations for running the **Eclipse ThreadX RTOS**, **FileX Embedded File System**, and **NetX Duo TCP/IP stack** on the **STMicroelectronics NUCLEO-F767ZI** evaluation board (ARM Cortex-M7). The project features a decoupled static BSP library that hides all low-level hardware initializations (clocks, GPIO, MPU, DMA descriptors, and interrupts) from the application code. @@ -13,6 +13,7 @@ Use the `ACTIVE_DEMO` CMake variable to select which demo to compile: | Demo Name | Description | Targets | | :--- | :--- | :--- | | **`netx_echo`** *(Default)* | Dynamic network state machine monitoring cable hot-plugging, DHCP IP configuration, and a TCP Echo Server listening on port 7. | ThreadX, NetX Duo | +| **`network_station`** | Complete Environmental Station demo polling temperature and humidity metrics, logging CSV records to a local FileX FAT RAM Disk, and publishing JSON telemetry to an MQTT broker. | ThreadX, FileX, NetX Duo | | **`threadx_basic`** | Multi-threaded RTOS demo showcasing thread scheduling, mechanical button debouncing, message queue logging, and interrupt-driven UART ring buffers. | ThreadX | --- @@ -25,10 +26,10 @@ Use the `ACTIVE_DEMO` CMake variable to select which demo to compile: * *Note: The MPU maps `128 KB` of SRAM2 (starting at `0x20060000`) as non-cacheable/non-bufferable for Ethernet DMA descriptors and the packet pool.* * **Virtual COM Port**: USART3 (PD8/PD9) connected to ST-LINK debugger (115,200 baud, 8N1) * **User Button**: PC13 (Blue button, Active High) -* **Board LEDs**: - * `LD1` (Green) - PB0 - * `LD2` (Blue) - PB7 - * `LD3` (Red) - PB14 +* **Board LEDs (VT100 State Indicators)**: + * `LD1` (Green) - PB0: Blinks to indicate ThreadX heartbeat. + * `LD2` (Blue) - PB7: ON when Ethernet link is up and IP address is resolved. + * `LD3` (Red) - PB14: Flashes when network is disconnected or MQTT broker is unreachable. --- @@ -37,7 +38,7 @@ Use the `ACTIVE_DEMO` CMake variable to select which demo to compile: Before building, ensure you have the following cross-compilation tools installed on your system PATH: * **ARM GNU Toolchain** (`arm-none-eabi-gcc`) -* **CMake** (version 3.5 or higher) +* **CMake** (version 3.10 or higher) * **Ninja** or **Make** * **Git** (for downloading SDK dependencies) @@ -46,7 +47,7 @@ Before building, ensure you have the following cross-compilation tools installed ## Quick Start Guide ### 1. Download SDK Dependencies -Run the driver fetcher script to clone official, stock STMicroelectronics HAL drivers and CMSIS files locally: +Run the driver fetcher script to clone official, stock STMicroelectronics HAL drivers, CMSIS files, and driver configurations locally: * **On Windows (PowerShell)**: ```powershell @@ -69,7 +70,16 @@ cmake -DACTIVE_DEMO=netx_echo -B build cmake --build build ``` -#### Option B: Build `threadx_basic` +#### Option B: Build `network_station` +```bash +# Configure CMake +cmake -DACTIVE_DEMO=network_station -B build + +# Compile +cmake --build build +``` + +#### Option C: Build `threadx_basic` ```bash # Configure CMake cmake -DACTIVE_DEMO=threadx_basic -B build @@ -92,38 +102,31 @@ The raw binary files will be generated in `build/app/demos//stm32f767 --- -### 2. How to Run & Verify the `netx_echo` Demo -1. **Set Up Serial Monitor**: Open your serial terminal program (e.g., VS Code Serial Monitor, PuTTY, or Tera Term) to the virtual ST-LINK COM Port at **115,200 baud, 8N1**. -2. **Boot Unplugged**: Reset the board with the Ethernet cable disconnected. You should see the following log confirming the BSP initialization completed successfully and the network monitor is polling: - ```text - ========================================== - NetX Echo Demo Booted! - ========================================== - [HAL] Calling HAL_ETH_Init... - [HAL] HAL_ETH_Init returned status: 0 - [NetX] Initializing PHY transceiver... - [NetX] Waiting for Ethernet link (max 3s)... - [NetX] Ethernet link timeout! Cable connected? - [NetX] Packet pool created - [NetX] IP instance created - [NetX] Enabling ARP... - [NetX] Enabling TCP... - [NetX] Enabling UDP... - [NetX] Enabling ICMP... - [NetX] Creating DHCP Thread... - [NetX] tx_application_define completed - [NetX] Network Monitor Thread Started. - ``` -3. **Connect Cable**: Plug in your network Ethernet cable. The console will report the connection, initiate DHCP, and spawn the TCP Echo Server: - ```text - [NetX] Ethernet cable connected! Enabling link... - [NetX] Ethernet link is UP! Starting DHCP client... - [NetX] DHCP Success! - [NetX] IP Address : - [NetX] Subnet Mask: 255.255.255.0 - [Echo] TCP Echo Server listening on port 7 - ``` -4. **Run the Simple Echo Test**: Open a terminal on your computer and run one of the included scripts: +### 2. How to Run & Verify the `network_station` Demo +1. **Set Up Serial Monitor**: Open your serial terminal program (e.g., VS Code Serial Monitor, PuTTY, or Tera Term) to the virtual ST-LINK COM Port at **115,200 baud, 8N1** (ANSI colored logging is enabled, VT100-compatible terminal recommended). +2. **Boot Logs**: You will see colored output detailing the startup steps: + * **[HAL]** initializing the Ethernet MAC layer. + * **[NetX]** setting up the packet pool, ARP cache, and link state. + * **[Sensor Thread]** probing the I2C bus (falling back to Mock Mode if HTS221 shield is absent). + * **[Logger Thread]** formatting and mounting the 32 KB virtual RAM disk. + * **[NetX]** enabling link, running DHCP client, and printing the resolved IP address. + * **[DNS]** resolving the IP address of the public MQTT broker. + * **[MQTT]** connecting to `test.mosquitto.org:1883` and beginning periodic JSON telemetry publishes. +3. **Outage/Disconnect Verification**: + * Pull the Ethernet cable. The console immediately prints warning codes and enters reconnect state (Red LED starts flashing). + * Local writes to `sensor_log.txt` continue unaffected. + * When `network_queue` fills up, the **Evict Oldest** circular policy discards the oldest unsent reading at the front to prioritize live data upon reconnection. +4. **Subscribe to Cloud Telemetry**: + * Open the [HiveMQ WebSocket Client](http://www.hivemq.com/demos/websocket-client/). + * Connect to host `test.mosquitto.org`, port `8081` (ensure **SSL checkbox is active**). + * Subscribe to the topic: `samplex/env_station/+/telemetry`. You will see the JSON environmental records arriving in real-time. + +--- + +### 3. How to Run & Verify the `netx_echo` Demo +1. Open your serial terminal program at **115,200 baud, 8N1**. +2. Connect the Ethernet cable and boot the board. +3. Once the Blue LED (`LD2`) turns ON, run the simple client script to test the TCP echo loop: * **On Windows (PowerShell)**: ```powershell powershell -ExecutionPolicy Bypass -File "app/demos/netx_echo/test_echo_simple.ps1" @@ -139,11 +142,10 @@ The raw binary files will be generated in `build/app/demos//stm32f767 Sending: 'Hello ThreadX NetX Echo!' Received: 'Hello ThreadX NetX Echo!' ``` -5. **Test Mid-Run Hot-Unplugging**: Disconnect the Ethernet cable. You will see `[NetX] Ethernet cable disconnected! Disabling link...` on the serial console, and the interface IP resets to `0.0.0.0`. Plug the cable back in, and it will re-acquire its configuration dynamically. --- -### 3. How to Run & Verify the `threadx_basic` Demo +### 4. How to Run & Verify the `threadx_basic` Demo 1. Open your serial terminal program at **115,200 baud, 8N1**. 2. Flash the `threadx_basic` binary to the board. 3. **Verify Heartbeat**: The Green LED (`LD1`) will blink continuously at `2 Hz` (250ms ON, 250ms OFF). @@ -198,6 +200,7 @@ target_compile_definitions(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) # Link with BSP, ThreadX, and optionally NetX Duo @@ -205,6 +208,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE board_bsp threadx + # filex # Uncomment if using filesystem # netxduo # Uncomment if using network # netx_stm32_driver # Uncomment if using network stm32cubef7