From 2ee5282b8b39b59bb1630c9d6bc2de8de9032da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Sowa?= Date: Mon, 30 Oct 2023 10:55:31 +0100 Subject: [PATCH] FreeRTOS-Plus-TCP port (#239) --- .github/workflows/freertos_plus_tcp.yaml | 42 ++++ CMakeLists.txt | 7 + README.md | 21 +- examples/freertos_plus_tcp/CMakeLists.txt | 98 ++++++++ .../include/FreeRTOSConfig.h | 64 ++++++ .../include/FreeRTOSIPConfig.h | 54 +++++ examples/freertos_plus_tcp/main.c | 140 ++++++++++++ examples/freertos_plus_tcp/z_get.c | 95 ++++++++ examples/freertos_plus_tcp/z_pub.c | 106 +++++++++ examples/freertos_plus_tcp/z_pub_st.c | 74 ++++++ examples/freertos_plus_tcp/z_pull.c | 79 +++++++ examples/freertos_plus_tcp/z_put.c | 76 +++++++ examples/freertos_plus_tcp/z_queryable.c | 91 ++++++++ examples/freertos_plus_tcp/z_scout.c | 92 ++++++++ examples/freertos_plus_tcp/z_sub.c | 77 +++++++ examples/freertos_plus_tcp/z_sub_st.c | 69 ++++++ extra_script.py | 5 + include/zenoh-pico/api/types.h | 9 + include/zenoh-pico/net/session.h | 6 +- include/zenoh-pico/system/platform.h | 4 +- .../system/platform/freertos_plus_tcp.h | 61 +++++ src/api/api.c | 33 ++- src/net/session.c | 13 +- src/system/freertos_plus_tcp/network.c | 211 ++++++++++++++++++ src/system/freertos_plus_tcp/system.c | 204 +++++++++++++++++ 25 files changed, 1707 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/freertos_plus_tcp.yaml create mode 100644 examples/freertos_plus_tcp/CMakeLists.txt create mode 100644 examples/freertos_plus_tcp/include/FreeRTOSConfig.h create mode 100644 examples/freertos_plus_tcp/include/FreeRTOSIPConfig.h create mode 100644 examples/freertos_plus_tcp/main.c create mode 100644 examples/freertos_plus_tcp/z_get.c create mode 100644 examples/freertos_plus_tcp/z_pub.c create mode 100644 examples/freertos_plus_tcp/z_pub_st.c create mode 100644 examples/freertos_plus_tcp/z_pull.c create mode 100644 examples/freertos_plus_tcp/z_put.c create mode 100644 examples/freertos_plus_tcp/z_queryable.c create mode 100644 examples/freertos_plus_tcp/z_scout.c create mode 100644 examples/freertos_plus_tcp/z_sub.c create mode 100644 examples/freertos_plus_tcp/z_sub_st.c create mode 100644 include/zenoh-pico/system/platform/freertos_plus_tcp.h create mode 100644 src/system/freertos_plus_tcp/network.c create mode 100644 src/system/freertos_plus_tcp/system.c diff --git a/.github/workflows/freertos_plus_tcp.yaml b/.github/workflows/freertos_plus_tcp.yaml new file mode 100644 index 000000000..1e8ee0fe7 --- /dev/null +++ b/.github/workflows/freertos_plus_tcp.yaml @@ -0,0 +1,42 @@ +# +# Copyright (c) 2023 ZettaScale Technology +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +# which is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +# +# Contributors: +# Błażej Sowa, +# +name: freertos_plus_tcp + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +jobs: + build: + name: Build on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + steps: + - uses: actions/checkout@v2 + - uses: jwlawson/actions-setup-cmake@v1.13 + - name: Install requirements + run: | + sudo apt update + sudo apt install -y ninja-build libslirp-dev + - name: Build examples + run: | + cd examples/freertos_plus_tcp + cmake -Bbuild -G"Ninja Multi-Config" + cmake --build ./build --config Debug + cmake --build ./build --config Release diff --git a/CMakeLists.txt b/CMakeLists.txt index 81105e115..2838ec142 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ include(GNUInstallDirs) option(BUILD_SHARED_LIBS "Build shared libraries if ON, otherwise build static libraries" ON) option(ZENOH_DEBUG "Use this to set the ZENOH_DEBUG variable." 0) option(WITH_ZEPHYR "Build for Zephyr RTOS" OFF) +option(WITH_FREERTOS_PLUS_TCP "Build for FreeRTOS RTOS and FreeRTOS-Plus-TCP network stack" OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") if(CMAKE_EXPORT_COMPILE_COMMANDS) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES @@ -91,6 +92,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") elseif(CMAKE_SYSTEM_NAME MATCHES "Generic") if(WITH_ZEPHYR) add_definition(ZENOH_ZEPHYR) + elseif(WITH_FREERTOS_PLUS_TCP) + add_definition(ZENOH_FREERTOS_PLUS_TCP) endif() else() message(FATAL_ERROR "zenoh-pico is not yet available on ${CMAKE_SYSTEM_NAME} platform") @@ -104,6 +107,7 @@ message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode") message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}") message(STATUS "Zenoh Level Log: ${ZENOH_DEBUG}") message(STATUS "Build for Zephyr RTOS: ${WITH_ZEPHYR}") +message(STATUS "Build for FreeRTOS-Plus-TCP: ${WITH_FREERTOS_PLUS_TCP}") message(STATUS "Configuring for ${CMAKE_SYSTEM_NAME}") if(SKBUILD) @@ -163,6 +167,9 @@ file(GLOB_RECURSE Sources if(WITH_ZEPHYR) file (GLOB Sources_Zephyr "src/system/zephyr/*.c") list(APPEND Sources ${Sources_Zephyr}) +elseif(WITH_FREERTOS_PLUS_TCP) + file (GLOB Sources_Freertos_Plus_TCP "src/system/freertos_plus_tcp/*.c") + list(APPEND Sources ${Sources_Freertos_Plus_TCP}) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "BSD" OR POSIX_COMPATIBLE) file (GLOB Sources_Unix "src/system/unix/*.c") list(APPEND Sources ${Sources_Unix}) diff --git a/README.md b/README.md index 62992f3de..033521869 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,17 @@ It is fully compatible with its main [Rust Zenoh implementation](https://github. Currently, zenoh-pico provides support for the following (RT)OSs and protocols: -| **(RT)OS** | **Transport Layer** | **Network Layer** | **Data Link Layer** | -|:---------------:|:--------------------------------:|:-------------------:|:--------------------------------------------------:| -| **Unix** | UDP (unicast and multicast), TCP | IPv4, IPv6, 6LoWPAN | WiFi, Ethernet, Thread | -| **Windows** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet | -| **Zephyr** | UDP (unicast and multicast), TCP | IPv4, IPv6, 6LoWPAN | WiFi, Ethernet, Thread, Serial | -| **Arduino** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet, Bluetooth (Serial profile), Serial | -| **ESP-IDF** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet, Serial | -| **MbedOS** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet, Serial | -| **OpenCR** | UDP (unicast and multicast), TCP | IPv4 | WiFi | -| **Emscripten** | Websocket | IPv4, IPv6 | WiFi, Ethernet | +| **(RT)OS** | **Transport Layer** | **Network Layer** | **Data Link Layer** | +|:---------------------:|:--------------------------------:|:-------------------:|:--------------------------------------------------:| +| **Unix** | UDP (unicast and multicast), TCP | IPv4, IPv6, 6LoWPAN | WiFi, Ethernet, Thread | +| **Windows** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet | +| **Zephyr** | UDP (unicast and multicast), TCP | IPv4, IPv6, 6LoWPAN | WiFi, Ethernet, Thread, Serial | +| **Arduino** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet, Bluetooth (Serial profile), Serial | +| **ESP-IDF** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet, Serial | +| **MbedOS** | UDP (unicast and multicast), TCP | IPv4, IPv6 | WiFi, Ethernet, Serial | +| **OpenCR** | UDP (unicast and multicast), TCP | IPv4 | WiFi | +| **Emscripten** | Websocket | IPv4, IPv6 | WiFi, Ethernet | +| **FreeRTOS-Plus-TCP** | UDP (unicast), TCP | IPv4 | Ethernet | Check the website [zenoh.io](http://zenoh.io) and the [roadmap](https://github.com/eclipse-zenoh/roadmap) for more detailed information. diff --git a/examples/freertos_plus_tcp/CMakeLists.txt b/examples/freertos_plus_tcp/CMakeLists.txt new file mode 100644 index 000000000..8130e0a23 --- /dev/null +++ b/examples/freertos_plus_tcp/CMakeLists.txt @@ -0,0 +1,98 @@ +# +# Copyright (c) 2023 Fictionlab sp. z o.o. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +# which is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +# +# Contributors: +# Błażej Sowa, + +cmake_minimum_required(VERSION 3.20) +project(zenohpico_freertos_plus_tcp_examples) + +set(CMAKE_SYSTEM_NAME "Generic") +set(CMAKE_C_STANDARD 11) + +include(../../cmake/helpers.cmake) +set_default_build_type(Release) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(SLIRP REQUIRED slirp) + +add_library(slirp INTERFACE) +target_link_libraries(slirp INTERFACE ${SLIRP_LINK_LIBRARIES}) +target_include_directories(slirp INTERFACE ${SLIRP_INCLUDE_DIRS}) +target_compile_options(slirp INTERFACE -Wno-error) + +include(FetchContent) + +FetchContent_Declare(freertos_kernel + GIT_REPOSITORY "https://github.com/FreeRTOS/FreeRTOS-Kernel.git" + GIT_TAG "V10.6.1" +) + +FetchContent_Declare(freertos_plus_tcp + GIT_REPOSITORY "https://github.com/FreeRTOS/FreeRTOS-Plus-TCP.git" + GIT_TAG "34148c3" + GIT_SUBMODULES "" +) + +add_library(freertos_config INTERFACE) +target_include_directories(freertos_config SYSTEM INTERFACE include) +target_compile_options(freertos_config INTERFACE -Wno-error) + +set(FREERTOS_HEAP "3" CACHE STRING "" FORCE) +set(FREERTOS_PORT "GCC_POSIX" CACHE STRING "" FORCE) +set(FREERTOS_PLUS_TCP_NETWORK_IF "LIBSLIRP" CACHE STRING "" FORCE) +set(FREERTOS_PLUS_TCP_BUFFER_ALLOCATION "2" CACHE STRING "" FORCE) + +FetchContent_MakeAvailable(freertos_kernel freertos_plus_tcp) + +set(BUILD_SHARED_LIBS OFF) +set(WITH_FREERTOS_PLUS_TCP ON) +set(ZENOH_DEBUG 3) +configure_include_project(ZENOHPICO zenohpico zenohpico "../.." zenohpico "https://github.com/eclipse-zenoh/zenoh-pico" "") + +target_link_libraries(zenohpico + freertos_kernel + freertos_plus_tcp +) +target_compile_definitions(zenohpico + PUBLIC + Z_FEATURE_MULTI_THREAD=1 + Z_FEATURE_LINK_TCP=1 + Z_FEATURE_SCOUTING_UDP=1 + Z_FEATURE_LINK_UDP_UNICAST=1 + Z_FEATURE_LINK_UDP_MULTICAST=0 + Z_CONFIG_SOCKET_TIMEOUT=1000 +) + +add_library(main OBJECT main.c) +target_link_libraries(main + freertos_kernel + freertos_plus_tcp +) + +function(add_example name) + add_executable(${name} ${name}.c) + target_link_libraries(${name} + main + freertos_kernel + freertos_plus_tcp + zenohpico + ) +endfunction() + +add_example(z_get) +add_example(z_pub_st) +add_example(z_pub) +add_example(z_pull) +add_example(z_put) +add_example(z_queryable) +add_example(z_scout) +add_example(z_sub_st) +add_example(z_sub) diff --git a/examples/freertos_plus_tcp/include/FreeRTOSConfig.h b/examples/freertos_plus_tcp/include/FreeRTOSConfig.h new file mode 100644 index 000000000..cbd027ce3 --- /dev/null +++ b/examples/freertos_plus_tcp/include/FreeRTOSConfig.h @@ -0,0 +1,64 @@ +// +// Copyright (c) 2023 Fictionlab sp. z o.o. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// Błażej Sowa, + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "bits/pthread_stack_min.h" + +/* Core options */ +#define configUSE_PREEMPTION 1 +#define configTICK_RATE_HZ ((TickType_t)1000) +#define configMAX_PRIORITIES (56) +#define configMINIMAL_STACK_SIZE ((uint16_t) PTHREAD_STACK_MIN) +#define configMAX_TASK_NAME_LEN (16) +#define configUSE_16_BIT_TICKS 0 +#define configQUEUE_REGISTRY_SIZE 0 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configUSE_SB_COMPLETED_CALLBACK 0 + +/* Enable/Disable features */ +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_TIMERS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_QUEUE_SETS 0 +#define configUSE_NEWLIB_REENTRANT 0 + +/* Set the API functions which should be included */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 0 + +#endif /* FREERTOS_CONFIG_H */ diff --git a/examples/freertos_plus_tcp/include/FreeRTOSIPConfig.h b/examples/freertos_plus_tcp/include/FreeRTOSIPConfig.h new file mode 100644 index 000000000..2070ad000 --- /dev/null +++ b/examples/freertos_plus_tcp/include/FreeRTOSIPConfig.h @@ -0,0 +1,54 @@ +// +// Copyright (c) 2023 Fictionlab sp. z o.o. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// Błażej Sowa, + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +// Driver specific +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 +#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 0 +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 +#define ipconfigZERO_COPY_RX_DRIVER 1 +#define ipconfigZERO_COPY_TX_DRIVER 1 +#define ipconfigUSE_LINKED_RX_MESSAGES 1 +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +// Enable/Disable features +#define ipconfigUSE_IPv4 1 +#define ipconfigUSE_IPv6 1 +#define ipconfigUSE_DHCP 1 +#define ipconfigUSE_DHCPv6 0 +#define ipconfigUSE_RA 0 +#define ipconfigUSE_DNS 1 +#define ipconfigUSE_TCP 1 +#define ipconfigUSE_ARP_REMOVE_ENTRY 0 +#define ipconfigUSE_ARP_REVERSED_LOOKUP 0 +#define ipconfigSUPPORT_SELECT_FUNCTION 0 +#define ipconfigSUPPORT_OUTGOING_PINGS 0 +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 +#define ipconfigUSE_DHCP_HOOK 0 + +// DHCP +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD (pdMS_TO_TICKS(1000U)) +#define ipconfigDHCP_REGISTER_HOSTNAME 1 + +#define ipconfigIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) +#define ipconfigIP_TASK_STACK_SIZE_WORDS (configMINIMAL_STACK_SIZE * 5) + +// Set ipconfigBUFFER_PADDING on 64-bit platforms +#if INTPTR_MAX == INT64_MAX + #define ipconfigBUFFER_PADDING 14U +#endif + +#endif /* FREERTOS_IP_CONFIG_H */ \ No newline at end of file diff --git a/examples/freertos_plus_tcp/main.c b/examples/freertos_plus_tcp/main.c new file mode 100644 index 000000000..5d53e7c39 --- /dev/null +++ b/examples/freertos_plus_tcp/main.c @@ -0,0 +1,140 @@ +// +// Copyright (c) 2023 Fictionlab sp. z o.o. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// Błażej Sowa, + +#include +#include + +#include "FreeRTOS.h" +#include "FreeRTOS_IP.h" +#include "task.h" + +#define APP_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE +#define APP_TASK_PRIORITY 10 + +static const uint8_t ucIPAddress[] = {192, 168, 1, 80}; +static const uint8_t ucNetMask[] = {255, 255, 255, 0}; +static const uint8_t ucGatewayAddress[] = {192, 168, 1, 1}; +static const uint8_t ucDNSServerAddress[] = {192, 168, 1, 1}; +static const uint8_t ucMACAddress[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; + +NetworkInterface_t *pxLibslirp_FillInterfaceDescriptor(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface); + +static NetworkInterface_t xInterface; +static NetworkEndPoint_t xEndPoint; + +static TaskHandle_t xAppTaskHandle; +static StaticTask_t xAppTaskTCB; +static StackType_t uxAppTaskStack[APP_TASK_STACK_DEPTH]; + +void app_main(); + +static void vAppTask(void * /*argument*/) { + printf("Waiting for network...\n"); + + uint32_t ulNotificationValue = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5000)); + + if (ulNotificationValue == 0) { + printf("Timed out waiting for network.\n"); + } else { + printf("Starting Zenoh App...\n"); + app_main(); + } + + vTaskDelete(NULL); +} + +int main(int argc, char **argv) { + memcpy(ipLOCAL_MAC_ADDRESS, ucMACAddress, sizeof(ucMACAddress)); + + pxLibslirp_FillInterfaceDescriptor(0, &xInterface); + + FreeRTOS_FillEndPoint(&xInterface, &xEndPoint, ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, + ucMACAddress); + xEndPoint.bits.bWantDHCP = 1; + + FreeRTOS_IPInit_Multi(); + + xAppTaskHandle = + xTaskCreateStatic(vAppTask, "", APP_TASK_STACK_DEPTH, NULL, APP_TASK_PRIORITY, uxAppTaskStack, &xAppTaskTCB); + vTaskStartScheduler(); + + return 0; +} + +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize) { + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} + +BaseType_t xApplicationGetRandomNumber(uint32_t *pulNumber) { + *pulNumber = (uint32_t)rand(); + + return pdTRUE; +} + +uint32_t ulApplicationGetNextSequenceNumber(uint32_t /*ulSourceAddress*/, uint16_t /*usSourcePort*/, + uint32_t /*ulDestinationAddress*/, uint16_t /*usDestinationPort*/) { + uint32_t ulNext = 0; + xApplicationGetRandomNumber(&ulNext); + + return ulNext; +} + +const char *pcApplicationHostnameHook(void) { return "FreeRTOS-simulator"; } + +void vApplicationIPNetworkEventHook_Multi(eIPCallbackEvent_t eNetworkEvent, struct xNetworkEndPoint * /*xEndPoint*/) { + if (eNetworkEvent == eNetworkUp) { + printf("Network is up!\n"); + + uint32_t ulIPAddress = 0; + uint32_t ulNetMask = 0; + uint32_t ulGatewayAddress = 0; + uint32_t ulDNSServerAddress = 0; + char cBuf[50]; + + // The network is up and configured. Print out the configuration obtained + // from the DHCP server. + FreeRTOS_GetEndPointConfiguration(&ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, &xEndPoint); + + // Convert the IP address to a string then print it out. + FreeRTOS_inet_ntoa(ulIPAddress, cBuf); + printf("IP Address: %s\n", cBuf); + + // Convert the net mask to a string then print it out. + FreeRTOS_inet_ntoa(ulNetMask, cBuf); + printf("Subnet Mask: %s\n", cBuf); + + // Convert the IP address of the gateway to a string then print it out. + FreeRTOS_inet_ntoa(ulGatewayAddress, cBuf); + printf("Gateway IP Address: %s\n", cBuf); + + // Convert the IP address of the DNS server to a string then print it out. + FreeRTOS_inet_ntoa(ulDNSServerAddress, cBuf); + printf("DNS server IP Address: %s\n", cBuf); + + // Make sure MAC address of the gateway is known + if (xARPWaitResolution(ulGatewayAddress, pdMS_TO_TICKS(3000)) < 0) { + xTaskNotifyGive(xAppTaskHandle); + } else { + printf("Failed to obtain the MAC address of the gateway!\n"); + } + + } else if (eNetworkEvent == eNetworkDown) { + printf("IPv4 End Point is down!\n"); + } +} diff --git a/examples/freertos_plus_tcp/z_get.c b/examples/freertos_plus_tcp/z_get.c new file mode 100644 index 000000000..8a0f74b4f --- /dev/null +++ b/examples/freertos_plus_tcp/z_get.c @@ -0,0 +1,95 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#include "FreeRTOS.h" + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447#iface=en0" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/**" +#define VALUE "" + +void reply_dropper(void *ctx) { + (void)(ctx); + printf(">> Received query final notification\n"); +} + +void reply_handler(z_owned_reply_t *reply, void *ctx) { + (void)(ctx); + if (z_reply_is_ok(reply)) { + z_sample_t sample = z_reply_ok(reply); + z_owned_str_t keystr = z_keyexpr_to_string(sample.keyexpr); + printf(">> Received ('%s': '%.*s')\n", z_loan(keystr), (int)sample.payload.len, sample.payload.start); + z_drop(z_move(keystr)); + } else { + printf(">> Received an error\n"); + } +} + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan(s), NULL) < 0 || zp_start_lease_task(z_loan(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + return; + } + + z_keyexpr_t ke = z_keyexpr(KEYEXPR); + if (!z_check(ke)) { + printf("%s is not a valid key expression\n", KEYEXPR); + return; + } + + while (1) { + z_sleep_s(5); + printf("Sending Query '%s'...\n", KEYEXPR); + z_get_options_t opts = z_get_options_default(); + if (strcmp(VALUE, "") != 0) { + opts.value.payload = _z_bytes_wrap((const uint8_t *)VALUE, strlen(VALUE)); + } + z_owned_closure_reply_t callback = z_closure(reply_handler, reply_dropper); + if (z_get(z_loan(s), ke, "", z_move(callback), &opts) < 0) { + printf("Unable to send query.\n"); + return; + } + } + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan(s)); + zp_stop_lease_task(z_loan(s)); + + z_close(z_move(s)); +} \ No newline at end of file diff --git a/examples/freertos_plus_tcp/z_pub.c b/examples/freertos_plus_tcp/z_pub.c new file mode 100644 index 000000000..969202074 --- /dev/null +++ b/examples/freertos_plus_tcp/z_pub.c @@ -0,0 +1,106 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#include "FreeRTOS.h" + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/zenoh-pico-pub" +#define VALUE "[FreeRTOS-Plus-TCP] Pub from Zenoh-Pico!" + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + static StackType_t read_task_stack[1000]; + static StaticTask_t read_task_buffer; + + _z_task_attr_t read_task_attr = { + .name = "ZenohReadTask", + .priority = 10, + .stack_depth = 1000, + .static_allocation = true, + .stack_buffer = read_task_stack, + .task_buffer = &read_task_buffer, + }; + + zp_task_read_options_t read_task_opt = {.task_attributes = &read_task_attr}; + + static StackType_t lease_task_stack[1000]; + static StaticTask_t lease_task_buffer; + + _z_task_attr_t lease_task_attr = { + .name = "ZenohLeaseTask", + .priority = 10, + .stack_depth = 1000, + .static_allocation = true, + .stack_buffer = lease_task_stack, + .task_buffer = &lease_task_buffer, + }; + + zp_task_lease_options_t lease_task_opt = {.task_attributes = &lease_task_attr}; + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan(s), &read_task_opt) < 0 || zp_start_lease_task(z_loan(s), &lease_task_opt) < 0) { + printf("Unable to start read and lease tasks\n"); + return; + } + + printf("Declaring publisher for '%s'...\n", KEYEXPR); + z_owned_publisher_t pub = z_declare_publisher(z_loan(s), z_keyexpr(KEYEXPR), NULL); + if (!z_check(pub)) { + printf("Unable to declare publisher for key expression!\n"); + return; + } + + char *buf = (char *)pvPortMalloc(256); + for (int idx = 0; 1; ++idx) { + z_sleep_s(1); + snprintf(buf, 256, "[%4d] %s", idx, VALUE); + printf("Putting Data ('%s': '%s')...\n", KEYEXPR, buf); + + z_publisher_put_options_t options = z_publisher_put_options_default(); + options.encoding = z_encoding(Z_ENCODING_PREFIX_TEXT_PLAIN, NULL); + z_publisher_put(z_loan(pub), (const uint8_t *)buf, strlen(buf), &options); + } + + z_undeclare_publisher(z_move(pub)); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan(s)); + zp_stop_lease_task(z_loan(s)); + + z_close(z_move(s)); +} diff --git a/examples/freertos_plus_tcp/z_pub_st.c b/examples/freertos_plus_tcp/z_pub_st.c new file mode 100644 index 000000000..f31516b72 --- /dev/null +++ b/examples/freertos_plus_tcp/z_pub_st.c @@ -0,0 +1,74 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#include "FreeRTOS.h" + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/zenoh-pico-pub" +#define VALUE "[FreeRTOS-Plus-TCP] Pub from Zenoh-Pico!" + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + printf("Declaring publisher for '%s'...\n", KEYEXPR); + z_owned_publisher_t pub = z_declare_publisher(z_loan(s), z_keyexpr(KEYEXPR), NULL); + if (!z_check(pub)) { + printf("Unable to declare publisher for key expression!\n"); + return; + } + + char *buf = (char *)pvPortMalloc(256); + z_clock_t now = z_clock_now(); + for (int idx = 0; 1;) { + if (z_clock_elapsed_ms(&now) > 1000) { + snprintf(buf, 256, "[%4d] %s", idx, VALUE); + printf("Putting Data ('%s': '%s')...\n", KEYEXPR, buf); + z_publisher_put(z_loan(pub), (const uint8_t *)buf, strlen(buf), NULL); + ++idx; + + now = z_clock_now(); + } + + zp_read(z_loan(s), NULL); + zp_send_keep_alive(z_loan(s), NULL); + zp_send_join(z_loan(s), NULL); + } + + z_undeclare_publisher(z_move(pub)); + + z_close(z_move(s)); +} diff --git a/examples/freertos_plus_tcp/z_pull.c b/examples/freertos_plus_tcp/z_pull.c new file mode 100644 index 000000000..b6d5d84f8 --- /dev/null +++ b/examples/freertos_plus_tcp/z_pull.c @@ -0,0 +1,79 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447#iface=en0" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/**" + +void data_handler(const z_sample_t *sample, void *ctx) { + (void)(ctx); + z_owned_str_t keystr = z_keyexpr_to_string(sample->keyexpr); + printf(">> [Subscriber] Received ('%s': '%.*s')\n", z_loan(keystr), (int)sample->payload.len, + sample->payload.start); + z_drop(z_move(keystr)); +} + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_config_loan(&config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan(s), NULL) < 0 || zp_start_lease_task(z_loan(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + return; + } + + z_owned_closure_sample_t callback = z_closure(data_handler); + printf("Declaring Subscriber on '%s'...\n", KEYEXPR); + z_owned_pull_subscriber_t sub = z_declare_pull_subscriber(z_loan(s), z_keyexpr(KEYEXPR), z_move(callback), NULL); + if (!z_check(sub)) { + printf("Unable to declare subscriber.\n"); + return; + } + + while (1) { + z_sleep_s(5); + printf("Pulling data from '%s'...\n", KEYEXPR); + z_subscriber_pull(z_loan(sub)); + } + + z_undeclare_pull_subscriber(z_move(sub)); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan(s)); + zp_stop_lease_task(z_loan(s)); + + z_close(z_move(s)); +} diff --git a/examples/freertos_plus_tcp/z_put.c b/examples/freertos_plus_tcp/z_put.c new file mode 100644 index 000000000..f8913146d --- /dev/null +++ b/examples/freertos_plus_tcp/z_put.c @@ -0,0 +1,76 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/zenoh-pico-put" +#define VALUE "[FreeRTOS-Plus-TCP] Pub from Zenoh-Pico!" + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan(s), NULL) < 0 || zp_start_lease_task(z_loan(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + return; + } + + printf("Declaring key expression '%s'...\n", KEYEXPR); + z_owned_keyexpr_t ke = z_declare_keyexpr(z_loan(s), z_keyexpr(KEYEXPR)); + if (!z_check(ke)) { + printf("Unable to declare key expression!\n"); + return; + } + + printf("Putting Data ('%s': '%s')...\n", KEYEXPR, VALUE); + z_put_options_t options = z_put_options_default(); + options.encoding = z_encoding(Z_ENCODING_PREFIX_TEXT_PLAIN, NULL); + if (z_put(z_loan(s), z_loan(ke), (const uint8_t *)VALUE, strlen(VALUE), &options) < 0) { + printf("Oh no! Put has failed...\n"); + } + + while (1) { + z_sleep_s(1); + } + + z_undeclare_keyexpr(z_loan(s), z_move(ke)); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan(s)); + zp_stop_lease_task(z_loan(s)); + + z_close(z_move(s)); +} diff --git a/examples/freertos_plus_tcp/z_queryable.c b/examples/freertos_plus_tcp/z_queryable.c new file mode 100644 index 000000000..1a9f19514 --- /dev/null +++ b/examples/freertos_plus_tcp/z_queryable.c @@ -0,0 +1,91 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/zenoh-pico-queryable" +#define VALUE "[FreeRTOS-Plus-TCP] Queryable from Zenoh-Pico!" + +void query_handler(const z_query_t *query, void *ctx) { + (void)(ctx); + z_owned_str_t keystr = z_keyexpr_to_string(z_query_keyexpr(query)); + z_bytes_t pred = z_query_parameters(query); + z_value_t payload_value = z_query_value(query); + printf(" >> [Queryable handler] Received Query '%s?%.*s'\n", z_loan(keystr), (int)pred.len, pred.start); + if (payload_value.payload.len > 0) { + printf(" with value '%.*s'\n", (int)payload_value.payload.len, payload_value.payload.start); + } + z_query_reply_options_t options = z_query_reply_options_default(); + options.encoding = z_encoding(Z_ENCODING_PREFIX_TEXT_PLAIN, NULL); + z_query_reply(query, z_keyexpr(KEYEXPR), (const unsigned char *)VALUE, strlen(VALUE), &options); + z_drop(z_move(keystr)); +} + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan(s), NULL) < 0 || zp_start_lease_task(z_loan(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + return; + } + + z_keyexpr_t ke = z_keyexpr(KEYEXPR); + if (!z_check(ke)) { + printf("%s is not a valid key expression\n", KEYEXPR); + return; + } + + printf("Creating Queryable on '%s'...\n", KEYEXPR); + z_owned_closure_query_t callback = z_closure(query_handler); + z_owned_queryable_t qable = z_declare_queryable(z_loan(s), ke, z_move(callback), NULL); + if (!z_check(qable)) { + printf("Unable to create queryable.\n"); + return; + } + + while (1) { + z_sleep_s(5); + } + + z_undeclare_queryable(z_move(qable)); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan(s)); + zp_stop_lease_task(z_loan(s)); + + z_close(z_move(s)); +} diff --git a/examples/freertos_plus_tcp/z_scout.c b/examples/freertos_plus_tcp/z_scout.c new file mode 100644 index 000000000..c73785779 --- /dev/null +++ b/examples/freertos_plus_tcp/z_scout.c @@ -0,0 +1,92 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include +#include +#include +#include +#include + +#include "FreeRTOS.h" + +void fprintzid(FILE *stream, z_id_t zid) { + unsigned int zidlen = _z_id_len(zid); + if (zidlen == 0) { + fprintf(stream, "None"); + } else { + fprintf(stream, "Some("); + for (unsigned int i = 0; i < zidlen; i++) { + fprintf(stream, "%02X", (int)zid.id[i]); + } + fprintf(stream, ")"); + } +} + +void fprintwhatami(FILE *stream, unsigned int whatami) { + if (whatami == Z_WHATAMI_ROUTER) { + fprintf(stream, "\"Router\""); + } else if (whatami == Z_WHATAMI_PEER) { + fprintf(stream, "\"Peer\""); + } else { + fprintf(stream, "\"Other\""); + } +} + +void fprintlocators(FILE *stream, const z_str_array_t *locs) { + fprintf(stream, "["); + for (unsigned int i = 0; i < z_str_array_len(locs); i++) { + fprintf(stream, "\""); + fprintf(stream, "%s", *z_str_array_get(locs, i)); + fprintf(stream, "\""); + if (i < z_str_array_len(locs) - 1) { + fprintf(stream, ", "); + } + } + fprintf(stream, "]"); +} + +void fprinthello(FILE *stream, const z_hello_t hello) { + fprintf(stream, "Hello { zid: "); + fprintzid(stream, hello.zid); + fprintf(stream, ", whatami: "); + fprintwhatami(stream, hello.whatami); + fprintf(stream, ", locators: "); + fprintlocators(stream, &hello.locators); + fprintf(stream, " }"); +} + +void callback(z_owned_hello_t *hello, void *context) { + fprinthello(stdout, z_loan(*hello)); + fprintf(stdout, "\n"); + (*(int *)context)++; +} + +void drop(void *context) { + int count = *(int *)context; + free(context); + if (!count) { + printf("Did not find any zenoh process.\n"); + } else { + printf("Dropping scout results.\n"); + } +} + +void app_main() { + int *context = (int *)pvPortMalloc(sizeof(int)); + *context = 0; + z_owned_scouting_config_t config = z_scouting_config_default(); + z_owned_closure_hello_t closure = z_closure(callback, drop, context); + printf("Scouting...\n"); + z_scout(z_move(config), z_move(closure)); +} diff --git a/examples/freertos_plus_tcp/z_sub.c b/examples/freertos_plus_tcp/z_sub.c new file mode 100644 index 000000000..62e39ba59 --- /dev/null +++ b/examples/freertos_plus_tcp/z_sub.c @@ -0,0 +1,77 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447#iface=en0" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/**" + +void data_handler(const z_sample_t *sample, void *ctx) { + (void)(ctx); + z_owned_str_t keystr = z_keyexpr_to_string(sample->keyexpr); + printf(">> [Subscriber] Received ('%s': '%.*s')\n", z_loan(keystr), (int)sample->payload.len, + sample->payload.start); + z_drop(z_move(keystr)); +} + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan(s), NULL) < 0 || zp_start_lease_task(z_loan(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + return; + } + + z_owned_closure_sample_t callback = z_closure(data_handler); + printf("Declaring Subscriber on '%s'...\n", KEYEXPR); + z_owned_subscriber_t sub = z_declare_subscriber(z_loan(s), z_keyexpr(KEYEXPR), z_move(callback), NULL); + if (!z_check(sub)) { + printf("Unable to declare subscriber.\n"); + return; + } + + while (1) { + z_sleep_s(5); + } + + z_undeclare_subscriber(z_move(sub)); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan(s)); + zp_stop_lease_task(z_loan(s)); + + z_close(z_move(s)); +} diff --git a/examples/freertos_plus_tcp/z_sub_st.c b/examples/freertos_plus_tcp/z_sub_st.c new file mode 100644 index 000000000..b051ed467 --- /dev/null +++ b/examples/freertos_plus_tcp/z_sub_st.c @@ -0,0 +1,69 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#define CLIENT_OR_PEER 0 // 0: Client mode; 1: Peer mode +#if CLIENT_OR_PEER == 0 +#define MODE "client" +#define CONNECT "" // If empty, it will scout +#elif CLIENT_OR_PEER == 1 +#define MODE "peer" +#define CONNECT "udp/224.0.0.225:7447#iface=en0" +#else +#error "Unknown Zenoh operation mode. Check CLIENT_OR_PEER value." +#endif + +#define KEYEXPR "demo/example/**" + +void data_handler(const z_sample_t *sample, void *ctx) { + (void)(ctx); + z_owned_str_t keystr = z_keyexpr_to_string(sample->keyexpr); + printf(">> [Subscriber] Received ('%s': '%.*s')\n", z_loan(keystr), (int)sample->payload.len, + sample->payload.start); + z_drop(z_move(keystr)); +} + +void app_main() { + z_owned_config_t config = z_config_default(); + zp_config_insert(z_loan(config), Z_CONFIG_MODE_KEY, z_string_make(MODE)); + if (strcmp(CONNECT, "") != 0) { + zp_config_insert(z_loan(config), Z_CONFIG_CONNECT_KEY, z_string_make(CONNECT)); + } + + printf("Opening session...\n"); + z_owned_session_t s = z_open(z_move(config)); + if (!z_check(s)) { + printf("Unable to open session!\n"); + return; + } + + z_owned_closure_sample_t callback = z_closure(data_handler); + printf("Declaring Subscriber on '%s'...\n", KEYEXPR); + z_owned_subscriber_t sub = z_declare_subscriber(z_loan(s), z_keyexpr(KEYEXPR), z_move(callback), NULL); + if (!z_check(sub)) { + printf("Unable to declare subscriber.\n"); + return; + } + + while (1) { + zp_read(z_loan(s), NULL); + zp_send_keep_alive(z_loan(s), NULL); + zp_send_join(z_loan(s), NULL); + } + + z_undeclare_subscriber(z_move(sub)); + + z_close(z_move(s)); +} diff --git a/extra_script.py b/extra_script.py index 3d4780ca8..c80f143c2 100644 --- a/extra_script.py +++ b/extra_script.py @@ -25,6 +25,7 @@ "-", "-", "-", + "-", "-", "-", "-"] @@ -39,6 +40,7 @@ "-", "-", "-", + "-", "-", "-", "-", @@ -53,6 +55,7 @@ "-", "-", "-", + "-", "-", "-", "-", @@ -65,6 +68,7 @@ "-", "-", "-", + "-", "-", "-", "-", @@ -78,6 +82,7 @@ "-", "-", "-", + "-", "-", "-", "-"] diff --git a/include/zenoh-pico/api/types.h b/include/zenoh-pico/api/types.h index 4e8c48f13..96bd2158d 100644 --- a/include/zenoh-pico/api/types.h +++ b/include/zenoh-pico/api/types.h @@ -10,6 +10,7 @@ // // Contributors: // ZettaScale Zenoh Team, +// Błażej Sowa, #ifndef INCLUDE_ZENOH_PICO_API_TYPES_H #define INCLUDE_ZENOH_PICO_API_TYPES_H @@ -342,7 +343,11 @@ typedef struct { * whenever issued via :c:func:`zp_start_read_task`. */ typedef struct { +#if Z_FEATURE_MULTI_THREAD == 1 + _z_task_attr_t *task_attributes; +#else uint8_t __dummy; // Just to avoid empty structures that might cause undefined behavior +#endif } zp_task_read_options_t; /** @@ -350,7 +355,11 @@ typedef struct { * whenever issued via :c:func:`zp_start_lease_task`. */ typedef struct { +#if Z_FEATURE_MULTI_THREAD == 1 + _z_task_attr_t *task_attributes; +#else uint8_t __dummy; // Just to avoid empty structures that might cause undefined behavior +#endif } zp_task_lease_options_t; /** diff --git a/include/zenoh-pico/net/session.h b/include/zenoh-pico/net/session.h index a93e387ce..aa6e14f06 100644 --- a/include/zenoh-pico/net/session.h +++ b/include/zenoh-pico/net/session.h @@ -10,7 +10,7 @@ // // Contributors: // ZettaScale Zenoh Team, -// +// Błażej Sowa, #ifndef INCLUDE_ZENOH_PICO_NET_SESSION_H #define INCLUDE_ZENOH_PICO_NET_SESSION_H @@ -139,7 +139,7 @@ int8_t _zp_send_join(_z_session_t *z); * Returns: * ``0`` in case of success, ``-1`` in case of failure. */ -int8_t _zp_start_read_task(_z_session_t *z); +int8_t _zp_start_read_task(_z_session_t *z, _z_task_attr_t *attr); /** * Stop the read task. This may result in stopping a thread or a process depending @@ -166,7 +166,7 @@ int8_t _zp_stop_read_task(_z_session_t *z); * Returns: * ``0`` in case of success, ``-1`` in case of failure. */ -int8_t _zp_start_lease_task(_z_session_t *z); +int8_t _zp_start_lease_task(_z_session_t *z, _z_task_attr_t *attr); /** * Stop the lease task. This may result in stopping a thread or a process depending diff --git a/include/zenoh-pico/system/platform.h b/include/zenoh-pico/system/platform.h index 4a8697800..858e63ae9 100644 --- a/include/zenoh-pico/system/platform.h +++ b/include/zenoh-pico/system/platform.h @@ -10,7 +10,7 @@ // // Contributors: // ZettaScale Zenoh Team, -// +// Błażej Sowa, #ifndef ZENOH_PICO_SYSTEM_COMMON_H #define ZENOH_PICO_SYSTEM_COMMON_H @@ -35,6 +35,8 @@ #include "zenoh-pico/system/platform/arduino/opencr.h" #elif defined(ZENOH_EMSCRIPTEN) #include "zenoh-pico/system/platform/emscripten.h" +#elif defined(ZENOH_FREERTOS_PLUS_TCP) +#include "zenoh-pico/system/platform/freertos_plus_tcp.h" #else #include "zenoh-pico/system/platform/void.h" #error "Unknown platform" diff --git a/include/zenoh-pico/system/platform/freertos_plus_tcp.h b/include/zenoh-pico/system/platform/freertos_plus_tcp.h new file mode 100644 index 000000000..17a7616a9 --- /dev/null +++ b/include/zenoh-pico/system/platform/freertos_plus_tcp.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2023 Fictionlab sp. z o.o. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// Błażej Sowa, + +#ifndef ZENOH_PICO_SYSTEM_FREERTOS_PLUS_TCP_TYPES_H +#define ZENOH_PICO_SYSTEM_FREERTOS_PLUS_TCP_TYPES_H + +#include "FreeRTOS.h" +#include "FreeRTOS_IP.h" +#include "semphr.h" + +#if Z_FEATURE_MULTI_THREAD == 1 +typedef struct { + const char *name; + UBaseType_t priority; + size_t stack_depth; +#if (configSUPPORT_STATIC_ALLOCATION == 1) + _Bool static_allocation; + StackType_t *stack_buffer; + StaticTask_t *task_buffer; +#endif /* SUPPORT_STATIC_ALLOCATION */ +} _z_task_attr_t; + +typedef struct { + TaskHandle_t handle; + EventGroupHandle_t join_event; +} _z_task_t; + +typedef SemaphoreHandle_t _z_mutex_t; +typedef void *_z_condvar_t; +#endif // Z_MULTI_THREAD == 1 + +typedef TickType_t z_clock_t; +typedef TickType_t z_time_t; + +typedef struct { + union { +#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1 + Socket_t _socket; +#endif + }; +} _z_sys_net_socket_t; + +typedef struct { + union { +#if Z_FEATURE_LINK_TCP == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 || Z_FEATURE_LINK_UDP_UNICAST == 1 + struct freertos_addrinfo *_iptcp; +#endif + }; +} _z_sys_net_endpoint_t; + +#endif \ No newline at end of file diff --git a/src/api/api.c b/src/api/api.c index 288465a70..0e2e59749 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -10,6 +10,7 @@ // // Contributors: // ZettaScale Zenoh Team, +// Błażej Sowa, #include #include @@ -1016,12 +1017,24 @@ z_owned_keyexpr_t z_subscriber_keyexpr(z_subscriber_t sub) { #endif /**************** Tasks ****************/ -zp_task_read_options_t zp_task_read_options_default(void) { return (zp_task_read_options_t){.__dummy = 0}; } +zp_task_read_options_t zp_task_read_options_default(void) { + return (zp_task_read_options_t) { +#if Z_FEATURE_MULTI_THREAD == 1 + .task_attributes = NULL +#else + .__dummy = 0 +#endif + }; +} int8_t zp_start_read_task(z_session_t zs, const zp_task_read_options_t *options) { (void)(options); #if Z_FEATURE_MULTI_THREAD == 1 - return _zp_start_read_task(zs._val); + zp_task_read_options_t opt = zp_task_read_options_default(); + if (options != NULL) { + opt.task_attributes = options->task_attributes; + } + return _zp_start_read_task(zs._val, opt.task_attributes); #else (void)(zs); return -1; @@ -1037,12 +1050,24 @@ int8_t zp_stop_read_task(z_session_t zs) { #endif } -zp_task_lease_options_t zp_task_lease_options_default(void) { return (zp_task_lease_options_t){.__dummy = 0}; } +zp_task_lease_options_t zp_task_lease_options_default(void) { + return (zp_task_lease_options_t) { +#if Z_FEATURE_MULTI_THREAD == 1 + .task_attributes = NULL +#else + .__dummy = 0 +#endif + }; +} int8_t zp_start_lease_task(z_session_t zs, const zp_task_lease_options_t *options) { (void)(options); #if Z_FEATURE_MULTI_THREAD == 1 - return _zp_start_lease_task(zs._val); + zp_task_lease_options_t opt = zp_task_lease_options_default(); + if (options != NULL) { + opt.task_attributes = options->task_attributes; + } + return _zp_start_lease_task(zs._val, opt.task_attributes); #else (void)(zs); return -1; diff --git a/src/net/session.c b/src/net/session.c index 24d66dea6..c89f83f35 100644 --- a/src/net/session.c +++ b/src/net/session.c @@ -10,6 +10,7 @@ // // Contributors: // ZettaScale Zenoh Team, +// Błażej Sowa, #include "zenoh-pico/net/session.h" @@ -188,7 +189,7 @@ int8_t _zp_send_keep_alive(_z_session_t *zn) { return _z_send_keep_alive(&zn->_t int8_t _zp_send_join(_z_session_t *zn) { return _z_send_join(&zn->_tp); } #if Z_FEATURE_MULTI_THREAD == 1 -int8_t _zp_start_read_task(_z_session_t *zn) { +int8_t _zp_start_read_task(_z_session_t *zn, _z_task_attr_t *attr) { int8_t ret = _Z_RES_OK; _z_task_t *task = (_z_task_t *)z_malloc(sizeof(_z_task_t)); @@ -199,7 +200,7 @@ int8_t _zp_start_read_task(_z_session_t *zn) { if (zn->_tp._type == _Z_TRANSPORT_UNICAST_TYPE) { zn->_tp._transport._unicast._read_task = task; zn->_tp._transport._unicast._read_task_running = true; - if (_z_task_init(task, NULL, _zp_unicast_read_task, &zn->_tp._transport._unicast) != _Z_RES_OK) { + if (_z_task_init(task, attr, _zp_unicast_read_task, &zn->_tp._transport._unicast) != _Z_RES_OK) { zn->_tp._transport._unicast._read_task_running = false; ret = _Z_ERR_SYSTEM_TASK_FAILED; z_free(task); @@ -210,7 +211,7 @@ int8_t _zp_start_read_task(_z_session_t *zn) { if (zn->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE) { zn->_tp._transport._multicast._read_task = task; zn->_tp._transport._multicast._read_task_running = true; - if (_z_task_init(task, NULL, _zp_multicast_read_task, &zn->_tp._transport._multicast) != _Z_RES_OK) { + if (_z_task_init(task, attr, _zp_multicast_read_task, &zn->_tp._transport._multicast) != _Z_RES_OK) { zn->_tp._transport._multicast._read_task_running = false; ret = _Z_ERR_SYSTEM_TASK_FAILED; z_free(task); @@ -246,7 +247,7 @@ int8_t _zp_stop_read_task(_z_session_t *zn) { return ret; } -int8_t _zp_start_lease_task(_z_session_t *zn) { +int8_t _zp_start_lease_task(_z_session_t *zn, _z_task_attr_t *attr) { int8_t ret = _Z_RES_OK; _z_task_t *task = (_z_task_t *)z_malloc(sizeof(_z_task_t)); @@ -257,7 +258,7 @@ int8_t _zp_start_lease_task(_z_session_t *zn) { if (zn->_tp._type == _Z_TRANSPORT_UNICAST_TYPE) { zn->_tp._transport._unicast._lease_task = task; zn->_tp._transport._unicast._lease_task_running = true; - if (_z_task_init(task, NULL, _zp_unicast_lease_task, &zn->_tp._transport._unicast) != _Z_RES_OK) { + if (_z_task_init(task, attr, _zp_unicast_lease_task, &zn->_tp._transport._unicast) != _Z_RES_OK) { zn->_tp._transport._unicast._lease_task_running = false; ret = _Z_ERR_SYSTEM_TASK_FAILED; z_free(task); @@ -268,7 +269,7 @@ int8_t _zp_start_lease_task(_z_session_t *zn) { if (zn->_tp._type == _Z_TRANSPORT_MULTICAST_TYPE) { zn->_tp._transport._multicast._lease_task = task; zn->_tp._transport._multicast._lease_task_running = true; - if (_z_task_init(task, NULL, _zp_multicast_lease_task, &zn->_tp._transport._multicast) != _Z_RES_OK) { + if (_z_task_init(task, attr, _zp_multicast_lease_task, &zn->_tp._transport._multicast) != _Z_RES_OK) { zn->_tp._transport._multicast._lease_task_running = false; ret = _Z_ERR_SYSTEM_TASK_FAILED; z_free(task); diff --git a/src/system/freertos_plus_tcp/network.c b/src/system/freertos_plus_tcp/network.c new file mode 100644 index 000000000..60d717ddd --- /dev/null +++ b/src/system/freertos_plus_tcp/network.c @@ -0,0 +1,211 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// Copyright (c) 2023 Fictionlab sp. z o.o. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include + +#include "zenoh-pico/system/platform.h" +#include "zenoh-pico/utils/pointers.h" +#include "zenoh-pico/utils/result.h" + +// FreeRTOS includes +#include "FreeRTOS.h" +#include "FreeRTOS_IP.h" + +#if Z_FEATURE_LINK_TCP == 1 +/*------------------ TCP sockets ------------------*/ +int8_t _z_create_endpoint_tcp(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) { + int8_t ret = _Z_RES_OK; + + if (FreeRTOS_getaddrinfo(s_address, NULL, NULL, &ep->_iptcp) < 0) { + ret = _Z_ERR_GENERIC; + return ret; + } + + ep->_iptcp->ai_addr->sin_family = ep->_iptcp->ai_family; + + // Parse and check the validity of the port + uint32_t port = strtoul(s_port, NULL, 10); + if ((port > (uint32_t)0) && (port <= (uint32_t)65355)) { // Port numbers should range from 1 to 65355 + ep->_iptcp->ai_addr->sin_port = FreeRTOS_htons((uint16_t)port); + } else { + ret = _Z_ERR_GENERIC; + } + + return ret; +} + +void _z_free_endpoint_tcp(_z_sys_net_endpoint_t *ep) { FreeRTOS_freeaddrinfo(ep->_iptcp); } + +int8_t _z_open_tcp(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout) { + int8_t ret = _Z_RES_OK; + + sock->_socket = FreeRTOS_socket(rep._iptcp->ai_family, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP); + if (sock->_socket != FREERTOS_INVALID_SOCKET) { + TickType_t receive_timeout = pdMS_TO_TICKS(tout); + + if (FreeRTOS_setsockopt(sock->_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, 0) != 0) { + ret = _Z_ERR_GENERIC; + } else if (FreeRTOS_connect(sock->_socket, rep._iptcp->ai_addr, rep._iptcp->ai_addrlen) < 0) { + ret = _Z_ERR_GENERIC; + } + } else { + ret = _Z_ERR_GENERIC; + } + + return ret; +} + +int8_t _z_listen_tcp(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t lep) { + int8_t ret = _Z_RES_OK; + (void)sock; + (void)lep; + + // @TODO: To be implemented + ret = _Z_ERR_GENERIC; + + return ret; +} + +void _z_close_tcp(_z_sys_net_socket_t *sock) { FreeRTOS_closesocket(sock->_socket); } + +size_t _z_read_tcp(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { + BaseType_t rb = FreeRTOS_recv(sock._socket, ptr, len, 0); + if (rb < 0) { + return SIZE_MAX; + } + + return rb; +} + +size_t _z_read_exact_tcp(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { + size_t n = 0; + uint8_t *pos = &ptr[0]; + + do { + size_t rb = _z_read_tcp(sock, pos, len - n); + if (rb == SIZE_MAX) { + n = rb; + break; + } + + n = n + rb; + pos = _z_ptr_u8_offset(pos, n); + } while (n != len); + + return n; +} + +size_t _z_send_tcp(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len) { + return FreeRTOS_send(sock._socket, ptr, len, 0); +} +#endif + +#if Z_FEATURE_LINK_UDP_UNICAST == 1 || Z_FEATURE_LINK_UDP_MULTICAST == 1 +/*------------------ UDP sockets ------------------*/ +int8_t _z_create_endpoint_udp(_z_sys_net_endpoint_t *ep, const char *s_address, const char *s_port) { + int8_t ret = _Z_RES_OK; + + if (FreeRTOS_getaddrinfo(s_address, NULL, NULL, &ep->_iptcp) < 0) { + ret = _Z_ERR_GENERIC; + return ret; + } + + ep->_iptcp->ai_addr->sin_family = ep->_iptcp->ai_family; + + // Parse and check the validity of the port + uint32_t port = strtoul(s_port, NULL, 10); + if ((port > (uint32_t)0) && (port <= (uint32_t)65355)) { // Port numbers should range from 1 to 65355 + ep->_iptcp->ai_addr->sin_port = FreeRTOS_htons((uint16_t)port); + } else { + ret = _Z_ERR_GENERIC; + } + + return ret; +} + +void _z_free_endpoint_udp(_z_sys_net_endpoint_t *ep) { FreeRTOS_freeaddrinfo(ep->_iptcp); } +#endif + +#if Z_FEATURE_LINK_UDP_UNICAST == 1 +int8_t _z_open_udp_unicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout) { + int8_t ret = _Z_RES_OK; + + sock->_socket = FreeRTOS_socket(rep._iptcp->ai_family, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP); + if (sock->_socket != FREERTOS_INVALID_SOCKET) { + TickType_t receive_timeout = pdMS_TO_TICKS(tout); + + if (FreeRTOS_setsockopt(sock->_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, 0) != 0) { + ret = _Z_ERR_GENERIC; + } + } else { + ret = _Z_ERR_GENERIC; + } + + return ret; +} + +int8_t _z_listen_udp_unicast(_z_sys_net_socket_t *sock, const _z_sys_net_endpoint_t rep, uint32_t tout) { + int8_t ret = _Z_RES_OK; + (void)sock; + (void)rep; + (void)tout; + + // @TODO: To be implemented + ret = _Z_ERR_GENERIC; + + return ret; +} + +void _z_close_udp_unicast(_z_sys_net_socket_t *sock) { FreeRTOS_closesocket(sock->_socket); } + +size_t _z_read_udp_unicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { + struct freertos_sockaddr raddr; + uint32_t addrlen = sizeof(struct freertos_sockaddr); + + int32_t rb = FreeRTOS_recvfrom(sock._socket, ptr, len, 0, &raddr, &addrlen); + if (rb < 0) { + return SIZE_MAX; + } + + return rb; +} + +size_t _z_read_exact_udp_unicast(const _z_sys_net_socket_t sock, uint8_t *ptr, size_t len) { + size_t n = 0; + uint8_t *pos = &ptr[0]; + + do { + size_t rb = _z_read_udp_unicast(sock, pos, len - n); + if (rb == SIZE_MAX) { + n = rb; + break; + } + + n = n + rb; + pos = _z_ptr_u8_offset(pos, n); + } while (n != len); + + return n; +} + +size_t _z_send_udp_unicast(const _z_sys_net_socket_t sock, const uint8_t *ptr, size_t len, + const _z_sys_net_endpoint_t rep) { + return FreeRTOS_sendto(sock._socket, ptr, len, 0, rep._iptcp->ai_addr, sizeof(struct freertos_sockaddr)); +} +#endif + +#if Z_FEATURE_LINK_UDP_MULTICAST == 1 +#error "UDP Multicast not supported yet on FreeRTOS-Plus-TCP port of Zenoh-Pico" +#endif diff --git a/src/system/freertos_plus_tcp/system.c b/src/system/freertos_plus_tcp/system.c new file mode 100644 index 000000000..7df351c41 --- /dev/null +++ b/src/system/freertos_plus_tcp/system.c @@ -0,0 +1,204 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// Copyright (c) 2023 Fictionlab sp. z o.o. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// Błażej Sowa, + +#include +#include +#include +#include + +#include "FreeRTOS_IP.h" +#include "zenoh-pico/config.h" +#include "zenoh-pico/system/platform.h" + +/*------------------ Random ------------------*/ +uint8_t z_random_u8(void) { return z_random_u32(); } + +uint16_t z_random_u16(void) { return z_random_u32(); } + +uint32_t z_random_u32(void) { + uint32_t ret = 0; + xApplicationGetRandomNumber(&ret); + return ret; +} + +uint64_t z_random_u64(void) { + uint64_t ret = 0; + ret |= z_random_u32(); + ret = ret << 32; + ret |= z_random_u32(); + return ret; +} + +void z_random_fill(void *buf, size_t len) { + for (size_t i = 0; i < len; i++) { + *((uint8_t *)buf) = z_random_u8(); + } +} + +/*------------------ Memory ------------------*/ +void *z_malloc(size_t size) { return pvPortMalloc(size); } + +void *z_realloc(void *ptr, size_t size) { + // realloc not implemented in FreeRTOS + return NULL; +} + +void z_free(void *ptr) { vPortFree(ptr); } + +#if Z_FEATURE_MULTI_THREAD == 1 +// In FreeRTOS, tasks created using xTaskCreate must end with vTaskDelete. +// A task function should __not__ simply return. +typedef struct { + void *(*fun)(void *); + void *arg; + EventGroupHandle_t join_event; +} __z_task_arg; + +static void z_task_wrapper(void *arg) { + __z_task_arg *targ = (__z_task_arg *)arg; + targ->fun(targ->arg); + xEventGroupSetBits(targ->join_event, 1); + vTaskDelete(NULL); +} + +static _z_task_attr_t z_default_task_attr = { + .name = "", + .priority = configMAX_PRIORITIES / 2, + .stack_depth = 5120, +#if (configSUPPORT_STATIC_ALLOCATION == 1) + .static_allocation = false, + .stack_buffer = NULL, + .task_buffer = NULL, +#endif /* SUPPORT_STATIC_ALLOCATION */ +}; + +/*------------------ Thread ------------------*/ +int8_t _z_task_init(_z_task_t *task, _z_task_attr_t *attr, void *(*fun)(void *), void *arg) { + __z_task_arg *z_arg = (__z_task_arg *)z_malloc(sizeof(__z_task_arg)); + if (z_arg == NULL) { + return -1; + } + + z_arg->fun = fun; + z_arg->arg = arg; + z_arg->join_event = task->join_event = xEventGroupCreate(); + + if (attr == NULL) { + attr = &z_default_task_attr; + } + +#if (configSUPPORT_STATIC_ALLOCATION == 1) + if (attr->static_allocation) { + task->handle = xTaskCreateStatic(z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority, + attr->stack_buffer, attr->task_buffer); + if (task->handle == NULL) { + return -1; + } + } else { +#endif /* SUPPORT_STATIC_ALLOCATION */ + if (xTaskCreate(z_task_wrapper, attr->name, attr->stack_depth, z_arg, attr->priority, &task->handle) != + pdPASS) { + return -1; + } +#if (configSUPPORT_STATIC_ALLOCATION == 1) + } +#endif /* SUPPORT_STATIC_ALLOCATION */ + + return 0; +} + +int8_t _z_task_join(_z_task_t *task) { + xEventGroupWaitBits(task->join_event, 1, pdFALSE, pdFALSE, portMAX_DELAY); + return 0; +} + +int8_t _z_task_cancel(_z_task_t *task) { + vTaskDelete(task->handle); + return 0; +} + +void _z_task_free(_z_task_t **task) { + z_free((*task)->join_event); + z_free(*task); +} + +/*------------------ Mutex ------------------*/ +int8_t _z_mutex_init(_z_mutex_t *m) { + *m = xSemaphoreCreateRecursiveMutex(); + return *m == NULL ? -1 : 0; +} + +int8_t _z_mutex_free(_z_mutex_t *m) { + z_free(*m); + return 0; +} + +int8_t _z_mutex_lock(_z_mutex_t *m) { return xSemaphoreTakeRecursive(*m, portMAX_DELAY) == pdTRUE ? 0 : -1; } + +int8_t _z_mutex_trylock(_z_mutex_t *m) { return xSemaphoreTakeRecursive(*m, 0) == pdTRUE ? 0 : -1; } + +int8_t _z_mutex_unlock(_z_mutex_t *m) { return xSemaphoreGiveRecursive(*m) == pdTRUE ? 0 : -1; } + +/*------------------ CondVar ------------------*/ +// Condition variables not supported in FreeRTOS +int8_t _z_condvar_init(_z_condvar_t *cv) { return -1; } +int8_t _z_condvar_free(_z_condvar_t *cv) { return -1; } +int8_t _z_condvar_signal(_z_condvar_t *cv) { return -1; } +int8_t _z_condvar_wait(_z_condvar_t *cv, _z_mutex_t *m) { return -1; } +#endif // Z_MULTI_THREAD == 1 + +/*------------------ Sleep ------------------*/ +int z_sleep_us(size_t time) { + vTaskDelay(pdMS_TO_TICKS(time / 1000)); + return 0; +} + +int z_sleep_ms(size_t time) { + vTaskDelay(pdMS_TO_TICKS(time)); + return 0; +} + +int z_sleep_s(size_t time) { + vTaskDelay(pdMS_TO_TICKS(time * 1000)); + return 0; +} + +/*------------------ Clock ------------------*/ +z_clock_t z_clock_now(void) { return z_time_now(); } + +unsigned long z_clock_elapsed_us(z_clock_t *instant) { return z_clock_elapsed_ms(instant) * 1000; } + +unsigned long z_clock_elapsed_ms(z_clock_t *instant) { return z_time_elapsed_ms(instant); } + +unsigned long z_clock_elapsed_s(z_clock_t *instant) { return z_clock_elapsed_ms(instant) / 1000; } + +/*------------------ Time ------------------*/ +z_time_t z_time_now(void) { return xTaskGetTickCount(); } + +const char *z_time_now_as_str(char *const buf, unsigned long buflen) { + snprintf(buf, buflen, "%u", z_time_now()); + return buf; +} + +unsigned long z_time_elapsed_us(z_time_t *time) { return z_time_elapsed_ms(time) * 1000; } + +unsigned long z_time_elapsed_ms(z_time_t *time) { + z_time_t now = z_time_now(); + + unsigned long elapsed = (now - *time) * portTICK_PERIOD_MS; + return elapsed; +} + +unsigned long z_time_elapsed_s(z_time_t *time) { return z_time_elapsed_ms(time) / 1000; }