diff --git a/CMakeLists.txt b/CMakeLists.txt index d49da60..b2c35c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,11 @@ -cmake_minimum_required(VERSION 3.21) - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +cmake_minimum_required(VERSION 3.10) include(project.conf) - +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules") include(extension) +include(banner) +include(default) include(project) -set(PROJECT_VER "") -get_git_hash(PROJECT_VER) -message("Current project git information: ${PROJECT_VER}") -project(RAFAEL_HOST_SDK LANGUAGES C CXX) -add_subdirectory(module) \ No newline at end of file +ext_add_subdirectory(module) +ext_add_subdirectory_ifdef(CONFIG_GEN_SYSTEM integrate) diff --git a/README.md b/README.md index c20a95d..efaff16 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,48 @@ # EZMesh ## Introduction -The EZMesh Project is the Host Daemon of Rafael's CPC Dongle (Rafael Multi-protocol RCP). The EZMesh, which use a single Rafael's CPC Dongle, can support Host OS using different communication protocol at the same time. The EZMesh currently supports Bluetooth, Thread, and Matter +The EZMesh Project is the Host Daemon of Rafael's EZmesh Dongle (Rafael Multi-protocol RCP). The EZMesh, which uses a single Rafael's EZmesh Dongle, can support the Host OS using different communication protocols simultaneously. -The EZMesh Project is supported by [Rafael Micro](https://www.rafaelmicro.com/). +The EZMesh currently supports: +- **Bluetooth** +- **Sub-G** +- **Thread** +- **Matter** +- **Zigbee** + +Recommend Platform: +- Ubuntu 22.04.3 LTS (Ubuntu-based) +- Raspberry Pi OS (Legacy) Lite (Debian-based) + - Release date: December 5th 2023 + - System: 64-bit + - Kernel version: 6.1 + - Debian version: 11 (bullseye) + +**The EZMesh Project is supported by [Rafael Micro](https://www.rafaelmicro.com/).** --- ## Prepare Env ``` -$ sudo apt update \ -&& sudo apt install git mosquitto libsystemd-dev net-tools curl +$ sudo apt update && sudo apt install git mosquitto libsystemd-dev net-tools curl gcc ``` --- ## Project setup and pre-install -### clone EZMesh +### Clone EZMesh ``` -$ git@github.com:RafaelMicro/EZMesh.git +$ git clone git@github.com:RafaelMicro/EZMesh.git ``` ### Install Cmake -- Ubuntu based platfrom +- Ubuntu-based platform ``` $ sudo curl -L https://github.com/Kitware/CMake/releases/download/v3.21.6/cmake-3.21.6-linux-x86_64.sh --output /tmp/cmake-3.21.6-linux-x86_64.sh \ - && sudo chmod +x /tmp/cmake*.sh \ - && sudo /tmp/cmake*.sh --prefix=/usr/local --skip-license \ - && sudo rm /tmp/cmake* + && sudo chmod +x /tmp/cmake*.sh && sudo /tmp/cmake*.sh --prefix=/usr/local --skip-license && sudo rm /tmp/cmake* ``` -- Debian based platfrom +- Debian-based platform ``` $ sudo curl -L https://github.com/Kitware/CMake/releases/download/v3.21.6/cmake-3.21.6-linux-aarch64.sh --output /tmp/cmake-3.21.6-linux-aarch64.sh \ - && sudo chmod +x /tmp/cmake*.sh \ - && sudo /tmp/cmake*.sh --prefix=/usr/local --skip-license \ - && sudo rm /tmp/cmake* + && sudo chmod +x /tmp/cmake*.sh && sudo /tmp/cmake*.sh --prefix=/usr/local --skip-license && sudo rm /tmp/cmake* ``` ### Bluetooth pre-install -Rafael's EZMesh bluetooth based on Bluez, so makesure Bluez already in your Host. +Rafael's EZMesh Bluetooth is based on Bluez, so make sure Bluez is already in your Host. ### Border Router pre-install ``` $ sudo NAT64=1 module/border_router/ot-br-posix/script/bootstrap @@ -46,39 +56,35 @@ $ ifconfig ``` - Build project (example network interface is enp0s3) ``` -$ mkdir build && cd build \ -&& cmake ../ -DOTBR_INFRA_IF_NAME=enp0s3 && sudo make install && sudo ldconfig\ -&& cd .. +$ mkdir build && cd build && cmake ../ -DOTBR_INFRA_IF_NAME=enp0s3 \ + && sudo make install && sudo ldconfig && cd .. ``` --- ## Apply Project to system service -### Apply CPC +### Apply EZmesh controller ``` -export cpc_path=build/module/cpc/cpcd-system/debconf \ -&& sudo bash $cpc_path/prerm && sudo bash $cpc_path/postrm && sudo bash $cpc_path/postinst +$ sudo ./build/integrate/debian/controller/setup ``` ### Apply Border Router ``` -export br=build/module/border_router/cpc-otbr/debconf \ -&& sudo bash $br/prerm && sudo bash $br/postinst +$ sudo ./build/integrate/debian/border_router/setup ``` ### Apply Bluetooth ``` -export bt=build/module/bluetooth/cpc-bluetooth/debconf \ -&& sudo bash $bt/prerm && sudo bash $bt/postinst +$ sudo ./build/integrate/debian/bluetooth/setup ``` -- Note: Please makesure you RCP dongle already attach on boot -- Note: All service will auto setup on boot +- Note: Please make sure your RCP dongle is already attached to the boot +- Note: All services will auto setup on boot --- ## Manage system service ### Start all service ``` -$ sudo systemctl start cpc-mgmt.service +$ sudo systemctl start ez-mgmt.service ``` ### Restart all service ``` -$ sudo systemctl restart cpc-mgmt.service +$ sudo systemctl restart ez-mgmt.service ``` diff --git a/cmake/banner.cmake b/cmake/banner.cmake new file mode 100644 index 0000000..25c4b0c --- /dev/null +++ b/cmake/banner.cmake @@ -0,0 +1,15 @@ + +function(show_banner var) + message("") + message("") + message(" 8888888888 8888888888P 888b d888 888 .d8888b. 8888888b. 888 d8P ") + message(" 888 d88P 8888b d8888 888 d88P Y88b 888 \"Y88b 888 d8P ") + message(" 888 d88P 88888b.d88888 888 Y88b. 888 888 888 d8P ") + message(" 888888888 d88P 888Y88888P888 .d88b. .d8888b 88888b. \"Y888b. 888 888 888d88K ") + message(" 888 d88P 888 Y888P 888 d8P Y8b 88K 888 \"88b \"Y88b. 888 888 8888888b ") + message(" 888 d88P 888 Y8P 888 88888888 \"Y8888b. 888 888 Y88b \"888 888 888 888 Y88b ") + message(" 888 d88P 888 \" 888 Y8b. X88 888 888 Y8888888P 88888888P\" 888 Y88b ") + message(" 8888888888 d8888888888 888 888 \"Y8888 88888P' 888 888 v${var} Powered By Rafael Micro ") + message("") + message("") +endfunction() diff --git a/cmake/default.cmake b/cmake/default.cmake new file mode 100644 index 0000000..57ac68c --- /dev/null +++ b/cmake/default.cmake @@ -0,0 +1,14 @@ + +ext_config_ifndef(CONFIG_CONTROLLER true) +ext_config_ifndef(CONFIG_UPGRADE true) +ext_config_ifndef(CONFIG_BLUETOOTH false) +ext_config_ifndef(CONFIG_BORDER_ROUTER false) +ext_config_ifndef(CONFIG_ZIGBEE_GW_SERVICE false) +ext_config_ifndef(CONFIG_SUBG_SERVICE false) + +ext_config_ifndef(CONFIG_GEN_SYSTEM false) +ext_config_ifndef(CONFIG_PLATEFROM "") + +ext_config_ifndef(EZMESHD_VER "1.0.0") +ext_config_ifndef(EZMESHD_LIB "1") +ext_config_ifndef(EZMESHD_POTOCOL "3") \ No newline at end of file diff --git a/cmake/extension.cmake b/cmake/extension.cmake index ef29ef4..4ad9c87 100644 --- a/cmake/extension.cmake +++ b/cmake/extension.cmake @@ -7,12 +7,29 @@ macro(get_git_hash _git_hash) OUTPUT_VARIABLE ${_git_hash} OUTPUT_STRIP_TRAILING_WHITESPACE # ERROR_QUIET - WORKING_DIRECTORY - ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif() endmacro() +function(ext_set_config_file src) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${src}.in ${CMAKE_CURRENT_BINARY_DIR}/${src}) +endfunction() + +function(ext_set_config_file_to_dst src dst) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${src}.in ${CMAKE_CURRENT_BINARY_DIR}/${dst}) +endfunction() + +function(ext_set_config_file_with_gen src) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${src}.in ${CMAKE_CURRENT_BINARY_DIR}/${src}.in) + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${src} INPUT ${CMAKE_CURRENT_BINARY_DIR}/${src}.in) +endfunction() + +function(ext_set_config_file_to_dst_with_gen src dst) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${src}.in ${CMAKE_CURRENT_BINARY_DIR}/${dst}.in) + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${dst} INPUT ${CMAKE_CURRENT_BINARY_DIR}/${src}.in) +endfunction() + function(ext_add_subdirectory_ifdef feature dir) if(${${feature}}) add_subdirectory(${dir}) @@ -23,58 +40,52 @@ function(ext_add_subdirectory dir) add_subdirectory(${dir}) endfunction() +function(ext_config define val) + set(${define} ${val}) +endfunction() + +function(ext_config_ifndef define val) + if(NOT DEFINED ${define}) + set(${define} ${val}) + endif() +endfunction() + function(ext_install type src dest component) if("${type}" STREQUAL "EXECUTE") install( FILES "${src}" DESTINATION "${dest}" PERMISSIONS - OWNER_READ - OWNER_WRITE - OWNER_EXECUTE - GROUP_EXECUTE - GROUP_READ - WORLD_READ - WORLD_EXECUTE + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_EXECUTE GROUP_READ + WORLD_READ WORLD_EXECUTE COMPONENT "${component}") elseif("${type}" STREQUAL "TARGET_HEADER") install( TARGETS "${src}" PUBLIC_HEADER DESTINATION "${dest}" PERMISSIONS - OWNER_READ - OWNER_WRITE - OWNER_EXECUTE - GROUP_EXECUTE - GROUP_READ - WORLD_READ - WORLD_EXECUTE + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE COMPONENT "${component}") elseif("${type}" STREQUAL "TARGET_LIBRARY") install( TARGETS "${src}" LIBRARY DESTINATION "${dest}" PERMISSIONS - OWNER_READ - OWNER_WRITE - OWNER_EXECUTE - GROUP_EXECUTE - GROUP_READ - WORLD_READ - WORLD_EXECUTE + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE COMPONENT "${component}") elseif("${type}" STREQUAL "TARGET_RUNTIME") install( TARGETS "${src}" RUNTIME DESTINATION "${dest}" PERMISSIONS - OWNER_READ - OWNER_WRITE - OWNER_EXECUTE - GROUP_EXECUTE - GROUP_READ - WORLD_READ - WORLD_EXECUTE + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE COMPONENT "${component}") elseif("${type}" STREQUAL "FILE") install( @@ -89,20 +100,8 @@ function(ext_install type src dest component) FILES_MATCHING PATTERN * PERMISSIONS - OWNER_READ - OWNER_WRITE - OWNER_EXECUTE - GROUP_EXECUTE - GROUP_READ - WORLD_READ - WORLD_EXECUTE) + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) endif() endfunction() - -macro(ext_ifndef define val) - if(NOT DEFINED ${define}) - set(${define} ${val}) - endif() -endmacro() - - diff --git a/cmake/modules/FindCPCD.cmake b/cmake/modules/FindCPCD.cmake deleted file mode 100644 index bb6f5c8..0000000 --- a/cmake/modules/FindCPCD.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# Find the Silicon Labs CPCd location -# ============================================================================= -# Usage of this module is as follows: -# -# find_package(CPCD) -# -# cmake-format: off -# Variables used by this module: -# -# Variables defined by this module: -# * CPCD_FOUND - True if the CPCd sources are found. -# cmake-format: on -# ============================================================================= -if(CPCD_LOCATION) - set(FETCHCONTENT_SOURCE_DIR_CPCD CMAKE_SOURCE_DIR "${CPCD_LOCATION}") - message(STATUS "Found CPCd at ${CPCD_LOCATION}") -elseif(DEFINED ENV{CPCD_LOCATION}) - set(FETCHCONTENT_SOURCE_DIR_CPCD "$ENV{CPCD_LOCATION}") - message(STATUS "CPCd - using provided CPCD_LOCATION ($ENV{CPCD_LOCATION})") -else() - if(NOT FETCH_CPCD_VERSION) - # The version to fetch should ideally be the same as the version used for fetching GeckoSDK - set(FETCH_CPCD_VERSION "v4.2.0") - endif() - message(STATUS "Fetching CPCd ${FETCH_CPCD_VERSION} from public repository") -endif() - -# Find the version of CPCd -file( - STRINGS ${cpcd_SOURCE_DIR}/CMakeLists.txt _ver_line - REGEX "^ +VERSION \"([^\"]*)\"" - LIMIT_COUNT 1) -string(REGEX MATCHALL "[0-9\.]+" CPCD_VERSION "${_ver_line}") -message(STATUS "CPCd version ${CPCD_VERSION}") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - CPCD - REQUIRED_VARS CPCD_VERSION - VERSION_VAR CPCD_VERSION) diff --git a/cmake/modules/FindEZMESH.cmake b/cmake/modules/FindEZMESH.cmake new file mode 100644 index 0000000..0463e4a --- /dev/null +++ b/cmake/modules/FindEZMESH.cmake @@ -0,0 +1,40 @@ +# Find the Silicon Labs EZMESH location +# ============================================================================= +# Usage of this module is as follows: +# +# find_package(EZMESH) +# +# cmake-format: off +# Variables used by this module: +# +# Variables defined by this module: +# * EZMESH_FOUND - True if the EZMESH sources are found. +# cmake-format: on +# ============================================================================= +if(EZMESH_LOCATION) + set(FETCHCONTENT_SOURCE_DIR_EZMESH CMAKE_SOURCE_DIR "${EZMESH_LOCATION}") + message(STATUS "Found EZMESH at ${EZMESH_LOCATION}") +elseif(DEFINED ENV{EZMESH_LOCATION}) + set(FETCHCONTENT_SOURCE_DIR_EZMESH "$ENV{EZMESH_LOCATION}") + message(STATUS "EZMESH - using provided EZMESH_LOCATION ($ENV{EZMESH_LOCATION})") +else() + if(NOT FETCH_EZMESH_VERSION) + # The version to fetch should ideally be the same as the version used for fetching GeckoSDK + set(FETCH_EZMESH_VERSION "v4.2.0") + endif() + message(STATUS "Fetching EZMESH ${FETCH_EZMESH_VERSION} from public repository") +endif() + +# Find the version of EZMESH +file( + STRINGS ${EZMESH_SOURCE_DIR}/CMakeLists.txt _ver_line + REGEX "^ +VERSION \"([^\"]*)\"" + LIMIT_COUNT 1) +string(REGEX MATCHALL "[0-9\.]+" EZMESH_VERSION "${_ver_line}") +message(STATUS "EZMESH version ${EZMESH_VERSION}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + EZMESH + REQUIRED_VARS EZMESH_VERSION + VERSION_VAR EZMESH_VERSION) diff --git a/cmake/project.cmake b/cmake/project.cmake index 4987b53..17b3790 100644 --- a/cmake/project.cmake +++ b/cmake/project.cmake @@ -1,6 +1,10 @@ -set(CPCD_VER "1.0.0") -set(CPCD_LIB "1") -set(CPCD_POTOCOL "3") -ext_ifndef(CONFIG_CPC false) -ext_ifndef(CONFIG_BLUETOOTH false) -ext_ifndef(CONFIG_BORDER_ROUTER false) +set(EZMESHD_VER "1.0.0") +set(EZMESHD_LIB "1") +set(EZMESHD_POTOCOL "3") + +show_banner(${EZMESHD_VER}) + +set(PROJECT_VER "") +get_git_hash(PROJECT_VER) +message("Current project git version: ${PROJECT_VER}") +project(RAFAEL_HOST_SDK LANGUAGES C CXX) diff --git a/integrate/CMakeLists.txt b/integrate/CMakeLists.txt new file mode 100644 index 0000000..a2ba689 --- /dev/null +++ b/integrate/CMakeLists.txt @@ -0,0 +1,2 @@ + +ext_add_subdirectory_ifdef(CONFIG_GEN_SYSTEM ${CONFIG_PLATEFROM}) diff --git a/integrate/debian/CMakeLists.txt b/integrate/debian/CMakeLists.txt new file mode 100644 index 0000000..4a7ed41 --- /dev/null +++ b/integrate/debian/CMakeLists.txt @@ -0,0 +1,5 @@ + +ext_add_subdirectory_ifdef(CONFIG_CONTROLLER controller) +ext_add_subdirectory_ifdef(CONFIG_BLUETOOTH bluetooth) +ext_add_subdirectory_ifdef(CONFIG_BORDER_ROUTER border_router) + diff --git a/integrate/debian/bluetooth/CMakeLists.txt b/integrate/debian/bluetooth/CMakeLists.txt new file mode 100644 index 0000000..835f96d --- /dev/null +++ b/integrate/debian/bluetooth/CMakeLists.txt @@ -0,0 +1,26 @@ + +set(DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH /var/lib/ezmesh-bluetooth) +set(DEFAULT_EZMESHD_SERVICE_PATH /lib/systemd/system) +if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH} COMPONENT ezmesh-bluetooth) + set(EZMESHD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}${DEFAULT_EZMESHD_SERVICE_PATH}) + set(EZMESH_BLUETOOTH_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH}) +else() + install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH} COMPONENT ezmesh-bluetooth) + set(EZMESHD_SERVICE_PATH ${DEFAULT_EZMESHD_SERVICE_PATH}) + set(EZMESH_BLUETOOTH_SERVICE_PATH ${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH}) +endif() + +# ext_set_config_file(install/postinst) +# ext_set_config_file(install/postrm) +# ext_set_config_file(install/prerm) + +ext_set_config_file(debconf/setup) +ext_set_config_file(ez-bluetooth.service) +ext_set_config_file(scripts/ez_bt_kill) +ext_set_config_file(scripts/ez_bt_attach) + +ext_install( "FILE" ${CMAKE_CURRENT_BINARY_DIR}/ez-bluetooth.service ${EZMESHD_SERVICE_PATH} ezmesh-bluetooth) +ext_install( "EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/scripts/ez_bt_kill ${EZMESH_BLUETOOTH_SERVICE_PATH} ez_bt_kill) +ext_install( "EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/scripts/ez_bt_attach ${EZMESH_BLUETOOTH_SERVICE_PATH} ez_bt_attach) +ext_install( "EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/debconf/setup ${CMAKE_CURRENT_BINARY_DIR} ezmesh-bluetooth) diff --git a/module/bluetooth/cpc-bluetooth/debconf/postinst.in b/integrate/debian/bluetooth/debconf/postinst.in similarity index 95% rename from module/bluetooth/cpc-bluetooth/debconf/postinst.in rename to integrate/debian/bluetooth/debconf/postinst.in index 5a73632..f295260 100644 --- a/module/bluetooth/cpc-bluetooth/debconf/postinst.in +++ b/integrate/debian/bluetooth/debconf/postinst.in @@ -1,5 +1,5 @@ #!/bin/sh -# postinst script for cpc-hci-bridge +# postinst script for ez-bluetooth # # see: dh_installdeb(1) diff --git a/module/bluetooth/cpc-bluetooth/debconf/postrm.in b/integrate/debian/bluetooth/debconf/postrm.in similarity index 100% rename from module/bluetooth/cpc-bluetooth/debconf/postrm.in rename to integrate/debian/bluetooth/debconf/postrm.in diff --git a/module/bluetooth/cpc-bluetooth/debconf/prerm.in b/integrate/debian/bluetooth/debconf/prerm.in similarity index 52% rename from module/bluetooth/cpc-bluetooth/debconf/prerm.in rename to integrate/debian/bluetooth/debconf/prerm.in index f91591c..a477c92 100644 --- a/module/bluetooth/cpc-bluetooth/debconf/prerm.in +++ b/integrate/debian/bluetooth/debconf/prerm.in @@ -1,4 +1,4 @@ #!/bin/sh if type "systemctl" > /dev/null; then - sudo systemctl stop cpc-bluetooth.service + sudo systemctl stop ez-bluetooth.service fi \ No newline at end of file diff --git a/integrate/debian/bluetooth/debconf/setup.in b/integrate/debian/bluetooth/debconf/setup.in new file mode 100644 index 0000000..1f05edd --- /dev/null +++ b/integrate/debian/bluetooth/debconf/setup.in @@ -0,0 +1,53 @@ +#!/bin/sh + +set -e +RAFAEL_VAR_DIR="${CPACK_PACKAGING_INSTALL_PREFIX}/var/lib/rafael/" +RAFAEL_DEV_DIR="${CPACK_PACKAGING_INSTALL_PREFIX}/var/lib/rafael/dev/" + +pre_rm() { + if type "systemctl" > /dev/null; then + sudo systemctl stop ez-bluetooth.service + fi + + if [ "$1" = "purge" -a -e /usr/share/debconf/confmodule ]; then + # Source debconf library + . /usr/share/debconf/confmodule + # Remove my changes to the db + db_purge + fi + + if type "systemctl" >/dev/null; then + systemctl --system daemon-reload || true + fi +} + +setup_user() { + if ! getent group rafael >/dev/null; then + addgroup --quiet --system rafael + fi + + if ! getent passwd rafael >/dev/null; then + adduser --quiet --system --no-create-home --ingroup rafael --home "$RAFAEL_VAR_DIR" --shell /usr/sbin/nologin rafael + usermod -a -G dialout rafael + fi +} + +fix_permissions() { + mkdir -p $RAFAEL_VAR_DIR + chown rafael $RAFAEL_VAR_DIR + mkdir -p $RAFAEL_DEV_DIR + chown rafael $RAFAEL_DEV_DIR +} + +enable_hci_services() { + if type "systemctl" >/dev/null; then + systemctl --system daemon-reload || true + fi +} + +pre_rm +setup_user +fix_permissions +enable_hci_services + +exit 0 \ No newline at end of file diff --git a/integrate/debian/bluetooth/ez-bluetooth.service.in b/integrate/debian/bluetooth/ez-bluetooth.service.in new file mode 100644 index 0000000..8b80cc3 --- /dev/null +++ b/integrate/debian/bluetooth/ez-bluetooth.service.in @@ -0,0 +1,16 @@ +[Unit] +Description=EZMESH BT Bridge service (ver @PROJECT_VER@) + + +[Service] +WorkingDirectory=/var/lib/rafael/dev +ExecStartPre=${EZMESH_BLUETOOTH_SERVICE_PATH}/ez_bt_kill +ExecStart=${EZMESH_BLUETOOTH_SERVICE_PATH}/ez-bluetooth +ExecStartPost=${EZMESH_BLUETOOTH_SERVICE_PATH}/ez_bt_attach +ExecStopPost=${EZMESH_BLUETOOTH_SERVICE_PATH}/ez_bt_kill +# Restart=on-failure +KillMode=process +LimitMEMLOCK=infinity + +[Install] +WantedBy=multi-user.target diff --git a/module/bluetooth/cpc-bluetooth/scripts/startpost.in b/integrate/debian/bluetooth/scripts/ez_bt_attach.in similarity index 100% rename from module/bluetooth/cpc-bluetooth/scripts/startpost.in rename to integrate/debian/bluetooth/scripts/ez_bt_attach.in diff --git a/module/bluetooth/cpc-bluetooth/scripts/stop.in b/integrate/debian/bluetooth/scripts/ez_bt_kill.in similarity index 100% rename from module/bluetooth/cpc-bluetooth/scripts/stop.in rename to integrate/debian/bluetooth/scripts/ez_bt_kill.in diff --git a/integrate/debian/border_router/CMakeLists.txt b/integrate/debian/border_router/CMakeLists.txt new file mode 100644 index 0000000..4b333af --- /dev/null +++ b/integrate/debian/border_router/CMakeLists.txt @@ -0,0 +1,21 @@ +include(FetchContent) + +set(FETCHCONTENT_QUIET False) +set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME ez-otbr) + +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/options.cmake") + +# ext_set_config_file(debconf/prerm) +# ext_set_config_file(debconf/postinst) +# ext_set_config_file(debconf/postrm) + +ext_set_config_file_with_gen(debconf/setup) +ext_set_config_file_with_gen(debconf/services/ez-otbr) +ext_set_config_file(debconf/services/ez-otbr.service) + +ext_install("DIRECTORY" ${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/otbr-agent.service.d /etc/systemd/system ez-otbr) +ext_install("DIRECTORY" ${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/otbr-nat44.service.d /etc/systemd/system ez-otbr) +ext_install("DIRECTORY" ${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/otbr-firewall.service.d /etc/systemd/system ez-otbr) +ext_install("FILE" ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/ez-otbr.service ${OTBR_SYSTEMD_UNIT_DIR} ez-otbr) +ext_install("FILE" ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/ez-otbr /etc/default ez-otbr) +ext_install("EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/debconf/setup ${CMAKE_CURRENT_BINARY_DIR} ez-otbr) diff --git a/integrate/debian/border_router/cmake/options.cmake b/integrate/debian/border_router/cmake/options.cmake new file mode 100644 index 0000000..20e1721 --- /dev/null +++ b/integrate/debian/border_router/cmake/options.cmake @@ -0,0 +1,78 @@ +# Options used to configure the otbr bootstrap and setup scripts +option(EZMESH_OTBR_BORDER_ROUTING "enable border routing features" 1) +option(EZMESH_OTBR_BACKBONE_ROUTER "enable backbone routing features" 1) +option(EZMESH_OTBR_REFERENCE_DEVICE "enable openthread reference device feature-set" 0) +option(EZMESH_OTBR_RELEASE "remove dependency on testing utilities" 1) # Unused - no runtime dependencies +option(EZMESH_OTBR_NAT64 "include nat64 service" 0) +option(EZMESH_OTBR_DNS64 "include dns64 service" 0) +option(EZMESH_OTBR_DHCPV6_PD "include dhcp service" 0) +option(EZMESH_OTBR_NETWORK_MANAGER "include network manager service" 0) + +# Set OTBR runtime and service options +set(OTBR_SYSTEMD_UNIT_DIR "/lib/systemd/system" CACHE STRING "Destination path for otbr systemd service files") +set(OTBR_INFRA_IF_NAME "eth0" CACHE STRING "The infrastructure interface name") +set(OTBR_RADIO_URL "spinel+ezmesh://ezmeshd_0?iid=2" CACHE STRING "URL") +set(OTBR_MDNS "avahi" CACHE STRING "mDNS publisher provider") +set(OTBR_NAT64_SERVICE "openthread" CACHE STRING "nat64 service name") + +# Packages installed in bootstrap when above options are enabled +set(EZMESH_OTBR_RECS "rsyslog, libavahi-client3, avahi-daemon, libjsoncpp-dev") +set(NAT64_RECS "iptables") +set(DNS64_RECS "bind9, resolvconf") +set(NETWORK_MANAGER_RECS "dnsmasq, network-manager") +set(DHCPV6_PD_RECS "dhcpcd5") +set(REFERENCE_DEVICE_RECS "radvd, dnsutils") +set(BACKBONE_ROUTER_RECS "libnetfilter-queue1") + +# Including options to enable and packages to recommend +# based off of selected options +if(EZMESH_OTBR_NAT64) + string(COMPARE EQUAL ${OTBR_NAT64_SERVICE} "tayga" TAYGA_NAT64_SERVICE) + + if(TAYGA_NAT64_SERVICE) + string(APPEND NAT64_RECS ", ${OTBR_NAT64_SERVICE}") + endif(TAYGA_NAT64_SERVICE) + + string(APPEND EZMESH_OTBR_RECS ", ${NAT64_RECS}") +endif(EZMESH_OTBR_NAT64) + +if(EZMESH_OTBR_DNS64) + string(APPEND EZMESH_OTBR_RECS ", ${DNS64_RECS}") +endif(EZMESH_OTBR_DNS64) + +if(EZMESH_OTBR_NETWORK_MANAGER) + string(APPEND EZMESH_OTBR_RECS ", ${NETWORK_MANAGER_RECS}") +endif(EZMESH_OTBR_NETWORK_MANAGER) + +if(EZMESH_OTBR_DHCPV6_PD) + string(APPEND EZMESH_OTBR_RECS ", ${DHCPV6_PD_RECS}") +endif(EZMESH_OTBR_DHCPV6_PD) + +if(EZMESH_OTBR_REFERENCE_DEVICE) + string(APPEND EZMESH_OTBR_RECS ", ${REFERENCE_DEVICE_RECS}") + set(OTBR_NO_AUTO_ATTACH 1 CACHE BOOL "disable auto Thread attach") + set(OT_REFERENCE_DEVICE ON CACHE BOOL "enable openthread reference device feature-set") + set(OT_DHCP6_CLIENT ON CACHE BOOL "enable DHCP6 client support") + set(OT_DHCP6_SERVER ON CACHE BOOL "enable DHCP6 server support") +endif(EZMESH_OTBR_REFERENCE_DEVICE) + +if(EZMESH_OTBR_BACKBONE_ROUTER) + string(APPEND EZMESH_OTBR_RECS ", ${BACKBONE_ROUTER_RECS}") + set(OTBR_BACKBONE_ROUTER ON CACHE BOOL "enable backbone router features") + if(EZMESH_OTBR_REFERENCE_DEVICE) + set(OTBR_DUA_ROUTING ON CACHE BOOL "enable backbone router DUA routing") + endif(EZMESH_OTBR_REFERENCE_DEVICE) +endif(EZMESH_OTBR_BACKBONE_ROUTER) + +if(EZMESH_OTBR_BORDER_ROUTING) + set(OTBR_BORDER_ROUTING ON CACHE BOOL "enable border routing features") +endif(EZMESH_OTBR_BORDER_ROUTING) + +# Setting additional default options +option(OTBR_DBUS "enable DBUS support" ON) +option(OTBR_DNSSD_DISCOVERY_PROXY "enable dns-sd discovery proxy support" ON) +option(OTBR_SRP_ADVERTISING_PROXY "enable advertising proxy" ON) + +# Adding selected packages to debian recommends control field +message("OTBR INSTALL: ${EZMESH_OTBR_RECS}") +set(CPACK_DEBIAN_UIC-OTBR_PACKAGE_RECOMMENDS ${EZMESH_OTBR_RECS} CACHE STRING "Package recommendations for ez-otbr: ${EZMESH_OTBR_RECS}" FORCE) diff --git a/module/border_router/cpc-otbr/debconf/postinst.in b/integrate/debian/border_router/debconf/postinst.in similarity index 65% rename from module/border_router/cpc-otbr/debconf/postinst.in rename to integrate/debian/border_router/debconf/postinst.in index 10606e5..c52ddc2 100644 --- a/module/border_router/cpc-otbr/debconf/postinst.in +++ b/integrate/debian/border_router/debconf/postinst.in @@ -1,5 +1,5 @@ #!/bin/bash -# postinst script for cpc-otbr +# postinst script for ez-otbr # # see: dh_installdeb(1) @@ -14,17 +14,15 @@ configure_otbr_install() { export OTBR_MDNS=@OTBR_MDNS@ export NAT64_SERVICE=@OTBR_NAT64_SERVICE@ - export RELEASE=$ - export REFERENCE_DEVICE=$ + export RELEASE=$ + export REFERENCE_DEVICE=$ - export BORDER_ROUTING=$ - export BACKBONE_ROUTER=$ - export NAT64=$ - export DNS64=$ - export DHCPV6_PD=$ - export NETWORK_MANAGER=$ - # export WEB_GUI=$ - # export REST_API=$ + export BORDER_ROUTING=$ + export BACKBONE_ROUTER=$ + export NAT64=$ + export DNS64=$ + export DHCPV6_PD=$ + export NETWORK_MANAGER=$ } init_otbr_scripts() { @@ -55,8 +53,7 @@ install_services() { } setup_config() { - cp /usr/local/etc/dbus-1/system.d/otbr-agent.conf \ - /etc/dbus-1/system.d/otbr-agent.conf + cp /usr/local/etc/dbus-1/system.d/otbr-agent.conf /etc/dbus-1/system.d/otbr-agent.conf } enable_otbr_services() { diff --git a/module/border_router/cpc-otbr/debconf/postrm.in b/integrate/debian/border_router/debconf/postrm.in similarity index 100% rename from module/border_router/cpc-otbr/debconf/postrm.in rename to integrate/debian/border_router/debconf/postrm.in diff --git a/module/border_router/cpc-otbr/debconf/prerm.in b/integrate/debian/border_router/debconf/prerm.in similarity index 67% rename from module/border_router/cpc-otbr/debconf/prerm.in rename to integrate/debian/border_router/debconf/prerm.in index 0ebf281..d1b80ad 100644 --- a/module/border_router/cpc-otbr/debconf/prerm.in +++ b/integrate/debian/border_router/debconf/prerm.in @@ -6,17 +6,15 @@ configure_otbr_uninstall() { export OTBR_MDNS=@OTBR_MDNS@ export NAT64_SERVICE=@OTBR_NAT64_SERVICE@ - export RELEASE=$ - export REFERENCE_DEVICE=$ + export RELEASE=$ + export REFERENCE_DEVICE=$ - export BORDER_ROUTING=$ - export BACKBONE_ROUTER=$ - export NAT64=$ - export DNS64=$ - export DHCPV6_PD=$ - export NETWORK_MANAGER=$ - # export WEB_GUI=$ - # export REST_API=$ + export BORDER_ROUTING=$ + export BACKBONE_ROUTER=$ + export NAT64=$ + export DNS64=$ + export DHCPV6_PD=$ + export NETWORK_MANAGER=$ } init_otbr_scripts() { @@ -44,8 +42,8 @@ clean_temp_dirs() { } uninstall_services() { - systemctl stop cpc-otbr - systemctl disable cpc-otbr + systemctl stop ez-otbr + systemctl disable ez-otbr cd $OTBR_SCRIPTS_DIR/.. extend_sudo_timeout diff --git a/integrate/debian/border_router/debconf/services/ez-otbr.in b/integrate/debian/border_router/debconf/services/ez-otbr.in new file mode 100644 index 0000000..1b9d166 --- /dev/null +++ b/integrate/debian/border_router/debconf/services/ez-otbr.in @@ -0,0 +1,15 @@ +INFRA_IF_NAME=@OTBR_INFRA_IF_NAME@ +RADIO_URL=@OTBR_RADIO_URL@ + +OTBR_MDNS=@OTBR_MDNS@ +NAT64_SERVICE=@OTBR_NAT64_SERVICE@ + +RELEASE=$ +REFERENCE_DEVICE=$ + +BORDER_ROUTING=$ +BACKBONE_ROUTER=$ +NAT64=$ +DNS64=$ +DHCPV6_PD=$ +NETWORK_MANAGER=$ diff --git a/module/border_router/cpc-otbr/debconf/services/cpc-otbr.service.in b/integrate/debian/border_router/debconf/services/ez-otbr.service.in similarity index 62% rename from module/border_router/cpc-otbr/debconf/services/cpc-otbr.service.in rename to integrate/debian/border_router/debconf/services/ez-otbr.service.in index 9e0c1d3..3f98d0e 100644 --- a/module/border_router/cpc-otbr/debconf/services/cpc-otbr.service.in +++ b/integrate/debian/border_router/debconf/services/ez-otbr.service.in @@ -1,10 +1,10 @@ [Unit] -Description=CPC Openthread Border Router (ver @PROJECT_VER@) +Description=EZMESH Openthread Border Router (ver @PROJECT_VER@) [Service] Type=oneshot RemainAfterExit=yes -EnvironmentFile=-/etc/default/cpc-otbr +EnvironmentFile=-/etc/default/ez-otbr ExecStart=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/otbr/script/server [Install] diff --git a/integrate/debian/border_router/debconf/services/otbr-agent.service.d/override.conf b/integrate/debian/border_router/debconf/services/otbr-agent.service.d/override.conf new file mode 100644 index 0000000..75f6a77 --- /dev/null +++ b/integrate/debian/border_router/debconf/services/otbr-agent.service.d/override.conf @@ -0,0 +1,4 @@ +[Unit] +PartOf=ez-otbr.service +BindsTo=ezmeshd.service +After=ezmeshd.service diff --git a/integrate/debian/border_router/debconf/services/otbr-firewall.service.d/override.conf b/integrate/debian/border_router/debconf/services/otbr-firewall.service.d/override.conf new file mode 100644 index 0000000..f50bffd --- /dev/null +++ b/integrate/debian/border_router/debconf/services/otbr-firewall.service.d/override.conf @@ -0,0 +1,2 @@ +[Unit] +PartOf=ez-otbr.service diff --git a/integrate/debian/border_router/debconf/services/otbr-nat44.service.d/override.conf b/integrate/debian/border_router/debconf/services/otbr-nat44.service.d/override.conf new file mode 100644 index 0000000..f50bffd --- /dev/null +++ b/integrate/debian/border_router/debconf/services/otbr-nat44.service.d/override.conf @@ -0,0 +1,2 @@ +[Unit] +PartOf=ez-otbr.service diff --git a/integrate/debian/border_router/debconf/setup.in b/integrate/debian/border_router/debconf/setup.in new file mode 100644 index 0000000..cf5aa21 --- /dev/null +++ b/integrate/debian/border_router/debconf/setup.in @@ -0,0 +1,124 @@ +#!/bin/bash + +OTBR_SCRIPTS_DIR=/usr/local/share/otbr/script + +configure_otbr_uninstall() { + export OTBR_MDNS=@OTBR_MDNS@ + export NAT64_SERVICE=@OTBR_NAT64_SERVICE@ + + export RELEASE=$ + export REFERENCE_DEVICE=$ + + export BORDER_ROUTING=$ + export BACKBONE_ROUTER=$ + export NAT64=$ + export DNS64=$ + export DHCPV6_PD=$ + export NETWORK_MANAGER=$ +} + +configure_otbr_install() { + export INFRA_IF_NAME=@OTBR_INFRA_IF_NAME@ + export RADIO_URL=@OTBR_RADIO_URL@ + + export OTBR_MDNS=@OTBR_MDNS@ + export NAT64_SERVICE=@OTBR_NAT64_SERVICE@ + + export RELEASE=$ + export REFERENCE_DEVICE=$ + + export BORDER_ROUTING=$ + export BACKBONE_ROUTER=$ + export NAT64=$ + export DNS64=$ + export DHCPV6_PD=$ + export NETWORK_MANAGER=$ +} + +install_services() { + cd $OTBR_SCRIPTS_DIR/.. + firewall_install + ipforward_install + rt_tables_install + nat64_install + dns64_install + network_manager_install + dhcpv6_pd_install + border_routing_install +} + +init_otbr_scripts() { + . $OTBR_SCRIPTS_DIR/_initrc + . $OTBR_SCRIPTS_DIR/_border_routing + . $OTBR_SCRIPTS_DIR/_otbr + . $OTBR_SCRIPTS_DIR/_ipforward + . $OTBR_SCRIPTS_DIR/_nat64 + . $OTBR_SCRIPTS_DIR/_dns64 + . $OTBR_SCRIPTS_DIR/_dhcpv6_pd + . $OTBR_SCRIPTS_DIR/_network_manager + . $OTBR_SCRIPTS_DIR/_rt_tables + . $OTBR_SCRIPTS_DIR/_swapfile + . $OTBR_SCRIPTS_DIR/_sudo_extend + . $OTBR_SCRIPTS_DIR/_disable_services + . $OTBR_SCRIPTS_DIR/_firewall +} + +clean_temp_dirs() { + STAGE_DIR=stage + BUILD_DIR=build + + [[ ! -d $STAGE_DIR ]] || rm -rf $STAGE_DIR + [[ ! -d $BUILD_DIR ]] || rm -rf $BUILD_DIR +} + +uninstall_services() { + systemctl stop ez-otbr + systemctl disable ez-otbr + + cd $OTBR_SCRIPTS_DIR/.. + extend_sudo_timeout + setup_swapfile + disable_services + otbr_uninstall + border_routing_uninstall + network_manager_uninstall + dhcpv6_pd_uninstall + nat64_uninstall + dns64_uninstall + rt_tables_uninstall + ipforward_uninstall + firewall_uninstall +} + +reload_daemon() { + if type "systemctl" >/dev/null; then + systemctl --system daemon-reload || true + fi +} + +setup_config() { + cp /usr/local/etc/dbus-1/system.d/otbr-agent.conf /etc/dbus-1/system.d/otbr-agent.conf +} + +enable_otbr_services() { + if type "systemctl" >/dev/null; then + systemctl --system daemon-reload || true + fi +} + +# configure_otbr_uninstall +# init_otbr_scripts +# clean_temp_dirs +# uninstall_services +# reload_daemon + +echo "Start Install Border Router Service" +configure_otbr_install +init_otbr_scripts +install_services +setup_config +enable_otbr_services +echo "Install Border Router Service Success" + + +exit 0 diff --git a/integrate/debian/controller/CMakeLists.txt b/integrate/debian/controller/CMakeLists.txt new file mode 100644 index 0000000..a30c38e --- /dev/null +++ b/integrate/debian/controller/CMakeLists.txt @@ -0,0 +1,52 @@ + +if((${CONFIG_BLUETOOTH}) AND (${CONFIG_BORDER_ROUTER})) + set(MGMT_POSTFIX -all) +elseif(${CONFIG_BLUETOOTH}) + set(MGMT_POSTFIX -bt) +elseif(${CONFIG_BORDER_ROUTER}) + set(MGMT_POSTFIX -br) +endif() + +# # ext_set_config_file(debconf/config) +# ext_set_config_file(debconf/postinst) +# ext_set_config_file(debconf/prerm) +# ext_set_config_file(debconf/postrm) +ext_set_config_file(debconf/setup) + +# ext_set_config_file(debconf/templates) +ext_set_config_file(debconf/conffiles) +ext_set_config_file(ezmeshd.service) +ext_set_config_file(ez-mgmt.service) +ext_set_config_file_to_dst(scripts/ez-mgmt${MGMT_POSTFIX} scripts/ez-mgmt) +# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/ez-mgmt${MGMT_POSTFIX}.in ${CMAKE_CURRENT_BINARY_DIR}/scripts/ez-mgmt) + + +set(DEFAULT_EZMESH_SERVICE_PATH lib/systemd/system/) +set(DEFAULT_EZMESH_SCRIPTS_PATH src/scripts/) +if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_SCRIPTS_PATH} COMPONENT ez-mgmt) + set(EZMESH_SCRIPTS_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_SERVICE_PATH}) + set(EZMESH_MGMT_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_SCRIPTS_PATH}) +else() + install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_SCRIPTS_PATH} COMPONENT ez-mgmt) + set(EZMESH_SCRIPTS_PATH ${DEFAULT_EZMESH_SERVICE_PATH}) + set(EZMESH_MGMT_PATH ${DEFAULT_EZMESH_SCRIPTS_PATH}) +endif() + +ext_install("FILE" ${CMAKE_CURRENT_BINARY_DIR}/ez-mgmt.service ${EZMESH_SCRIPTS_PATH} ezmesh) +ext_install("EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/scripts/ez-mgmt ${EZMESH_MGMT_PATH} ez-mgmt) +ext_install("EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/ezmeshd.service ${EZMESH_SCRIPTS_PATH} ezmesh) + + +if(EZMESH_LOCATION) + # Install configuration file + ext_install( "FILE" ${EZMESH_LOCATION}/etc/ez_config.ini ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} ezmesh) +else() + ext_install("TARGET_HEADER" ezmesh ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} ezmesh) + ext_install("TARGET_LIBRARY" ezmesh ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} ezmesh) + ext_install("TARGET_RUNTIME" ezmesh ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR} ezmesh) + ext_install("FILE" ${EZMESH_SOURCE_DIR}/ez_config.ini ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} ezmesh) + ext_install("TARGET_HEADER" ezmesh ${EZMESH_MGMT_PATH} ez-mgmt) + ext_install( "EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/debconf/setup ${CMAKE_CURRENT_BINARY_DIR} ezmesh) +endif() + diff --git a/module/cpc/cpcd-system/debconf/conffiles.in b/integrate/debian/controller/debconf/conffiles.in similarity index 100% rename from module/cpc/cpcd-system/debconf/conffiles.in rename to integrate/debian/controller/debconf/conffiles.in diff --git a/module/cpc/cpcd-system/debconf/config.in b/integrate/debian/controller/debconf/config.in similarity index 68% rename from module/cpc/cpcd-system/debconf/config.in rename to integrate/debian/controller/debconf/config.in index f670f29..9b410ea 100755 --- a/module/cpc/cpcd-system/debconf/config.in +++ b/integrate/debian/controller/debconf/config.in @@ -12,22 +12,22 @@ if [ -e $RAFAEL_CONFFILE ]; then do # Set the state depending on the line read from the config file case "$line" in - "cpcd:" ) # State: cpcd - state="cpcd" + "ezmesh:" ) # State: ezmesh + state="ezmesh" ;; " "* | "-"* ) # Lines starting with '-' or ' ' don't trigger state change. # Do nothing. ;; *) state="" ;; # Set state to empty, Any unknown text, that doesn't begin with '-' or ' ' esac - # STM to update entries under 'cpcd:' + # STM to update entries under 'ezmesh:' case $state in - "cpcd" ) + "ezmesh" ) case "$line" in *"serial:"*) echo "$line" ;; *) - ;; # Anything else inside cpcd we skip + ;; # Anything else inside ezmesh we skip esac ;; *) ;; @@ -37,21 +37,21 @@ if [ -e $RAFAEL_CONFFILE ]; then # Replace : With =", append " to each line, Remove all spaces, # Remove - in the beginning of the line # Remove lines having "", - # Rename serial to cpcd_serial to coexist with zpc and/or zipgc - sed -e 's/:/="/g;s/$/"/g;s/ //g;s/^-//g;/""/d;s/serial/cpcd_serial/g' $RAFAEL_CONFFILE.sh.tmp > $RAFAEL_CONFFILE.sh + # Rename serial to ezmesh_serial to coexist with zpc and/or zipgc + sed -e 's/:/="/g;s/$/"/g;s/ //g;s/^-//g;/""/d;s/serial/ezmesh_serial/g' $RAFAEL_CONFFILE.sh.tmp > $RAFAEL_CONFFILE.sh echo "Existing config options" cat $RAFAEL_CONFFILE.sh - #Source the file to set $cpcd_serial + #Source the file to set $ezmesh_serial . $RAFAEL_CONFFILE.sh || true rm $RAFAEL_CONFFILE.sh $RAFAEL_CONFFILE.sh.tmp #Preload debconf with what was in the conf file - if [ ! -z "$cpcd_serial" ]; then - db_set cpcd/serial_port "$cpcd_serial" + if [ ! -z "$ezmesh_serial" ]; then + db_set ezmesh/serial_port "$ezmesh_serial" fi fi -db_input critical cpcd/serial_port || true +db_input critical ezmesh/serial_port || true db_go diff --git a/module/cpc/cpcd-system/debconf/postinst.in b/integrate/debian/controller/debconf/postinst.in similarity index 63% rename from module/cpc/cpcd-system/debconf/postinst.in rename to integrate/debian/controller/debconf/postinst.in index 641ce89..f0fe7f5 100755 --- a/module/cpc/cpcd-system/debconf/postinst.in +++ b/integrate/debian/controller/debconf/postinst.in @@ -6,11 +6,12 @@ . /usr/share/debconf/confmodule RAFAEL_VAR_DIR="${CPACK_PACKAGING_INSTALL_PREFIX}/var/lib/rafael/" -RAFAEL_CONFFILE=$RAFAEL_CONFDIR/rafael.cfg -CPCD_CONFFILE=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/cpcd.conf +RAFAEL_CONFDIR="${CPACK_PACKAGING_INSTALL_PREFIX}/etc/rafael" +RAFAEL_CONFFILE="${RAFAEL_CONFDIR}/rafael.cfg" +ezmesh_CONFFILE="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/ez_config.ini" # Defaults for required arguments -CPCD_DEFAULT_CFG_SERIAL="/dev/ttyUSB0" +ezmesh_DEFAULT_CFG_SERIAL="/dev/ttyUSB0" setup_user() { if ! getent group rafael >/dev/null; then @@ -28,27 +29,28 @@ fix_permissions() { chown rafael $RAFAEL_VAR_DIR } -enable_start_cpcd() { +enable_start_ezmesh() { if type "systemctl" >/dev/null; then systemctl --system daemon-reload || true - # systemctl start cpcd || true - # systemctl enable cpcd || true - systemctl start cpc-mgmt.service || true - systemctl enable cpc-mgmt.service + systemctl start ez-mgmt.service || true + systemctl enable ez-mgmt.service fi } handle_conf() { - if ! grep -q "cpcd:" $RAFAEL_CONFFILE; then + echo "ezmesh dir:" >> $RAFAEL_CONFDIR + mkdir -p $RAFAEL_CONFDIR + if ! grep -q "ezmesh:" $RAFAEL_CONFFILE; then + echo "ezmesh dir:" >> $RAFAEL_CONFDIR mkdir -p $RAFAEL_CONFDIR - echo "cpcd:" >> $RAFAEL_CONFFILE - echo " serial: $CPCD_DEFAULT_CFG_SERIAL" >> $RAFAEL_CONFFILE + echo "ezmesh:" >> $RAFAEL_CONFFILE + echo " serial: $ezmesh_DEFAULT_CFG_SERIAL" >> $RAFAEL_CONFFILE fi - db_get cpcd/serial_port - CFG_CPCD_SERIAL="$RET" + db_get ezmesh/serial_port + CFG_ezmesh_SERIAL="$RET" if [ "$RET" = "" ]; then - CFG_CPCD_SERIAL="$CPCD_DEFAULT_CFG_SERIAL" + CFG_ezmesh_SERIAL="$ezmesh_DEFAULT_CFG_SERIAL" fi # Update configuration file with outcome of configuration @@ -59,8 +61,8 @@ handle_conf() { do # Set the state depending on the line read from the config file case "$line" in - "cpcd:" ) # State: cpcd - state="cpcd" + "ezmesh:" ) # State: ezmesh + state="ezmesh" ;; " "* | "-"* ) # Lines starting with '-' or ' ' don't trigger state change. # Do nothing. @@ -68,19 +70,19 @@ handle_conf() { *) state="" ;; # Set state to empty, Any unknown text, that doesn't begin with '-' or ' ' esac leftside=$(echo "$line" | cut -f1 -d":") - # STM to update entries under 'cpcd:' + # STM to update entries under 'ezmesh:' case $state in - "cpcd" ) + "ezmesh" ) case "$line" in - "cpcd:" ) - echo "$line" ;; # cpcd should not be indented + "ezmesh:" ) + echo "$line" ;; # ezmesh should not be indented *"serial:"*) - echo "$leftside: $CFG_CPCD_SERIAL" - # Update CPCd configuration file - sed -i "/uart_device_file/c\uart_device_file: $CFG_CPCD_SERIAL" $CPCD_CONFFILE + echo "$leftside: $CFG_ezmesh_SERIAL" + # Update ezmesh configuration file + sed -i "/uart_device_file/c\uart_device_file: $CFG_ezmesh_SERIAL" $ezmesh_CONFFILE ;; *) - echo "$line" ;; # Anything inside cpcd we indent + echo "$line" ;; # Anything inside ezmesh we indent esac ;; *) echo "$line" ;; # Anything else we just echo the line @@ -115,8 +117,7 @@ abort-upgrade | abort-remove | abort-deconfigure) ;; esac #DEBHELPER# - -# Enable and start RAFAEL_CPCD daemon -enable_start_cpcd +# Enable and start RAFAEL_ezmesh daemon +enable_start_ezmesh exit 0 diff --git a/module/cpc/cpcd-system/debconf/postrm.in b/integrate/debian/controller/debconf/postrm.in similarity index 100% rename from module/cpc/cpcd-system/debconf/postrm.in rename to integrate/debian/controller/debconf/postrm.in diff --git a/integrate/debian/controller/debconf/prerm.in b/integrate/debian/controller/debconf/prerm.in new file mode 100755 index 0000000..1334309 --- /dev/null +++ b/integrate/debian/controller/debconf/prerm.in @@ -0,0 +1,5 @@ +#!/bin/sh +if type "systemctl" > /dev/null; then + systemctl stop ezmeshd.service + systemctl disable ezmeshd.service +fi diff --git a/integrate/debian/controller/debconf/setup.in b/integrate/debian/controller/debconf/setup.in new file mode 100644 index 0000000..6ccc1e9 --- /dev/null +++ b/integrate/debian/controller/debconf/setup.in @@ -0,0 +1,130 @@ +#!/bin/sh -e +# postinst script for rafael +# +# see: dh_installdeb(1) + +. /usr/share/debconf/confmodule + +RAFAEL_VAR_DIR="${CPACK_PACKAGING_INSTALL_PREFIX}/var/lib/rafael" +RAFAEL_CONFDIR="${CPACK_PACKAGING_INSTALL_PREFIX}/etc/rafael" +RAFAEL_CONFFILE=$RAFAEL_CONFDIR"/rafael.cfg" +ezmesh_CONFFILE="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/ez_config.ini" + +# Defaults for required arguments +ezmesh_DEFAULT_CFG_SERIAL="/dev/ttyUSB0" + +pre_rm() { + if type "systemctl" > /dev/null; then + systemctl stop ezmeshd.service + systemctl disable ezmeshd.service + fi + + if [ "$1" = "purge" -a -e /usr/share/debconf/confmodule ]; then + # Source debconf library + . /usr/share/debconf/confmodule + # Remove my changes to the db + db_purge + fi + + if type "systemctl" >/dev/null; then + systemctl --system daemon-reload || true + fi +} + +setup_user() { + if ! getent group rafael >/dev/null; then + addgroup --quiet --system rafael + fi + + if ! getent passwd rafael >/dev/null; then + adduser --quiet --system --no-create-home --ingroup rafael --home "$RAFAEL_VAR_DIR" --shell /usr/sbin/nologin rafael + usermod -a -G dialout rafael + fi +} + +fix_permissions() { + mkdir -p $RAFAEL_VAR_DIR + chown rafael $RAFAEL_VAR_DIR +} + +enable_start_ezmesh() { + if type "systemctl" >/dev/null; then + systemctl --system daemon-reload || true + systemctl enable ez-mgmt.service + fi +} + +handle_conf() { + echo $RAFAEL_CONFDIR + echo $RAFAEL_CONFFILE + if ! grep -q "ezmesh:" $RAFAEL_CONFFILE; then + mkdir -p $RAFAEL_CONFDIR + echo "ezmesh:" >> $RAFAEL_CONFFILE + echo " serial: $ezmesh_DEFAULT_CFG_SERIAL" >> $RAFAEL_CONFFILE + fi + + db_get ezmesh/serial_port + CFG_ezmesh_SERIAL="$RET" + if [ "$RET" = "" ]; then + CFG_ezmesh_SERIAL="$ezmesh_DEFAULT_CFG_SERIAL" + fi + + # Update configuration file with outcome of configuration + # This is a small state machine that can update the Unify config file, which is written in YAML + state="" + + while IFS= read line #Read IFS https://en.wikipedia.org/wiki/Input_Field_Separators + do + # Set the state depending on the line read from the config file + case "$line" in + "ezmesh:" ) # State: ezmesh + state="ezmesh" + ;; + " "* | "-"* ) # Lines starting with '-' or ' ' don't trigger state change. + # Do nothing. + ;; + *) state="" ;; # Set state to empty, Any unknown text, that doesn't begin with '-' or ' ' + esac + leftside=$(echo "$line" | cut -f1 -d":") + # STM to update entries under 'ezmesh:' + case $state in + "ezmesh" ) + case "$line" in + "ezmesh:" ) + echo "$line" ;; # ezmesh should not be indented + *"serial:"*) + echo "$leftside: $CFG_ezmesh_SERIAL" + # Update ezmesh configuration file + sed -i "/uart_device_file/c\uart_device_file: $CFG_ezmesh_SERIAL" $ezmesh_CONFFILE + ;; + *) + echo "$line" ;; # Anything inside ezmesh we indent + esac ;; + *) + echo "$line" ;; # Anything else we just echo the line + # Without IFS= , echo here would remove the leading spaces and ruin the yaml formatting + esac + done < "$RAFAEL_CONFFILE" > "$RAFAEL_CONFFILE.tmp" + mv "$RAFAEL_CONFFILE.tmp" "$RAFAEL_CONFFILE" + + echo "===" + echo "$RAFAEL_CONFFILE new contents:" + echo "===" + cat "$RAFAEL_CONFFILE" + echo "===" + + +} + +echo "Setup EZMesh Controllor" +pre_rm +# handle_conf +setup_user +fix_permissions +echo "Setup EZMesh Controllor Successed" + +#DEBHELPER# +# Enable and start RAFAEL_ezmesh daemon +enable_start_ezmesh + +exit 0 diff --git a/integrate/debian/controller/debconf/templates.in b/integrate/debian/controller/debconf/templates.in new file mode 100755 index 0000000..635466e --- /dev/null +++ b/integrate/debian/controller/debconf/templates.in @@ -0,0 +1,5 @@ +Template: ezmeshd/serial_port +Type: string +Default: /dev/ttyUSB0 +Description: The serial port where EZMESH RCP is connected. + (default: /dev/ttyUSB0) diff --git a/module/cpc/cpcd-system/debconf/services/cpc-mgmt.service.in b/integrate/debian/controller/ez-mgmt.service.in similarity index 64% rename from module/cpc/cpcd-system/debconf/services/cpc-mgmt.service.in rename to integrate/debian/controller/ez-mgmt.service.in index 9a2dbb1..4619cf3 100644 --- a/module/cpc/cpcd-system/debconf/services/cpc-mgmt.service.in +++ b/integrate/debian/controller/ez-mgmt.service.in @@ -1,14 +1,12 @@ [Unit] -Description=CPC Mgmt Daemon (ver @PROJECT_VER@) +Description=EZMESH Management Daemon (ver @PROJECT_VER@) After=bluetooth.service otbr-agent.service dbus.service network.target systemd-timesyncd.service hciuart.service serial-getty.service [Service] Type=oneshot RemainAfterExit=yes -ExecStart=${CMAKE_INSTALL_PREFIX}/src/scripts/cpc-mgmt +ExecStart=${CMAKE_INSTALL_PREFIX}/src/scripts/ez-mgmt ExecReload=/bin/kill -HUP $MAINPID -# Restart=on-failure -# RestartSec=5s [Install] WantedBy=multi-user.target diff --git a/integrate/debian/controller/ezmeshd.service.in b/integrate/debian/controller/ezmeshd.service.in new file mode 100644 index 0000000..010dd3f --- /dev/null +++ b/integrate/debian/controller/ezmeshd.service.in @@ -0,0 +1,12 @@ +[Unit] +Description=EZMESH Agent Service (ver @PROJECT_VER@) + +[Service] +ExecStart=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/ezmeshd -c ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/ez_config.ini +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +KillMode=process +LimitMEMLOCK=infinity + +[Install] +WantedBy=multi-user.target diff --git a/integrate/debian/controller/scripts/ez-mgmt-all.in b/integrate/debian/controller/scripts/ez-mgmt-all.in new file mode 100755 index 0000000..be9fc7c --- /dev/null +++ b/integrate/debian/controller/scripts/ez-mgmt-all.in @@ -0,0 +1,37 @@ +#!/bin/bash + +die() +{ + echo >&2 " *** ERROR: $*" + exit 1 +} + +have() +{ + command -v "$1" >/dev/null 2>/dev/null +} + +main() +{ + echo >&2 "****************************\nEZMESH version: @PROJECT_VER@\n****************************" + sudo sysctl --system + if have systemctl; then + systemctl is-active ez-bluetooth && sudo systemctl stop ez-bluetooth + systemctl is-active ez-otbr && sudo systemctl stop ez-otbr + systemctl is-active ezmeshd && sudo systemctl stop ezmeshd + systemctl is-active ezmeshd || sudo systemctl start ezmeshd || die 'Failed to start ezmeshd!' + systemctl is-active ez-otbr || sudo systemctl start ez-otbr || die 'Failed to start ez-otbr!' + systemctl is-active ez-bluetooth || sudo systemctl start ez-bluetooth || die 'Failed to start ez-bluetooth' + elif have service; then + sudo service ez-bluetooth status && ( sudo service ez-bluetooth stop || die 'Failed to stop ez-bluetooth' ) + sudo service ez-otbr status && ( sudo service ez-otbr stop || die 'Failed to stop otbr!' ) + sudo service ezmeshd status && ( sudo service ezmeshd stop || die 'Failed to stop ezmeshd!' ) + sudo service ezmeshd status || sudo service ezmeshd start || die 'Failed to start ezmeshd!' + sudo service ez-otbr status || sudo service ez-otbr start || die 'Failed to start ez-otbr!' + sudo service ez-bluetooth status || sudo service ez-bluetooth start || die 'Failed to start ez-bluetooth' + else + die 'Unable to find service manager. Try script/console to start in console mode!' + fi +} + +main diff --git a/integrate/debian/controller/scripts/ez-mgmt-br.in b/integrate/debian/controller/scripts/ez-mgmt-br.in new file mode 100755 index 0000000..6343006 --- /dev/null +++ b/integrate/debian/controller/scripts/ez-mgmt-br.in @@ -0,0 +1,33 @@ +#!/bin/bash + +die() +{ + echo >&2 " *** ERROR: $*" + exit 1 +} + +have() +{ + command -v "$1" >/dev/null 2>/dev/null +} + +main() +{ + echo >&2 "****************************\nEZMESH version: @PROJECT_VER@\n****************************" + sudo sysctl --system + if have systemctl; then + systemctl is-active ez-otbr && sudo systemctl stop ez-otbr + systemctl is-active ezmeshd && sudo systemctl stop ezmeshd + systemctl is-active ezmeshd || sudo systemctl start ezmeshd || die 'Failed to start ezmeshd!' + systemctl is-active ez-otbr || sudo systemctl start ez-otbr || die 'Failed to start ez-otbr!' + elif have service; then + sudo service ez-otbr status && ( sudo service ez-otbr stop || die 'Failed to stop otbr!' ) + sudo service ezmeshd status && ( sudo service ezmeshd stop || die 'Failed to stop ezmeshd!' ) + sudo service ezmeshd status || sudo service ezmeshd start || die 'Failed to start ezmeshd!' + sudo service ez-otbr status || sudo service ez-otbr start || die 'Failed to start ez-otbr!' + else + die 'Unable to find service manager. Try script/console to start in console mode!' + fi +} + +main diff --git a/integrate/debian/controller/scripts/ez-mgmt-bt.in b/integrate/debian/controller/scripts/ez-mgmt-bt.in new file mode 100755 index 0000000..c117584 --- /dev/null +++ b/integrate/debian/controller/scripts/ez-mgmt-bt.in @@ -0,0 +1,33 @@ +#!/bin/bash + +die() +{ + echo >&2 " *** ERROR: $*" + exit 1 +} + +have() +{ + command -v "$1" >/dev/null 2>/dev/null +} + +main() +{ + echo >&2 "****************************\nEZMESH version: @PROJECT_VER@\n****************************" + sudo sysctl --system + if have systemctl; then + systemctl is-active ez-bluetooth && sudo systemctl stop ez-bluetooth + systemctl is-active ezmeshd && sudo systemctl stop ezmeshd + systemctl is-active ezmeshd || sudo systemctl start ezmeshd || die 'Failed to start ezmeshd!' + systemctl is-active ez-bluetooth || sudo systemctl start ez-bluetooth || die 'Failed to start ez-bluetooth' + elif have service; then + sudo service ez-bluetooth status && ( sudo service ez-bluetooth stop || die 'Failed to stop ez-bluetooth' ) + sudo service ezmeshd status && ( sudo service ezmeshd stop || die 'Failed to stop ezmeshd!' ) + sudo service ezmeshd status || sudo service ezmeshd start || die 'Failed to start ezmeshd!' + sudo service ez-bluetooth status || sudo service ez-bluetooth start || die 'Failed to start ez-bluetooth' + else + die 'Unable to find service manager. Try script/console to start in console mode!' + fi +} + +main diff --git a/integrate/debian/controller/scripts/ez-mgmt.in b/integrate/debian/controller/scripts/ez-mgmt.in new file mode 100755 index 0000000..be9fc7c --- /dev/null +++ b/integrate/debian/controller/scripts/ez-mgmt.in @@ -0,0 +1,37 @@ +#!/bin/bash + +die() +{ + echo >&2 " *** ERROR: $*" + exit 1 +} + +have() +{ + command -v "$1" >/dev/null 2>/dev/null +} + +main() +{ + echo >&2 "****************************\nEZMESH version: @PROJECT_VER@\n****************************" + sudo sysctl --system + if have systemctl; then + systemctl is-active ez-bluetooth && sudo systemctl stop ez-bluetooth + systemctl is-active ez-otbr && sudo systemctl stop ez-otbr + systemctl is-active ezmeshd && sudo systemctl stop ezmeshd + systemctl is-active ezmeshd || sudo systemctl start ezmeshd || die 'Failed to start ezmeshd!' + systemctl is-active ez-otbr || sudo systemctl start ez-otbr || die 'Failed to start ez-otbr!' + systemctl is-active ez-bluetooth || sudo systemctl start ez-bluetooth || die 'Failed to start ez-bluetooth' + elif have service; then + sudo service ez-bluetooth status && ( sudo service ez-bluetooth stop || die 'Failed to stop ez-bluetooth' ) + sudo service ez-otbr status && ( sudo service ez-otbr stop || die 'Failed to stop otbr!' ) + sudo service ezmeshd status && ( sudo service ezmeshd stop || die 'Failed to stop ezmeshd!' ) + sudo service ezmeshd status || sudo service ezmeshd start || die 'Failed to start ezmeshd!' + sudo service ez-otbr status || sudo service ez-otbr start || die 'Failed to start ez-otbr!' + sudo service ez-bluetooth status || sudo service ez-bluetooth start || die 'Failed to start ez-bluetooth' + else + die 'Unable to find service manager. Try script/console to start in console mode!' + fi +} + +main diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index 77956da..6ac6248 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -1,4 +1,5 @@ -ext_add_subdirectory_ifdef(CONFIG_CPC cpc) +ext_add_subdirectory_ifdef(CONFIG_CONTROLLER controller) +ext_add_subdirectory_ifdef(CONFIG_UPGRADE upgrade) ext_add_subdirectory_ifdef(CONFIG_BLUETOOTH bluetooth) ext_add_subdirectory_ifdef(CONFIG_BORDER_ROUTER border_router) ext_add_subdirectory_ifdef(CONFIG_ZIGBEE_GW_SERVICE zigbee) diff --git a/module/bluetooth/CMakeLists.txt b/module/bluetooth/CMakeLists.txt index d317b1a..2c12e6c 100644 --- a/module/bluetooth/CMakeLists.txt +++ b/module/bluetooth/CMakeLists.txt @@ -1 +1,23 @@ -ext_add_subdirectory(cpc-bluetooth) \ No newline at end of file +add_executable(ez-bluetooth ezmesh-bluetooth.c) +target_link_libraries(ez-bluetooth ezmesh util pthread) + +get_target_property(EZMESH_SOURCE_DIR ezmesh SOURCE_DIR) +target_include_directories(ez-bluetooth PRIVATE ${EZMESH_SOURCE_DIR}/library) + +ext_install("TARGET_RUNTIME" ez-bluetooth "bin" ez-bluetooth) + + +if(${CONFIG_GEN_SYSTEM}) + set(DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH /var/lib/ezmesh-bluetooth) + set(DEFAULT_EZMESHD_SERVICE_PATH /lib/systemd/system) + if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH} COMPONENT ezmesh-bluetooth) + set(EZMESH_BLUETOOTH_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH}) + else() + install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH} COMPONENT ezmesh-bluetooth) + set(EZMESH_BLUETOOTH_SERVICE_PATH ${DEFAULT_EZMESH_BLUETOOTH_INSTALL_PATH}) + endif() + + ext_install("EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/ez-bluetooth ${EZMESH_BLUETOOTH_SERVICE_PATH} ez-bluetooth) +endif() + diff --git a/module/bluetooth/cpc-bluetooth/CMakeLists.txt b/module/bluetooth/cpc-bluetooth/CMakeLists.txt deleted file mode 100644 index b6f94c2..0000000 --- a/module/bluetooth/cpc-bluetooth/CMakeLists.txt +++ /dev/null @@ -1,93 +0,0 @@ -add_executable(cpc-bluetooth src/cpc-bluetooth.c) -target_link_libraries(cpc-bluetooth - cpc - util - pthread -) - -get_target_property(CPC_SOURCE_DIR cpc SOURCE_DIR) -target_include_directories(cpc-bluetooth PRIVATE ${CPC_SOURCE_DIR}/lib) - -ext_install( "TARGET_RUNTIME" cpc-bluetooth "bin" cpc-bluetooth) - -set(DEFAULT_CPC_BLUETOOTH_INSTALL_PATH /var/lib/cpc-bluetooth) -set(DEFAULT_CPCD_SERVICE_PATH /lib/systemd/system) -if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_BLUETOOTH_INSTALL_PATH} COMPONENT cpc-bluetooth) - set(CPCD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_BLUETOOTH_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_BLUETOOTH_INSTALL_PATH}) -else() - install(DIRECTORY DESTINATION ${DEFAULT_CPC_BLUETOOTH_INSTALL_PATH} COMPONENT cpc-bluetooth) - set(CPCD_SERVICE_PATH ${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_BLUETOOTH_SERVICE_PATH ${DEFAULT_CPC_BLUETOOTH_INSTALL_PATH}) -endif() - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/postinst.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/postinst) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/prerm.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/prerm) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/cpc-bluetooth.service.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-bluetooth.service) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/startpost.in - ${CMAKE_CURRENT_BINARY_DIR}/scripts/startpost) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/stop.in - ${CMAKE_CURRENT_BINARY_DIR}/scripts/stop) - -ext_install( - "FILE" - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-bluetooth.service - ${CPCD_SERVICE_PATH} - cpc-bluetooth) - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/cpc-bluetooth - ${CPC_BLUETOOTH_SERVICE_PATH} - cpc-bluetooth -) - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/scripts/startpost - ${CPC_BLUETOOTH_SERVICE_PATH} - startpost -) - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/scripts/stop - ${CPC_BLUETOOTH_SERVICE_PATH} - stop -) - -if(CPCD_LOCATION) - # Install configuration file - ext_install( - "FILE" ${CPCD_LOCATION}/etc/cpcd.conf - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} - cpcd) -else() - # Install binaries they come from custom target build_cpcd - ext_install( - "TARGET_HEADER" cpc - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} - cpc-bluetooth - ) - - ext_install( - "TARGET_HEADER" cpc - ${CPC_BLUETOOTH_SERVICE_PATH} - startpost - ) - - ext_install( - "TARGET_HEADER" cpc - ${CPC_BLUETOOTH_SERVICE_PATH} - stop - ) - - ext_install( - "FILE" ${cpcd_SOURCE_DIR}/cpcd.conf - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} - cpcd) -endif() \ No newline at end of file diff --git a/module/bluetooth/cpc-bluetooth/debconf/services/cpc-bluetooth.service.in b/module/bluetooth/cpc-bluetooth/debconf/services/cpc-bluetooth.service.in deleted file mode 100644 index e2f7ee4..0000000 --- a/module/bluetooth/cpc-bluetooth/debconf/services/cpc-bluetooth.service.in +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=CPC HCI Bridge service (ver @PROJECT_VER@) - - -[Service] -WorkingDirectory=/var/lib/rafael/dev -ExecStartPre=${CPC_BLUETOOTH_SERVICE_PATH}/stop -ExecStart=${CPC_BLUETOOTH_SERVICE_PATH}/cpc-bluetooth -ExecStartPost=${CPC_BLUETOOTH_SERVICE_PATH}/startpost -ExecStopPost=${CPC_BLUETOOTH_SERVICE_PATH}/stop -# Restart=on-failure -KillMode=process -LimitMEMLOCK=infinity - -[Install] -WantedBy=multi-user.target diff --git a/module/bluetooth/cpc-bluetooth/src/cpc-bluetooth.c b/module/bluetooth/ezmesh-bluetooth.c similarity index 62% rename from module/bluetooth/cpc-bluetooth/src/cpc-bluetooth.c rename to module/bluetooth/ezmesh-bluetooth.c index efd9ed8..63a4ccd 100644 --- a/module/bluetooth/cpc-bluetooth/src/cpc-bluetooth.c +++ b/module/bluetooth/ezmesh-bluetooth.c @@ -1,4 +1,4 @@ -#include "libcpc.h" +#include "libezmesh.h" #include #include #include @@ -9,26 +9,26 @@ #include #include -#define LOG_TAG "cpc-bluetooth" +#define LOG_TAG "ezmesh-bluetooth" -#define TO_CPC_BUF_SIZE 400 -#define FROM_CPC_BUF_SIZE LIB_CPC_READ_MINIMUM_SIZE +#define TO_EZMESH_BUF_SIZE 400 +#define FROM_EZMESH_BUF_SIZE LIB_EZMESH_READ_MINIMUM_SIZE #define INST_NAME_LEN 100 -#define RETRY_COUNT 10 -#define CPC_RETRY_SLEEP_NS 100000000L -#define CPC_RESET_SLEEP_NS 10000L +#define RETRY_COUNT 1 +#define EZMESH_RETRY_SLEEP_NS 100000000L +#define EZMESH_RESET_SLEEP_NS 10000L #define THREAD_SLEEP_NS 1000000L -#define CPC_TRANSMIT_WINDOW 1 +#define EZMESH_TRANSMIT_WINDOW 1 #define SYMLINK_PATH "pts_hci" -// cpc related structures -static cpc_handle_t lib_handle; -static cpc_ep_t endpoint; +// ezmesh related structures +static ezmesh_handle_t lib_handle; +static ezmesh_ep_t endpoint; // tx/rx buffers -static uint8_t data_to_cpc[TO_CPC_BUF_SIZE]; -static uint8_t data_from_cpc[FROM_CPC_BUF_SIZE]; -// cpc instance name -static char cpc_instance[INST_NAME_LEN]; +static uint8_t data_to_ezmesh[TO_EZMESH_BUF_SIZE]; +static uint8_t data_from_ezmesh[FROM_EZMESH_BUF_SIZE]; +// ezmesh instance name +static char ezmesh_instance[INST_NAME_LEN]; static int pty_m; static int pty_s; @@ -45,8 +45,8 @@ static pthread_t thread_rx; static pthread_t thread_tx; // Static receive function -static void *cpc_to_pty_func(void *ptr); -static void *pty_to_cpc_func(void *ptr); +static void *ezmesh_to_pty_func(void *ptr); +static void *pty_to_ezmesh_func(void *ptr); // Custom signal handler. static void signal_handler(int sig) @@ -56,40 +56,41 @@ static void signal_handler(int sig) } /**************************************************************************//** - * Starts CPC and pty. + * Starts EZMESH and pty. *****************************************************************************/ uint32_t startup(void) { int ret; uint8_t retry = 0; + ezmesh_handle_inst_t *p_ezmesh_inst; - // Initialize CPC communication + // Initialize EZMESH communication do { - ret = libcpc_init(&lib_handle, cpc_instance, reset_cb); + printf("Try open socket, retry_count %d\n", retry); + ret = libezmesh_init(&lib_handle, ezmesh_instance, reset_cb); if (ret == 0) { + p_ezmesh_inst = lib_handle.ptr; + printf("Agent app v%s\r\n", p_ezmesh_inst->agent_app_version); // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); if (ret < 0) { - perror("cpc_init: "); + perror("ezmesh_init: "); return ret; } // Start Bluetooth endpoint - ret = libcpc_open_ep(lib_handle, - &endpoint, - CPC_EP_BT_RCP, - CPC_TRANSMIT_WINDOW); + ret = libezmesh_open_ep(lib_handle, &endpoint, EP_BT_RCP, EZMESH_TRANSMIT_WINDOW); if (ret < 0) { - perror("cpc_open_ep "); + perror("ezmesh_open_ep "); return ret; } printf("Endpoint opened\n"); @@ -127,9 +128,9 @@ static void reset_cb(void) } /**************************************************************************//** - * Reset CPC communication after other end restarted. + * Reset EZMESH communication after other end restarted. *****************************************************************************/ -int reset_cpc(void) +int reset_ezmesh(void) { int ret; uint8_t retry = 0; @@ -139,28 +140,28 @@ int reset_cpc(void) // Restart cpp communication do { - ret = libcpc_reset(&lib_handle); + ret = libezmesh_reset(&lib_handle); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); has_reset = false; if (ret < 0) { - perror("cpc restart "); + perror("ezmesh restart "); return ret; } // Open Bluetooth endpoint - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_BT_RCP, - CPC_TRANSMIT_WINDOW); + EP_BT_RCP, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { perror(" open endpoint "); @@ -182,56 +183,51 @@ int main(int argc, char *argv[]) signal(SIGTERM, signal_handler); // Set device unique name if different from default - if (argc > 1) - { - strcpy(cpc_instance, argv[1]); - } else - { - strcpy(cpc_instance, "cpcd_0"); - } + strcpy(ezmesh_instance, (argc > 1)? argv[1] : "ezmeshd_0"); - // Start CPC and PTY communication + // Start EZMESH and PTY communication if (startup() < 0) { + printf("start failed\n"); exit(EXIT_FAILURE); } // Creating receiving working threads - ret = pthread_create(&thread_rx, NULL, cpc_to_pty_func, NULL); + ret = pthread_create(&thread_rx, NULL, ezmesh_to_pty_func, NULL); if (ret) { - // sl_log_error(LOG_TAG,"Error - pthread_create(thread_rx) return code: %d", ret); + printf("Error - pthread_create(thread_rx) return code: %d\n", ret); exit(EXIT_FAILURE); } - ret = pthread_create(&thread_tx, NULL, pty_to_cpc_func, NULL); + ret = pthread_create(&thread_tx, NULL, pty_to_ezmesh_func, NULL); if (ret) { - // sl_log_error(LOG_TAG,"Error - pthread_create(thread_tx) return code: %d", ret); + printf("Error - pthread_create(thread_tx) return code: %d\n", ret); exit(EXIT_FAILURE); } - // sl_log_debug(LOG_TAG,"CPC - VHCI bridge working, main thread is going to sleep"); + printf("EZMESH - VHCI bridge working, main thread is going to sleep\n"); - // Reset cpc communication if daemon signals + // Reset ezmesh communication if daemon signals while (run) { if (has_reset) { - ret = reset_cpc(); + ret = reset_ezmesh(); if (ret < 0) { perror("reset "); exit(EXIT_FAILURE); } } - nanosleep((const struct timespec[]){{ 0, CPC_RESET_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RESET_SLEEP_NS } }, NULL); } } /**************************************************************************//** - * Working thread from CPCd + * Working thread from EZMESHd *****************************************************************************/ -void *cpc_to_pty_func(void *ptr) +void *ezmesh_to_pty_func(void *ptr) { ssize_t size = 0; @@ -240,14 +236,14 @@ void *cpc_to_pty_func(void *ptr) while (run) { - // Read data from cpc - size = libcpc_read_ep(endpoint, - &data_from_cpc[0], - FROM_CPC_BUF_SIZE, - CPC_EP_READ_FLAG_NON_BLOCKING); + // Read data from ezmesh + size = libezmesh_read_ep(endpoint, + &data_from_ezmesh[0], + FROM_EZMESH_BUF_SIZE, + EP_READ_FLAG_NON_BLOCKING); if (size > 0) { - if (write(pty_m, &data_from_cpc[0], size) == -1) + if (write(pty_m, &data_from_ezmesh[0], size) == -1) { perror("write error "); } @@ -264,17 +260,17 @@ void *cpc_to_pty_func(void *ptr) printf("\n"); } - printf(" %02X", data_from_cpc[i]); + printf(" %02X", data_from_ezmesh[i]); } printf("\n\n"); - memset(&data_from_cpc[0], 0, FROM_CPC_BUF_SIZE); + memset(&data_from_ezmesh[0], 0, FROM_EZMESH_BUF_SIZE); } else if (has_reset) { // intentionally left blank } else if (errno != EAGAIN && errno != ECONNRESET) { - perror("cpc_to_pty_func error "); + perror("ezmesh_to_pty_func error "); exit(-1); } nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); @@ -283,9 +279,9 @@ void *cpc_to_pty_func(void *ptr) } /**************************************************************************//** - * Working thread to CPCd + * Working thread to EZMESHd *****************************************************************************/ -void *pty_to_cpc_func(void *ptr) +void *pty_to_ezmesh_func(void *ptr) { ssize_t size = 0; unsigned int d_len = 0; @@ -296,15 +292,15 @@ void *pty_to_cpc_func(void *ptr) while (run) { // Read data from pty - size = read(pty_m, data_to_cpc, TO_CPC_BUF_SIZE); + size = read(pty_m, data_to_ezmesh, TO_EZMESH_BUF_SIZE); if (size > 0) { - if (data_to_cpc[0] == 0x02) + if (data_to_ezmesh[0] == 0x02) { - d_len = (data_to_cpc[3] | (data_to_cpc[4] << 8)) + 5; + d_len = (data_to_ezmesh[3] | (data_to_ezmesh[4] << 8)) + 5; } else { - d_len = data_to_cpc[3] + 4; + d_len = data_to_ezmesh[3] + 4; } printf("w-> %d\n", d_len); for (int i = 0; i < d_len; i++) @@ -317,19 +313,19 @@ void *pty_to_cpc_func(void *ptr) printf("\n"); } - printf(" %02X", data_to_cpc[i]); + printf(" %02X", data_to_ezmesh[i]); } printf("\n\n"); - libcpc_write_ep(endpoint, &data_to_cpc[0], d_len, 0); + libezmesh_write_ep(endpoint, &data_to_ezmesh[0], d_len, 0); if (size > d_len) - libcpc_write_ep(endpoint, &data_to_cpc[d_len], size - d_len, 0); - memset(&data_to_cpc[0], 0, TO_CPC_BUF_SIZE); + libezmesh_write_ep(endpoint, &data_to_ezmesh[d_len], size - d_len, 0); + memset(&data_to_ezmesh[0], 0, TO_EZMESH_BUF_SIZE); } else if (has_reset) { // intentionally left blank } else if (errno != EAGAIN && errno != ECONNRESET) { - perror("pty_to_cpc_func error"); + perror("pty_to_ezmesh_func error"); exit(-1); } nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); diff --git a/module/border_router/CMakeLists.txt b/module/border_router/CMakeLists.txt index ee0735c..e43dff1 100644 --- a/module/border_router/CMakeLists.txt +++ b/module/border_router/CMakeLists.txt @@ -1 +1,47 @@ -ext_add_subdirectory(cpc-otbr) \ No newline at end of file +include(FetchContent) + +set(FETCHCONTENT_QUIET False) +set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME ez-otbr) + +# ot-br-posix unfortunately has a variable set but not used, making our compiler fail because of warnings as errors. +add_compile_options(-Wno-unused-but-set-variable) +FetchContent_Declare(ot-br-posix URL ${CMAKE_CURRENT_SOURCE_DIR}/ot-br-posix SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/ot-br-posix") +FetchContent_GetProperties(ot-br-posix) +FetchContent_Populate(ot-br-posix) + +FetchContent_Declare(openthread URL ${CMAKE_CURRENT_SOURCE_DIR}/openthread SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/openthread") +FetchContent_Populate(openthread) + +# Install compile-time configuration constants header file +file(GLOB POSIX_CONFIG_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/openthread-core-rafael-posix-config.h") +file(COPY ${POSIX_CONFIG_HEADERS} DESTINATION ${openthread_SOURCE_DIR}/src/posix/platform) +file(COPY ${POSIX_CONFIG_HEADERS} DESTINATION ${ot-br-posix_SOURCE_DIR}/third_party/openthread/repo/src/posix/platform) + +# Compilation settings defined +set(OT_CONFIG openthread-core-rafael-posix-config.h CACHE STRING "Project-specific openthread config file") +set(OT_MULTIPAN_RCP ON CACHE BOOL "enable multi-PAN RCP") +set(OT_POSIX_CONFIG_RCP_BUS "EZMESH" CACHE STRING "RCP bus type") +set(OT_DIAGNOSTIC ON CACHE BOOL "enable diagnostic support") +set(OT_PACKAGE_NAME "OPENTHREAD" CACHE STRING "OpenThread Package Name") +set(OT_FULL_LOGS OFF CACHE BOOL "Enable debug level logging" FORCE) + + +if(NOT BUILD_TESTING) + set(ENABLE_CJSON_TEST OFF CACHE BOOL "ENABLE CJSON tests") + set(ENABLE_TESTING OFF CACHE BOOL "Build mbed TLS tests.") +endif() + +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/options.cmake") + +add_subdirectory(${ot-br-posix_SOURCE_DIR} ${ot-br-posix_BINARY_DIR}) + +# Remove otbr compilation for target setup +# Update otbr-agent config with spinel url +execute_process( + COMMAND sed -i "/otbr/d" ${ot-br-posix_SOURCE_DIR}/script/setup + COMMAND sed -i "s/set -euxo pipefail/set -euo pipefail/g" ${ot-br-posix_SOURCE_DIR}/script/_initrc + COMMAND sed -i "s|spinel.* |${OTBR_RADIO_URL} |" ${ot-br-posix_BINARY_DIR}/src/agent/otbr-agent.default + COMMAND_ERROR_IS_FATAL ANY +) + +ext_install("DIRECTORY" ${ot-br-posix_SOURCE_DIR}/script share/otbr ez-otbr) \ No newline at end of file diff --git a/module/border_router/cmake/options.cmake b/module/border_router/cmake/options.cmake new file mode 100644 index 0000000..170b07a --- /dev/null +++ b/module/border_router/cmake/options.cmake @@ -0,0 +1,75 @@ +# Options used to configure the otbr bootstrap and setup scripts +option(EZMESH_OTBR_BORDER_ROUTING "enable border routing features" 1) +option(EZMESH_OTBR_BACKBONE_ROUTER "enable backbone routing features" 1) +option(EZMESH_OTBR_REFERENCE_DEVICE "enable openthread reference device feature-set" 0) +option(EZMESH_OTBR_RELEASE "remove dependency on testing utilities" 1) # Unused - no runtime dependencies +option(EZMESH_OTBR_NAT64 "include nat64 service" 0) +option(EZMESH_OTBR_DNS64 "include dns64 service" 0) +option(EZMESH_OTBR_DHCPV6_PD "include dhcp service" 0) +option(EZMESH_OTBR_NETWORK_MANAGER "include network manager service" 0) + +# Set OTBR runtime and service options +set(OTBR_SYSTEMD_UNIT_DIR "/lib/systemd/system" CACHE STRING "Destination path for otbr systemd service files") +set(OTBR_INFRA_IF_NAME "eth0" CACHE STRING "The infrastructure interface name") +set(OTBR_RADIO_URL "spinel+ezmesh://ezmeshd_0?iid=2" CACHE STRING "URL") +set(OTBR_MDNS "avahi" CACHE STRING "mDNS publisher provider") +set(OTBR_NAT64_SERVICE "openthread" CACHE STRING "nat64 service name") + +# Packages installed in bootstrap when above options are enabled +set(EZMESH_OTBR_RECS "rsyslog, libavahi-client3, avahi-daemon, libjsoncpp-dev") +set(NAT64_RECS "iptables") +set(DNS64_RECS "bind9, resolvconf") +set(NETWORK_MANAGER_RECS "dnsmasq, network-manager") +set(DHCPV6_PD_RECS "dhcpcd5") +set(REFERENCE_DEVICE_RECS "radvd, dnsutils") +set(BACKBONE_ROUTER_RECS "libnetfilter-queue1") + +# Including options to enable and packages to recommend +# based off of selected options +if(EZMESH_OTBR_NAT64) + string(COMPARE EQUAL ${OTBR_NAT64_SERVICE} "tayga" TAYGA_NAT64_SERVICE) + if(TAYGA_NAT64_SERVICE) + string(APPEND NAT64_RECS ", ${OTBR_NAT64_SERVICE}") + endif(TAYGA_NAT64_SERVICE) + string(APPEND EZMESH_OTBR_RECS ", ${NAT64_RECS}") +endif(EZMESH_OTBR_NAT64) + +if(EZMESH_OTBR_DNS64) + string(APPEND EZMESH_OTBR_RECS ", ${DNS64_RECS}") +endif(EZMESH_OTBR_DNS64) + +if(EZMESH_OTBR_NETWORK_MANAGER) + string(APPEND EZMESH_OTBR_RECS ", ${NETWORK_MANAGER_RECS}") +endif(EZMESH_OTBR_NETWORK_MANAGER) + +if(EZMESH_OTBR_DHCPV6_PD) + string(APPEND EZMESH_OTBR_RECS ", ${DHCPV6_PD_RECS}") +endif(EZMESH_OTBR_DHCPV6_PD) + +if(EZMESH_OTBR_REFERENCE_DEVICE) + string(APPEND EZMESH_OTBR_RECS ", ${REFERENCE_DEVICE_RECS}") + set(OTBR_NO_AUTO_ATTACH 1 CACHE BOOL "disable auto Thread attach") + set(OT_REFERENCE_DEVICE ON CACHE BOOL "enable openthread reference device feature-set") + set(OT_DHCP6_CLIENT ON CACHE BOOL "enable DHCP6 client support") + set(OT_DHCP6_SERVER ON CACHE BOOL "enable DHCP6 server support") +endif(EZMESH_OTBR_REFERENCE_DEVICE) + +if(EZMESH_OTBR_BACKBONE_ROUTER) + string(APPEND EZMESH_OTBR_RECS ", ${BACKBONE_ROUTER_RECS}") + set(OTBR_BACKBONE_ROUTER ON CACHE BOOL "enable backbone router features") + if(EZMESH_OTBR_REFERENCE_DEVICE) + set(OTBR_DUA_ROUTING ON CACHE BOOL "enable backbone router DUA routing") + endif(EZMESH_OTBR_REFERENCE_DEVICE) +endif(EZMESH_OTBR_BACKBONE_ROUTER) + +if(EZMESH_OTBR_BORDER_ROUTING) + set(OTBR_BORDER_ROUTING ON CACHE BOOL "enable border routing features") +endif(EZMESH_OTBR_BORDER_ROUTING) + +# Setting additional default options +option(OTBR_DBUS "enable DBUS support" ON) +option(OTBR_DNSSD_DISCOVERY_PROXY "enable dns-sd discovery proxy support" ON) +option(OTBR_SRP_ADVERTISING_PROXY "enable advertising proxy" ON) + +# Adding selected packages to debian recommends control field +set(CPACK_DEBIAN_UIC-OTBR_PACKAGE_RECOMMENDS ${EZMESH_OTBR_RECS} CACHE STRING "Package recommendations for ez-otbr: ${EZMESH_OTBR_RECS}" FORCE) diff --git a/module/border_router/cpc-otbr/CMakeLists.txt b/module/border_router/cpc-otbr/CMakeLists.txt deleted file mode 100644 index 04e95ba..0000000 --- a/module/border_router/cpc-otbr/CMakeLists.txt +++ /dev/null @@ -1,122 +0,0 @@ -include(FetchContent) - -set(FETCHCONTENT_QUIET False) -set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME cpc-otbr) - -# ot-br-posix unfortunately has a variable set but not used, making our compiler fail because of warnings as errors. -add_compile_options(-Wno-unused-but-set-variable) - -FetchContent_Declare( - ot-br-posix - URL ${CMAKE_CURRENT_SOURCE_DIR}/third_party/ot-br-posix - SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/ot-br-posix" -) -FetchContent_GetProperties(ot-br-posix) -FetchContent_Populate(ot-br-posix) - -FetchContent_Declare( - openthread - URL ${CMAKE_CURRENT_SOURCE_DIR}/third_party/openthread - SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/openthread" -) - -FetchContent_Populate(openthread) - - -# Install compile-time configuration constants header file -file(GLOB POSIX_CONFIG_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/openthread-core-rafael-posix-config.h") -file(COPY ${POSIX_CONFIG_HEADERS} DESTINATION ${openthread_SOURCE_DIR}/src/posix/platform) -file(COPY ${POSIX_CONFIG_HEADERS} DESTINATION ${ot-br-posix_SOURCE_DIR}/third_party/openthread/repo/src/posix/platform) - - -# Compilation settings defined -set(OT_CONFIG openthread-core-rafael-posix-config.h CACHE STRING "Project-specific openthread config file") -set(OT_MULTIPAN_RCP ON CACHE BOOL "enable multi-PAN RCP") -set(OT_POSIX_CONFIG_RCP_BUS "CPC" CACHE STRING "RCP bus type") -set(OT_DIAGNOSTIC ON CACHE BOOL "enable diagnostic support") -set(OT_PACKAGE_NAME "OPENTHREAD" CACHE STRING "OpenThread Package Name") -set(OT_FULL_LOGS OFF CACHE BOOL "Enable debug level logging" FORCE) - - -if(NOT BUILD_TESTING) - set(ENABLE_CJSON_TEST OFF CACHE BOOL "ENABLE CJSON tests") - set(ENABLE_TESTING OFF CACHE BOOL "Build mbed TLS tests.") -endif() - -include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/options.cmake") - -add_subdirectory(${ot-br-posix_SOURCE_DIR} ${ot-br-posix_BINARY_DIR}) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/prerm.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/prerm.in) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/postinst.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/postinst.in) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/cpc-otbr.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-otbr.in) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/postrm.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/postrm) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/cpc-otbr.service.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-otbr.service) - -# Second stage scriptlet configuration - evaluate generator expressions -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/debconf/prerm - INPUT ${CMAKE_CURRENT_BINARY_DIR}/debconf/prerm.in) - -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/debconf/postinst - INPUT ${CMAKE_CURRENT_BINARY_DIR}/debconf/postinst.in) - -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-otbr - INPUT ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-otbr.in) - -# Remove otbr compilation for target setup -# Update otbr-agent config with spinel url -execute_process( - COMMAND sed -i "/otbr/d" ${ot-br-posix_SOURCE_DIR}/script/setup - COMMAND sed -i "s/set -euxo pipefail/set -euo pipefail/g" ${ot-br-posix_SOURCE_DIR}/script/_initrc - COMMAND sed -i "s|spinel.* |${OTBR_RADIO_URL} |" ${ot-br-posix_BINARY_DIR}/src/agent/otbr-agent.default - COMMAND_ERROR_IS_FATAL ANY -) - -ext_install( - "DIRECTORY" - ${ot-br-posix_SOURCE_DIR}/script - share/otbr - cpc-otbr -) - -ext_install( - "DIRECTORY" - ${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/otbr-agent.service.d - /etc/systemd/system - cpc-otbr -) - -ext_install( - "DIRECTORY" - ${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/otbr-nat44.service.d - /etc/systemd/system - cpc-otbr -) - -ext_install( - "DIRECTORY" - ${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/otbr-firewall.service.d - /etc/systemd/system - cpc-otbr -) - -ext_install( - "FILE" - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-otbr.service - ${OTBR_SYSTEMD_UNIT_DIR} - cpc-otbr -) - - -ext_install( - "FILE" - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-otbr - /etc/default - cpc-otbr -) diff --git a/module/border_router/cpc-otbr/cmake/options.cmake b/module/border_router/cpc-otbr/cmake/options.cmake deleted file mode 100644 index ddfe5a4..0000000 --- a/module/border_router/cpc-otbr/cmake/options.cmake +++ /dev/null @@ -1,90 +0,0 @@ -# Options used to configure the otbr bootstrap and setup scripts -option(CPC_OTBR_BORDER_ROUTING "enable border routing features" 1) -option(CPC_OTBR_BACKBONE_ROUTER "enable backbone routing features" 1) -option(CPC_OTBR_REFERENCE_DEVICE "enable openthread reference device feature-set" 0) -option(CPC_OTBR_RELEASE "remove dependency on testing utilities" 1) # Unused - no runtime dependencies -option(CPC_OTBR_NAT64 "include nat64 service" 0) -option(CPC_OTBR_DNS64 "include dns64 service" 0) -# option(CPC_OTBR_WEB_GUI "include web gui service" 0) -# option(CPC_OTBR_REST_API "include rest api support" 0) -option(CPC_OTBR_DHCPV6_PD "include dhcp service" 0) -option(CPC_OTBR_NETWORK_MANAGER "include network manager service" 0) - -# Set OTBR runtime and service options -set(OTBR_SYSTEMD_UNIT_DIR "/lib/systemd/system" CACHE STRING "Destination path for otbr systemd service files") -set(OTBR_INFRA_IF_NAME "eth0" CACHE STRING "The infrastructure interface name") -set(OTBR_RADIO_URL "spinel+cpc://cpcd_0?iid=2" CACHE STRING "URL") -set(OTBR_MDNS "avahi" CACHE STRING "mDNS publisher provider") -set(OTBR_NAT64_SERVICE "openthread" CACHE STRING "nat64 service name") - -# Packages installed in bootstrap when above options are enabled -set(CPC_OTBR_RECS "rsyslog, libavahi-client3, avahi-daemon, libjsoncpp-dev") -set(NAT64_RECS "iptables") -set(DNS64_RECS "bind9, resolvconf") -set(NETWORK_MANAGER_RECS "dnsmasq, network-manager") -set(DHCPV6_PD_RECS "dhcpcd5") -set(REFERENCE_DEVICE_RECS "radvd, dnsutils") -set(BACKBONE_ROUTER_RECS "libnetfilter-queue1") -# set(WEB_GUI_RECS "nodejs, npm") - -# Including options to enable and packages to recommend -# based off of selected options -if(CPC_OTBR_NAT64) - string(COMPARE EQUAL ${OTBR_NAT64_SERVICE} "tayga" TAYGA_NAT64_SERVICE) - - if(TAYGA_NAT64_SERVICE) - string(APPEND NAT64_RECS ", ${OTBR_NAT64_SERVICE}") - endif(TAYGA_NAT64_SERVICE) - - string(APPEND CPC_OTBR_RECS ", ${NAT64_RECS}") -endif(CPC_OTBR_NAT64) - -if(CPC_OTBR_DNS64) - string(APPEND CPC_OTBR_RECS ", ${DNS64_RECS}") -endif(CPC_OTBR_DNS64) - -if(CPC_OTBR_NETWORK_MANAGER) - string(APPEND CPC_OTBR_RECS ", ${NETWORK_MANAGER_RECS}") -endif(CPC_OTBR_NETWORK_MANAGER) - -if(CPC_OTBR_DHCPV6_PD) - string(APPEND CPC_OTBR_RECS ", ${DHCPV6_PD_RECS}") -endif(CPC_OTBR_DHCPV6_PD) - -if(CPC_OTBR_REFERENCE_DEVICE) - string(APPEND CPC_OTBR_RECS ", ${REFERENCE_DEVICE_RECS}") - set(OTBR_NO_AUTO_ATTACH 1 CACHE BOOL "disable auto Thread attach") - set(OT_REFERENCE_DEVICE ON CACHE BOOL "enable openthread reference device feature-set") - set(OT_DHCP6_CLIENT ON CACHE BOOL "enable DHCP6 client support") - set(OT_DHCP6_SERVER ON CACHE BOOL "enable DHCP6 server support") -endif(CPC_OTBR_REFERENCE_DEVICE) - -if(CPC_OTBR_BACKBONE_ROUTER) - string(APPEND CPC_OTBR_RECS ", ${BACKBONE_ROUTER_RECS}") - set(OTBR_BACKBONE_ROUTER ON CACHE BOOL "enable backbone router features") - if(CPC_OTBR_REFERENCE_DEVICE) - set(OTBR_DUA_ROUTING ON CACHE BOOL "enable backbone router DUA routing") - endif(CPC_OTBR_REFERENCE_DEVICE) -endif(CPC_OTBR_BACKBONE_ROUTER) - -if(CPC_OTBR_BORDER_ROUTING) - set(OTBR_BORDER_ROUTING ON CACHE BOOL "enable border routing features") -endif(CPC_OTBR_BORDER_ROUTING) - -# if(CPC_OTBR_WEB_GUI) -# string(APPEND CPC_OTBR_RECS ", ${WEB_GUI_RECS}") -# set(OTBR_WEB ON CACHE BOOL "enable web gui service") -# endif(CPC_OTBR_WEB_GUI) - -# if(CPC_OTBR_REST_API) -# set(OTBR_REST ON CACHE BOOL "enable rest api support") -# set(ENABLE_CJSON_TEST OFF CACHE BOOL "enable cJSON lib testing" FORCE) # External unity dependency creates cmake target name conflict -# endif(CPC_OTBR_REST_API) - -# Setting additional default options -option(OTBR_DBUS "enable DBUS support" ON) -option(OTBR_DNSSD_DISCOVERY_PROXY "enable dns-sd discovery proxy support" ON) -option(OTBR_SRP_ADVERTISING_PROXY "enable advertising proxy" ON) - -# Adding selected packages to debian recommends control field -set(CPACK_DEBIAN_UIC-OTBR_PACKAGE_RECOMMENDS ${CPC_OTBR_RECS} CACHE STRING "Package recommendations for cpc-otbr: ${CPC_OTBR_RECS}" FORCE) diff --git a/module/border_router/cpc-otbr/debconf/services/cpc-otbr.in b/module/border_router/cpc-otbr/debconf/services/cpc-otbr.in deleted file mode 100644 index 9fffb70..0000000 --- a/module/border_router/cpc-otbr/debconf/services/cpc-otbr.in +++ /dev/null @@ -1,17 +0,0 @@ -INFRA_IF_NAME=@OTBR_INFRA_IF_NAME@ -RADIO_URL=@OTBR_RADIO_URL@ - -OTBR_MDNS=@OTBR_MDNS@ -NAT64_SERVICE=@OTBR_NAT64_SERVICE@ - -RELEASE=$ -REFERENCE_DEVICE=$ - -BORDER_ROUTING=$ -BACKBONE_ROUTER=$ -NAT64=$ -DNS64=$ -DHCPV6_PD=$ -NETWORK_MANAGER=$ -# WEB_GUI=$ -# REST_API=$ diff --git a/module/border_router/cpc-otbr/debconf/services/otbr-agent.service.d/override.conf b/module/border_router/cpc-otbr/debconf/services/otbr-agent.service.d/override.conf deleted file mode 100644 index d12a834..0000000 --- a/module/border_router/cpc-otbr/debconf/services/otbr-agent.service.d/override.conf +++ /dev/null @@ -1,4 +0,0 @@ -[Unit] -PartOf=cpc-otbr.service -BindsTo=cpcd.service -After=cpcd.service diff --git a/module/border_router/cpc-otbr/debconf/services/otbr-firewall.service.d/override.conf b/module/border_router/cpc-otbr/debconf/services/otbr-firewall.service.d/override.conf deleted file mode 100644 index bfe6d01..0000000 --- a/module/border_router/cpc-otbr/debconf/services/otbr-firewall.service.d/override.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Unit] -PartOf=cpc-otbr.service diff --git a/module/border_router/cpc-otbr/debconf/services/otbr-nat44.service.d/override.conf b/module/border_router/cpc-otbr/debconf/services/otbr-nat44.service.d/override.conf deleted file mode 100644 index bfe6d01..0000000 --- a/module/border_router/cpc-otbr/debconf/services/otbr-nat44.service.d/override.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Unit] -PartOf=cpc-otbr.service diff --git a/module/border_router/cpc-otbr/debconf/services/otbr-web.in b/module/border_router/cpc-otbr/debconf/services/otbr-web.in deleted file mode 100644 index e69de29..0000000 diff --git a/module/border_router/cpc-otbr/debconf/services/otbr-web.service.d/override.conf b/module/border_router/cpc-otbr/debconf/services/otbr-web.service.d/override.conf deleted file mode 100644 index 6ddfc93..0000000 --- a/module/border_router/cpc-otbr/debconf/services/otbr-web.service.d/override.conf +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -PartOf=cpc-otbr.service -Requires=otbr-agent.service - -[Service] -ExecStartPre=bash -c "test -e /run/openthread-wpan0.sock || sleep 5" diff --git a/module/border_router/cpc-otbr/third_party b/module/border_router/cpc-otbr/third_party deleted file mode 120000 index a96aa0e..0000000 --- a/module/border_router/cpc-otbr/third_party +++ /dev/null @@ -1 +0,0 @@ -.. \ No newline at end of file diff --git a/module/border_router/cpc-otbr/openthread-core-rafael-posix-config.h b/module/border_router/openthread-core-rafael-posix-config.h similarity index 99% rename from module/border_router/cpc-otbr/openthread-core-rafael-posix-config.h rename to module/border_router/openthread-core-rafael-posix-config.h index 945140d..7b68a3a 100644 --- a/module/border_router/cpc-otbr/openthread-core-rafael-posix-config.h +++ b/module/border_router/openthread-core-rafael-posix-config.h @@ -46,7 +46,7 @@ * * UART: OT_POSIX_RCP_BUS_UART * SPI: OT_POSIX_RCP_BUS_SPI - * CPC: OT_POSIX_RCP_BUS_CPC + * EZMESH: OT_POSIX_RCP_BUS_EZMESH * */ #ifndef OPENTHREAD_POSIX_CONFIG_RCP_BUS @@ -87,7 +87,7 @@ #endif // OPENTHREAD_CONFIG_COPROCESSOR_RPC_ENABLE /****************************************************************************** - * MultiPan RCP (CPC) defaults + * MultiPan RCP (EZMESH) defaults *****************************************************************************/ /** diff --git a/module/border_router/openthread/configure.ac b/module/border_router/openthread/configure.ac index c86126d..514969d 100644 --- a/module/border_router/openthread/configure.ac +++ b/module/border_router/openthread/configure.ac @@ -615,28 +615,28 @@ AC_MSG_RESULT(${enable_cli}) AM_CONDITIONAL([OPENTHREAD_ENABLE_CLI], [test "${enable_cli}" = "yes"]) # -# CPC +# EZMESH # -AC_MSG_CHECKING([whether use CPC support]) -AC_ARG_ENABLE(cpc, - [AS_HELP_STRING([--enable-cpc], [Link CPC @<:@default=no@:>@.])], +AC_MSG_CHECKING([whether use EZMESH support]) +AC_ARG_ENABLE(ezmesh, + [AS_HELP_STRING([--enable-ezmesh], [Link EZMESH @<:@default=no@:>@.])], [ case "${enableval}" in no|yes) - enable_cpc=${enableval} + enable_ezmesh=${enableval} ;; *) - AC_MSG_ERROR([Invalid value ${enable_cpc} for --enable-cpc]) + AC_MSG_ERROR([Invalid value ${enable_ezmesh} for --enable-ezmesh]) ;; esac ], - [enable_cpc=no]) + [enable_ezmesh=no]) -AC_MSG_RESULT(${enable_cpc}) -AM_CONDITIONAL([OPENTHREAD_ENABLE_CPC], [test "${enable_cpc}" = "yes"]) +AC_MSG_RESULT(${enable_ezmesh}) +AM_CONDITIONAL([OPENTHREAD_ENABLE_EZMESH], [test "${enable_ezmesh}" = "yes"]) # # NCP Library @@ -1117,7 +1117,7 @@ AC_MSG_NOTICE([ OpenThread MTD support : ${enable_mtd} OpenThread Radio Only support : ${enable_radio_only} OpenThread CLI support : ${enable_cli} - OpenThread CPC support : ${enable_cpc} + OpenThread EZMESH support : ${enable_ezmesh} OpenThread NCP support : ${enable_ncp} OpenThread NCP Vendor Hook Source : ${with_ncp_vendor_hook_source} OpenThread NCP Spinel Encrypter : ${with_ncp_spinel_encrypter_libs} diff --git a/module/border_router/openthread/src/posix/Makefile-posix b/module/border_router/openthread/src/posix/Makefile-posix index 6033888..cc4476b 100644 --- a/module/border_router/openthread/src/posix/Makefile-posix +++ b/module/border_router/openthread/src/posix/Makefile-posix @@ -123,7 +123,7 @@ endif ifeq ($(RCP_BUS),spi) COMMONCFLAGS += -DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_SPI else ifeq ($(RCP_BUS),cpc) - COMMONCFLAGS += -DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_CPC + COMMONCFLAGS += -DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_EZMESH configure_OPTIONS += --enable-cpc else COMMONCFLAGS += -DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_UART diff --git a/module/border_router/openthread/src/posix/Makefile.am b/module/border_router/openthread/src/posix/Makefile.am index 8f25dbc..962cd1a 100644 --- a/module/border_router/openthread/src/posix/Makefile.am +++ b/module/border_router/openthread/src/posix/Makefile.am @@ -60,9 +60,9 @@ LDADD_COMMON = \ $(top_builddir)/third_party/tcplp/libtcplp.a \ $(NULL) -if OPENTHREAD_ENABLE_CPC +if OPENTHREAD_ENABLE_EZMESH LDADD_COMMON += \ - -lcpc \ + -lezmesh \ $(NULL) endif diff --git a/module/border_router/openthread/src/posix/platform/CMakeLists.txt b/module/border_router/openthread/src/posix/platform/CMakeLists.txt index 8409974..19c34d4 100644 --- a/module/border_router/openthread/src/posix/platform/CMakeLists.txt +++ b/module/border_router/openthread/src/posix/platform/CMakeLists.txt @@ -106,7 +106,7 @@ add_library(openthread-posix backbone.cpp backtrace.cpp config_file.cpp - cpc_interface.cpp + ezmesh_interface.cpp daemon.cpp entropy.cpp firewall.cpp @@ -132,6 +132,8 @@ add_library(openthread-posix virtual_time.cpp ) +get_target_property(EZMESH_SOURCE_DIR ezmesh SOURCE_DIR) +target_include_directories(openthread-posix PRIVATE ${EZMESH_SOURCE_DIR}/library) include(vendor.cmake) target_link_libraries(openthread-posix @@ -179,33 +181,33 @@ target_include_directories(openthread-posix PRIVATE ${PROJECT_SOURCE_DIR}/src/posix/platform/include ) -if(OT_POSIX_CONFIG_RCP_BUS MATCHES "CPC") - if (NOT TARGET cpc) - message(WARNING "CPC target is not available.") - if (NOT CPCD_SOURCE_DIR) - message(FATAL_ERROR "Could not locate CPC daemon sources.\n" - "Please define the CMake variable 'CPCD_SOURCE_DIR'.\n" - "'CPCD_SOURCE_DIR' is an absolute path to the CPC Daemon sources") +if(OT_POSIX_CONFIG_RCP_BUS MATCHES "EZMESH") + if (NOT TARGET ezmesh) + message(WARNING "EZMESH target is not available.") + if (NOT EZMESHD_SOURCE_DIR) + message(FATAL_ERROR "Could not locate EZMESH daemon sources.\n" + "Please define the CMake variable 'EZMESHD_SOURCE_DIR'.\n" + "'EZMESHD_SOURCE_DIR' is an absolute path to the EZMESH Daemon sources") endif() - if (NOT IS_ABSOLUTE ${CPCD_SOURCE_DIR}) - message(FATAL_ERROR "'CPCD_SOURCE_DIR' must be an absolute path.\nCPCD_SOURCE_DIR=\"${CPCD_SOURCE_DIR}\"") + if (NOT IS_ABSOLUTE ${EZMESHD_SOURCE_DIR}) + message(FATAL_ERROR "'EZMESHD_SOURCE_DIR' must be an absolute path.\nEZMESHD_SOURCE_DIR=\"${EZMESHD_SOURCE_DIR}\"") else() - message(WARNING "Building cpc library from source...\n" - " CPCD_SOURCE_DIR = ${CPCD_SOURCE_DIR}") + message(WARNING "Building ezmesh library from source...\n" + " EZMESHD_SOURCE_DIR = ${EZMESHD_SOURCE_DIR}") endif() - # Add cpcd to the build tree - add_subdirectory(${CPCD_SOURCE_DIR} ${CPCD_SOURCE_DIR}/build) + # Add ezmeshd to the build tree + add_subdirectory(${EZMESHD_SOURCE_DIR} ${EZMESHD_SOURCE_DIR}/build) target_include_directories(openthread-posix PRIVATE - ${CPCD_SOURCE_DIR}/lib + ${EZMESHD_SOURCE_DIR}/lib ) endif() - get_target_property(CPCD_SOURCE_DIR cpc SOURCE_DIR) - target_include_directories(openthread-posix PRIVATE ${CPCD_SOURCE_DIR}/lib) - target_sources(openthread-posix PRIVATE cpc_interface.cpp) - target_link_libraries(openthread-posix PRIVATE cpc) + get_target_property(EZMESHD_SOURCE_DIR ezmesh SOURCE_DIR) + target_include_directories(openthread-posix PRIVATE ${EZMESHD_SOURCE_DIR}/lib) + target_sources(openthread-posix PRIVATE ezmesh_interface.cpp) + target_link_libraries(openthread-posix PRIVATE ezmesh) endif() diff --git a/module/border_router/openthread/src/posix/platform/Makefile.am b/module/border_router/openthread/src/posix/platform/Makefile.am index fb8194b..a9daaf8 100644 --- a/module/border_router/openthread/src/posix/platform/Makefile.am +++ b/module/border_router/openthread/src/posix/platform/Makefile.am @@ -83,14 +83,14 @@ noinst_HEADERS = \ radio_url.hpp \ $(NULL) -if OPENTHREAD_ENABLE_CPC +if OPENTHREAD_ENABLE_EZHESH libopenthread_posix_a_CPPFLAGS += \ - -I${top_srcdir}/../../../platform/service/cpc/daemon/lib \ - -I${top_srcdir}/../../../platform/service/cpc/daemon/misc \ + -I${top_srcdir}/../../../platform/service/ezmesh/daemon/lib \ + -I${top_srcdir}/../../../platform/service/ezmesh/daemon/misc \ $(NULL) -libopenthread_posix_a_SOURCES += cpc_interface.cpp -noinst_HEADERS += cpc_interface.hpp +libopenthread_posix_a_SOURCES += ezmesh_interface.cpp +noinst_HEADERS += ezmesh_interface.hpp endif openthread_HEADERS = \ diff --git a/module/border_router/openthread/src/posix/platform/cpc_interface.cpp b/module/border_router/openthread/src/posix/platform/ezmesh_interface.cpp similarity index 72% rename from module/border_router/openthread/src/posix/platform/cpc_interface.cpp rename to module/border_router/openthread/src/posix/platform/ezmesh_interface.cpp index 35d816d..b3ef32e 100644 --- a/module/border_router/openthread/src/posix/platform/cpc_interface.cpp +++ b/module/border_router/openthread/src/posix/platform/ezmesh_interface.cpp @@ -28,10 +28,10 @@ /** * @file - * This file includes the implementation for the CPCd interface to radio (RCP). + * This file includes the implementation for the EZMESHd interface to radio (RCP). */ -#include "cpc_interface.hpp" +#include "ezmesh_interface.hpp" #include "platform-posix.h" @@ -52,16 +52,16 @@ #include "common/logging.hpp" #include "lib/spinel/spinel.h" -#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_CPC +#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_EZMESH using ot::Spinel::SpinelInterface; namespace ot { namespace Posix { -bool CpcInterface::sCpcResetReq = false; +bool Ezmesh::sCpcResetReq = false; -CpcInterface::CpcInterface(SpinelInterface::ReceiveFrameCallback aCallback, +Ezmesh::Ezmesh(SpinelInterface::ReceiveFrameCallback aCallback, void * aCallbackContext, SpinelInterface::RxFrameBuffer & aFrameBuffer) : mReceiveFrameCallback(aCallback) @@ -70,37 +70,39 @@ CpcInterface::CpcInterface(SpinelInterface::ReceiveFrameCallback aCallback, , mSockFd(-1) { memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics)); - mInterfaceMetrics.mRcpInterfaceType = OT_POSIX_RCP_BUS_CPC; + mInterfaceMetrics.mRcpInterfaceType = OT_POSIX_RCP_BUS_EZMESH; mCpcBusSpeed = kCpcBusSpeed; } -void CpcInterface::OnRcpReset(void) +void Ezmesh::OnRcpReset(void) { } -otError CpcInterface::Init(const Url::Url &aRadioUrl) +otError Ezmesh::Init(const Url::Url &aRadioUrl) { otError error = OT_ERROR_NONE; const char * value; + int ret = 0; OT_UNUSED_VARIABLE(aRadioUrl); VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY); - - if (libcpc_init(&mHandle, aRadioUrl.GetPath(), HandleSecondaryReset) != 0) + otLogWarnPlat("%s", aRadioUrl.GetPath()); + ret = libezmesh_init(&mHandle, aRadioUrl.GetPath(), HandleSecondaryReset); + if (ret != 0) { - otLogCritPlat("CPC init failed. Ensure radio-url argument has the form 'spinel+cpc://cpcd_0?iid=<1..3>'"); + otLogCritPlat("%d EZMESH init failed. Ensure radio-url argument has the form 'spinel+ezmesh://ezmeshd_0?iid=<1..3>'", ret); DieNow(OT_EXIT_FAILURE); } - mSockFd = libcpc_open_ep(mHandle, &mEndpoint, mId, 1); + mSockFd = libezmesh_open_ep(mHandle, &mEndpoint, mId, 1); if (mSockFd < 0) { - otLogCritPlat("CPC endpoint open failed"); + otLogCritPlat("EZMESH endpoint open failed"); error = OT_ERROR_FAILED; } - if ((value = aRadioUrl.GetValue("cpc-bus-speed"))) + if ((value = aRadioUrl.GetValue("ezmesh-bus-speed"))) { mCpcBusSpeed = static_cast(atoi(value));; } @@ -111,27 +113,27 @@ otError CpcInterface::Init(const Url::Url &aRadioUrl) return error; } -void CpcInterface::HandleSecondaryReset(void) +void Ezmesh::HandleSecondaryReset(void) { SetCpcResetReq(true); } -CpcInterface::~CpcInterface(void) +Ezmesh::~Ezmesh(void) { Deinit(); } -void CpcInterface::Deinit(void) +void Ezmesh::Deinit(void) { VerifyOrExit(mEndpoint.ptr != nullptr); - VerifyOrExit(0 == libcpc_close_ep(&mEndpoint), perror("close cpc endpoint")); + VerifyOrExit(0 == libezmesh_close_ep(&mEndpoint), perror("close ezmesh endpoint")); exit: return; } -void CpcInterface::Read(uint64_t aTimeoutUs) +void Ezmesh::Read(uint64_t aTimeoutUs) { uint8_t buffer[kMaxFrameSize]; uint8_t *ptr = buffer; @@ -141,24 +143,24 @@ void CpcInterface::Read(uint64_t aTimeoutUs) if(aTimeoutUs > 0) { - cpc_timeval_t timeout; + ezmesh_timeval_t timeout; timeout.seconds = static_cast(aTimeoutUs / US_PER_S); timeout.microseconds = static_cast(aTimeoutUs % US_PER_S); block = true; - ret = libcpc_set_ep_option(mEndpoint, CPC_OPTION_BLOCKING, &block, sizeof(block)); + ret = libezmesh_set_ep_option(mEndpoint, OPTION_BLOCKING, &block, sizeof(block)); OT_ASSERT(ret == 0); - ret = libcpc_set_ep_option(mEndpoint, CPC_OPTION_RX_TIMEOUT, &timeout, sizeof(timeout)); + ret = libezmesh_set_ep_option(mEndpoint, OPTION_RX_TIMEOUT, &timeout, sizeof(timeout)); OT_ASSERT(ret == 0); } else { - ret = libcpc_set_ep_option(mEndpoint, CPC_OPTION_BLOCKING, &block, sizeof(block)); + ret = libezmesh_set_ep_option(mEndpoint, OPTION_BLOCKING, &block, sizeof(block)); OT_ASSERT(ret == 0); } - bytesRead = libcpc_read_ep(mEndpoint, buffer, sizeof(buffer), CPC_EP_READ_FLAG_NONE); + bytesRead = libezmesh_read_ep(mEndpoint, buffer, sizeof(buffer), EP_READ_FLAG_NONE); if (bytesRead > 0) { @@ -183,7 +185,7 @@ void CpcInterface::Read(uint64_t aTimeoutUs) } } -otError CpcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength) +otError Ezmesh::SendFrame(const uint8_t *aFrame, uint16_t aLength) { otError error; @@ -192,7 +194,7 @@ otError CpcInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength) return error; } -otError CpcInterface::Write(const uint8_t *aFrame, uint16_t aLength) +otError Ezmesh::Write(const uint8_t *aFrame, uint16_t aLength) { otError error = OT_ERROR_NONE; @@ -207,7 +209,7 @@ otError CpcInterface::Write(const uint8_t *aFrame, uint16_t aLength) while (aLength) { - ssize_t bytesWritten = libcpc_write_ep(mEndpoint, aFrame, aLength, CPC_EP_WRITE_FLAG_NON_BLOCKING); + ssize_t bytesWritten = libezmesh_write_ep(mEndpoint, aFrame, aLength, EP_WRITE_FLAG_NON_BLOCKING); if (bytesWritten == aLength) { @@ -230,7 +232,7 @@ otError CpcInterface::Write(const uint8_t *aFrame, uint16_t aLength) return error; } -otError CpcInterface::WaitForFrame(uint64_t aTimeoutUs) +otError Ezmesh::WaitForFrame(uint64_t aTimeoutUs) { otError error = OT_ERROR_NONE; @@ -240,7 +242,7 @@ otError CpcInterface::WaitForFrame(uint64_t aTimeoutUs) return error; } -void CpcInterface::UpdateFdSet(void *aMainloopContext) +void Ezmesh::UpdateFdSet(void *aMainloopContext) { otSysMainloopContext *context = reinterpret_cast(aMainloopContext); @@ -254,30 +256,30 @@ void CpcInterface::UpdateFdSet(void *aMainloopContext) } } -void CpcInterface::Process(const void *aMainloopContext) +void Ezmesh::Process(const void *aMainloopContext) { OT_UNUSED_VARIABLE(aMainloopContext); CheckAndReInitCpc(); Read(0); } -void CpcInterface::CheckAndReInitCpc(void) +void Ezmesh::CheckAndReInitCpc(void) { int result; int attempts = 0; - //Check if CPC needs to be restarted + //Check if EZMESH needs to be restarted VerifyOrExit(sCpcResetReq); do { //Add some delay before attempting to restart usleep(kMaxSleepDuration); - //Try to restart CPC - result = libcpc_reset(&mHandle); + //Try to restart EZMESH + result = libezmesh_reset(&mHandle); //Mark how many times the restart was attempted attempts++; - //Continue to try and restore CPC communication until we + //Continue to try and restore EZMESH communication until we //have exhausted the retries or restart was successful } while ((result != 0) && (attempts < kMaxRestartAttempts)); @@ -285,12 +287,12 @@ void CpcInterface::CheckAndReInitCpc(void) VerifyOrDie(result == 0, OT_EXIT_ERROR_ERRNO); //Reopen the endpoint for communication - mSockFd = libcpc_open_ep(mHandle, &mEndpoint, mId, 1); + mSockFd = libezmesh_open_ep(mHandle, &mEndpoint, mId, 1); //If the restart failed, exit. VerifyOrDie(mSockFd >= 0, OT_EXIT_ERROR_ERRNO); - otLogCritPlat("Restarted CPC successfully"); + otLogCritPlat("Restarted EZMESH successfully"); //Clear the flag SetCpcResetReq(false); @@ -299,10 +301,10 @@ void CpcInterface::CheckAndReInitCpc(void) return; } -void CpcInterface::SendResetResponse(void) +void Ezmesh::SendResetResponse(void) { - // Put CPC Reset call here + // Put EZMESH Reset call here for(int i=0; i STATUS_RESET_SOFTWARE uint8_t mResetResponse[kResetCMDSize] = {0x80, 0x06, 0x00, 0x72}; - const uint8_t mId = CPC_EP_15_4; - typedef uint8_t cpcError; + const uint8_t mId = EP_15_4; + typedef uint8_t ezmeshError; static bool sCpcResetReq; otRcpInterfaceMetrics mInterfaceMetrics; // Non-copyable, intentionally not implemented. - CpcInterface(const CpcInterface &); - CpcInterface &operator=(const CpcInterface &); + Ezmesh(const Ezmesh &); + Ezmesh &operator=(const Ezmesh &); }; } // namespace Posix } // namespace ot -#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_CPC -#endif // POSIX_APP_CPC_INTERFACE_HPP_ +#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_EZMESH +#endif // POSIX_APP_EZMESH_INTERFACE_HPP_ diff --git a/module/border_router/openthread/src/posix/platform/openthread-core-rafael-posix-config.h b/module/border_router/openthread/src/posix/platform/openthread-core-rafael-posix-config.h index 945140d..7b68a3a 100644 --- a/module/border_router/openthread/src/posix/platform/openthread-core-rafael-posix-config.h +++ b/module/border_router/openthread/src/posix/platform/openthread-core-rafael-posix-config.h @@ -46,7 +46,7 @@ * * UART: OT_POSIX_RCP_BUS_UART * SPI: OT_POSIX_RCP_BUS_SPI - * CPC: OT_POSIX_RCP_BUS_CPC + * EZMESH: OT_POSIX_RCP_BUS_EZMESH * */ #ifndef OPENTHREAD_POSIX_CONFIG_RCP_BUS @@ -87,7 +87,7 @@ #endif // OPENTHREAD_CONFIG_COPROCESSOR_RPC_ENABLE /****************************************************************************** - * MultiPan RCP (CPC) defaults + * MultiPan RCP (EZMESH) defaults *****************************************************************************/ /** diff --git a/module/border_router/openthread/src/posix/platform/openthread-posix-config.h b/module/border_router/openthread/src/posix/platform/openthread-posix-config.h index be6ad80..c2368be 100644 --- a/module/border_router/openthread/src/posix/platform/openthread-posix-config.h +++ b/module/border_router/openthread/src/posix/platform/openthread-posix-config.h @@ -105,7 +105,7 @@ */ #define OT_POSIX_RCP_BUS_VENDOR 3 -#define OT_POSIX_RCP_BUS_CPC 4 +#define OT_POSIX_RCP_BUS_EZMESH 4 /** * @def OPENTHREAD_POSIX_CONFIG_RCP_BUS diff --git a/module/border_router/openthread/src/posix/platform/radio.cpp b/module/border_router/openthread/src/posix/platform/radio.cpp index c389794..457dcaa 100644 --- a/module/border_router/openthread/src/posix/platform/radio.cpp +++ b/module/border_router/openthread/src/posix/platform/radio.cpp @@ -55,10 +55,10 @@ static ot::Spinel::RadioSpinel sRadioSpinel; #include "vendor_interface.hpp" static ot::Spinel::RadioSpinel sRadioSpinel; -#elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_CPC -#include "cpc_interface.hpp" +#elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_EZMESH +#include "ezmesh_interface.hpp" -static ot::Spinel::RadioSpinel sRadioSpinel; +static ot::Spinel::RadioSpinel sRadioSpinel; #else #error "OPENTHREAD_POSIX_CONFIG_RCP_BUS only allows OT_POSIX_RCP_BUS_UART, OT_POSIX_RCP_BUS_SPI and " \ "OT_POSIX_RCP_BUS_VENDOR!" diff --git a/module/border_router/openthread/src/posix/platform/radio_url.cpp b/module/border_router/openthread/src/posix/platform/radio_url.cpp index 69cdb59..ab2b02e 100644 --- a/module/border_router/openthread/src/posix/platform/radio_url.cpp +++ b/module/border_router/openthread/src/posix/platform/radio_url.cpp @@ -62,12 +62,12 @@ const char *otSysGetRadioUrlHelpString(void) " MISO frame. Max value is 16.\n" \ " spi-small-packet=[n] Specify the smallest packet we can receive in a single transaction.\n" \ " (larger packets will require two transactions). Default value is 32.\n" -#elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_CPC +#elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_EZMESH #define OT_RADIO_URL_HELP_BUS \ - " spinel+cpc://cpcd_0?${Parameters} for connecting to cpcd\n" \ + " spinel+ezmesh://ezmeshd_0?${Parameters} for connecting to ezmeshd\n" \ "Parameters:\n" \ - " cpc-bus-speed[=speed] CPC bus speed used for communicating with RCP.\n" + " ezmesh-bus-speed[=speed] EZMESH bus speed used for communicating with RCP.\n" diff --git a/module/border_router/ot-br-posix/script/cmake-build-android b/module/border_router/ot-br-posix/script/cmake-build-android index 06c3964..5919678 100644 --- a/module/border_router/ot-br-posix/script/cmake-build-android +++ b/module/border_router/ot-br-posix/script/cmake-build-android @@ -83,7 +83,7 @@ main() OTBR_MDNS=mDNSResponder - OTBR_OPTIONS="-DOT_MULTIPAN_RCP=ON -DOT_POSIX_CONFIG_RCP_BUS=CPC -DCPCD_SOURCE_DIR=${gsdk_dir}/platform/service/cpc/daemon" + OTBR_OPTIONS="-DOT_MULTIPAN_RCP=ON -DOT_POSIX_CONFIG_RCP_BUS=EZMESH" # Create builddir builddir="${OTBR_BUILD_DIR:-${OTBR_TOP_BUILD_DIR}}" diff --git a/module/controller/CMakeLists.txt b/module/controller/CMakeLists.txt new file mode 100644 index 0000000..485bd41 --- /dev/null +++ b/module/controller/CMakeLists.txt @@ -0,0 +1,114 @@ +project(EZMESH VERSION "${EZMESHD_VER}" LANGUAGES C) +set(EZMESH_LIBRARY_API_VERSION "${EZMESHD_LIB}") +set(EZMESH_PROTOCOL_VERSION "${EZMESHD_POTOCOL}") + +# Options +set(TARGET_GROUP release CACHE STRING "Group to build") +option(WARN_AS_ERROR "Treat warnings as errors") + +set(EZMESH_CRC_0 0) +if (DEFINED EZMESH_CRC_0) + message(STATUS "Using EZMESH_CRC_0") + add_definitions(-DEZMESH_CRC_0=${EZMESH_CRC_0}) +endif() + +# Includes +include(cmake/GetGitRevisionDescription.cmake) +include(cmake/TargetStds.cmake) +include(cmake/Warnings.cmake) +include(GNUInstallDirs) + +# Dependencies +find_package(Threads REQUIRED) +find_path(Linux_INCLUDE_DIR "linux/version.h") + +ext_config(GIT_SHA1 "Unknown") +ext_config(GIT_REFSPEC "Unknown") +get_git_head_revision(GIT_REFSPEC GIT_SHA1 ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) +add_definitions("-DGIT_SHA1=\"${GIT_SHA1}\"") +add_definitions("-DGIT_REFSPEC=\"${GIT_REFSPEC}\"") + +if(WARN_AS_ERROR) + target_compile_options(_Warnings INTERFACE -Werror) +endif() + +add_library(ezmesh SHARED) +target_stds(ezmesh C 99 POSIX 2008) +target_link_libraries(ezmesh PRIVATE Interface::Warnings) +target_sources(ezmesh PRIVATE host/hal_sleep.c) +target_sources(ezmesh PRIVATE library/libezmesh.c) + +target_include_directories(ezmesh PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") +target_include_directories(ezmesh PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") +set_target_properties(ezmesh PROPERTIES VERSION "${PROJECT_VERSION}") +set_target_properties(ezmesh PROPERTIES SOVERSION "${EZMESH_LIBRARY_API_VERSION}") +set_target_properties(ezmesh PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/library/libezmesh.h") + +# EZMESHd Config file path +if(NOT DEFINED EZMESHD_CONFIG_FILE_PATH) + set(EZMESHD_CONFIG_FILE_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/config.ini) +endif() +add_definitions(-DEZMESHD_CONFIG_FILE_PATH="${EZMESHD_CONFIG_FILE_PATH}") +message(STATUS "EZMESHD_CONFIG_FILE_PATH=${EZMESHD_CONFIG_FILE_PATH}") + +# EZMESHd minimum reboot time +if(NOT DEFINED EZMESHD_REBOOT_TIME_MS) + set(EZMESHD_REBOOT_TIME_MS 2000) +endif() +add_definitions(-DEZMESHD_REBOOT_TIME_MS=${EZMESHD_REBOOT_TIME_MS}) +message(STATUS "EZMESHD_REBOOT_TIME_MS=${EZMESHD_REBOOT_TIME_MS}") + +# EZMESH Socket directory +if(NOT DEFINED EZMESH_SOCKET_DIR) + set(EZMESH_SOCKET_DIR /dev/shm/ezmesh) +endif() +add_definitions(-DEZMESH_SOCKET_DIR="${EZMESH_SOCKET_DIR}") +message(STATUS "EZMESH_SOCKET_DIR=${EZMESH_SOCKET_DIR}") + + +# Build EZMESH Daemon if building for release or debug +if((TARGET_GROUP STREQUAL release) OR (TARGET_GROUP STREQUAL debug)) + message(STATUS "Building EZMESH Daemon") + + # CMake<3.11 requires two arguments + add_executable(ezmeshd main.c) + target_stds(ezmeshd C 99 POSIX 2008) + target_link_libraries(ezmeshd PRIVATE Interface::Warnings) + target_include_directories(ezmeshd PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") + target_include_directories(ezmeshd PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") + target_include_directories(ezmeshd PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/library") + target_sources(ezmeshd PRIVATE + main.c + daemon/hdlc/core.c + daemon/primary/primary.c + daemon/controller.c + host/hal_epoll.c + host/hal_kill.c + host/hal_sleep.c + host/hal_uart.c + utility/config.c + utility/list.c + utility/log.c + utility/utility.c) + + target_link_libraries(ezmeshd PRIVATE Threads::Threads) + + # Hash all files except those in the output folder + get_target_property(EZMESHD_SOURCES ezmeshd SOURCES) + foreach(file ${EZMESHD_SOURCES}) + file(SHA256 "${CMAKE_CURRENT_SOURCE_DIR}/${file}" FILE_HASH) + string(APPEND SOURCES_HASH "${FILE_HASH}") + string(SHA256 SOURCES_HASH "${SOURCES_HASH}") + endforeach() + message(STATUS "Sources hash: ${SOURCES_HASH}") + + install(TARGETS ezmesh ezmeshd + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + install(FILES ez_config.ini DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config) +endif() + +# Configure the version header file +configure_file(utility/version.h.in autogen/version.h) diff --git a/module/cpc/cpcd/cmake/GetGitRevisionDescription.cmake b/module/controller/cmake/GetGitRevisionDescription.cmake similarity index 100% rename from module/cpc/cpcd/cmake/GetGitRevisionDescription.cmake rename to module/controller/cmake/GetGitRevisionDescription.cmake diff --git a/module/cpc/cpcd/cmake/GetGitRevisionDescription.cmake.in b/module/controller/cmake/GetGitRevisionDescription.cmake.in similarity index 100% rename from module/cpc/cpcd/cmake/GetGitRevisionDescription.cmake.in rename to module/controller/cmake/GetGitRevisionDescription.cmake.in diff --git a/module/cpc/cpcd/cmake/TargetStds.cmake b/module/controller/cmake/TargetStds.cmake similarity index 100% rename from module/cpc/cpcd/cmake/TargetStds.cmake rename to module/controller/cmake/TargetStds.cmake diff --git a/module/cpc/cpcd/cmake/Warnings.cmake b/module/controller/cmake/Warnings.cmake similarity index 100% rename from module/cpc/cpcd/cmake/Warnings.cmake rename to module/controller/cmake/Warnings.cmake diff --git a/module/cpc/cpcd/cmake/modules/FindMbedTLS.cmake b/module/controller/cmake/modules/FindMbedTLS.cmake similarity index 100% rename from module/cpc/cpcd/cmake/modules/FindMbedTLS.cmake rename to module/controller/cmake/modules/FindMbedTLS.cmake diff --git a/module/cpc/cpcd/cmake/rpi.cmake b/module/controller/cmake/rpi.cmake similarity index 100% rename from module/cpc/cpcd/cmake/rpi.cmake rename to module/controller/cmake/rpi.cmake diff --git a/module/controller/daemon/controller.c b/module/controller/daemon/controller.c index e69de29..2cb92e0 100644 --- a/module/controller/daemon/controller.c +++ b/module/controller/daemon/controller.c @@ -0,0 +1,592 @@ +/** + * @file controller.c + * @author Rex Huang (rex.huang@rafaelmicro.com) + * @brief + * @version 0.1 + * @date 2023-10-30 + * + * + */ +#define _GNU_SOURCE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utility/config.h" +#include "utility/log.h" +#include "host/hal_sleep.h" +#include "utility/utility.h" + +#include "controller.h" +#include "host/hal_epoll.h" +#include "primary/primary.h" +#include "daemon/hdlc/core.h" + +#include "host/hal_kill.h" + +#include "version.h" + +//============================================================================= +// Constant Definition +//============================================================================= + +//============================================================================= +// Macro Definition +//============================================================================= + +//============================================================================= +// Structure Definition +//============================================================================= +#define MAX_EPOLL_EVENTS 1 +// #define THREAD_SLEEP_NS 2000000L + +//============================================================================= +// Global Data Definition +//============================================================================= +bool ignore_reset_reason = true; +static char *controller_agent_app_version = NULL; +static uint8_t controller_agent_protocol_version; +static bool set_reset_mode_ack = false; +static bool reset_ack = false; +static bool agent_ezmesh_version_received = false; +static bool agent_app_version_received_or_not_available = false; +static bool agent_bus_speed_received = false; +static bool failed_to_receive_agent_bus_speed = false; +static bool reset_reason_received = false; +static bool capabilities_received = false; +static bool rx_capability_received = false; +static bool protocol_version_received = false; +static reboot_mode_t pending_mode; +static int kill_eventfd = -1; +static enum +{ + E_SET_REBOOT_MODE, + E_WAIT_REBOOT_MODE_ACK, + E_WAIT_RESET_ACK, + E_WAIT_RESET_REASON, + E_WAIT_CAPABILITIES, + E_WAIT_RX_CAPABILITY, + E_WAIT_BOOTLOADER_INFO, + E_WAIT_SECONDARY_EZMESH_VERSION, + E_WAIT_SECONDARY_APP_VERSION, + E_WAIT_PROTOCOL_VERSION, + E_WAIT_SECONDARY_BUS_SPEED, + E_RESET_SEQUENCE_DONE +} reset_sequence_state = E_SET_REBOOT_MODE; + +static uint32_t rx_capability = 0; +static uint32_t capabilities = 0; + + +//============================================================================= +// Private Function Definition +//============================================================================= +static void __controller_reset_proc(void); + +static status_t state_passer(sys_status_t val) { return (val == SYS_STATUS_OK)? STATUS_OK : STATUS_FAIL; } + +static void __controller_remove_socket_folder(const char *folder) +{ + struct dirent *next_file = NULL; + char filepath[(sizeof(((struct sockaddr_un *)0)->sun_path))] = {}; + DIR *dir = NULL; + + dir = opendir(folder); + CHECK_ERROR(dir == NULL); + + while ((next_file = readdir(dir)) != NULL) + { + strcpy(filepath, folder); + strcat(filepath, "/"); + strcat(filepath, next_file->d_name); + if (strstr(filepath, ".sock") != NULL) + { + log_info("[Controller] Removing %s", filepath); + CHECK_ERROR(remove(filepath) < 0); + } + } + closedir(dir); +} + +static void *__controller_loop(void *param) +{ + struct epoll_event events[MAX_EPOLL_EVENTS] = {}; + size_t cnt = 0; + + (void)param; + + while (1) + { + __controller_reset_proc(); + core_process_transmit_queue(); + + cnt = hal_epoll_wait_for_event(events, MAX_EPOLL_EVENTS); + for (size_t i = 0; i < (size_t)cnt; i++) + { + hal_epoll_event_data_t *event_data = (hal_epoll_event_data_t *)events[i].data.ptr; + // log_info("EPOLL EVENT: fd 0x%02x, EP %d, cb: %p", event_data->file_descriptor, event_data->endpoint_number, event_data->callback); + if(event_data->callback != NULL) event_data->callback(event_data); + } + ctl_proc_conn(); + // nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); + } + + return NULL; +} + +static void __controller_set_reset_mode_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + (void)property_id; + (void)property_value; + + switch (status) + { + case STATUS_IN_PROGRESS: + case STATUS_OK:{ + if (property_length != sizeof(sys_status_t)) log_error("Set reset mode reply length error"); + CHECK_FATAL(property_length != sizeof(reboot_mode_t)); + set_reset_mode_ack = true; + break;} + + case STATUS_TIMEOUT: + case STATUS_ABORT:{ + log_info("Failed to connect, agent seems unresponsive"); + ignore_reset_reason = false; + reset_sequence_state = E_SET_REBOOT_MODE; + break;} + default:{ + FATAL("Unhandled __controller_set_reset_mode_callback status"); + break;} + } +} + +static void __controller_reset_callback(sys_cmd_handle_t *handle, + status_t status, + sys_status_t reset_status) +{ + (void)handle; + + switch (status) + { + case STATUS_IN_PROGRESS: + case STATUS_OK:{ + log_info("[Reset Seq] Reset request response received : %d", reset_status); + if (state_passer(reset_status) == STATUS_OK) reset_ack = true; + break;} + + case STATUS_TIMEOUT: + case STATUS_ABORT:{ + log_warn("Failed to reset Agent"); + ignore_reset_reason = false; // Don't ignore a agent that resets + reset_sequence_state = E_SET_REBOOT_MODE; + break;} + default:{ + FATAL("Unhandled __controller_reset_callback status"); + break;} + } +} + +static void __controller_unsolicited_callback(sys_status_t status) +{ + int ret; + extern char **argv_g; + + if (ignore_reset_reason) + { + ignore_reset_reason = false; + log_info("[Reset Seq] Ignored reset reason : %u", status); + return; + } + + if (status <= SYS_STATUS_RESET_WATCHDOG && status >= SYS_STATUS_RESET_POWER_ON) + { + log_info("[Reset Seq] Received reset reason : %u", status); + log_info("[Reset Seq] Reset sequence: %u", reset_sequence_state); + + if (reset_sequence_state == E_WAIT_RESET_REASON) reset_reason_received = true; + else + { + log_info("Agent has reset, reset the daemon."); + + /* Stop driver immediately */ + ret = hal_kill_signal_and_join(); + CHECK_ERROR(ret != 0); + ctl_notify_HW_reset(); + for (uint8_t i = 1; i < 255; ++i) EP_close(i, false); + config_restart(argv_g); + } + } +} + +static void __controller_get_capabilities_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + + CHECK_ERROR(property_id != PROP_CAPABILITIES); + CHECK_ERROR(status != STATUS_OK && status != STATUS_IN_PROGRESS); + CHECK_ERROR(property_value == NULL || property_length != sizeof(uint32_t)); + + capabilities = *((uint32_t *)property_value); + + if (capabilities & CAPABILITIES_PACKED_EP_MASK) log_info("[Reset Seq] Received capability : Packed endpoint"); + if (capabilities & CAPABILITIES_UART_FLOW_CONTROL_MASK) log_info("[Reset Seq] Received capability : UART flow control"); + capabilities_received = true; +} + +static void __controller_get_rx_capability_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + + CHECK_ERROR(property_id != PROP_RX_CAPABILITY); + CHECK_ERROR(status != STATUS_OK && status != STATUS_IN_PROGRESS); + CHECK_ERROR(property_value == NULL || property_length != sizeof(uint16_t)); + + log_info("[Reset Seq] Received RX capability of %u bytes", *((uint16_t *)property_value)); + rx_capability = *((uint16_t *)property_value); + rx_capability_received = true; +} + +static void __controller_get_agent_ezmesh_version_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + + uint32_t version[3]; + memcpy(version, property_value, 3 * sizeof(uint32_t)); + + if ((property_id != PROP_SECONDARY_EZMESH_VERSION) + || (status != STATUS_OK && status != STATUS_IN_PROGRESS) + || (property_value == NULL || property_length != 3 * sizeof(uint32_t))) + { + log_error("Cannot get Agent EZMESH version (obsolete RCP firmware?)"); + } + + log_info("[Controller] Agent EZMESH v%d.%d.%d", version[0], version[1], version[2]); + agent_ezmesh_version_received = true; +} + +static void __controller_get_agent_app_version_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + + if ((status == STATUS_OK || status == STATUS_IN_PROGRESS) && property_id == PROP_SECONDARY_APP_VERSION) + { + CHECK_ERROR(property_value == NULL); + CHECK_ERROR(property_length == 0); + + const char *version = (const char *)property_value; + + CHECK_FATAL(controller_agent_app_version); + + controller_agent_app_version = calloc(1, property_length); + CHECK_ERROR(controller_agent_app_version == NULL); + + strncpy(controller_agent_app_version, version, property_length - 1); + controller_agent_app_version[property_length - 1] = '\0'; + log_info("[Controller] Agent APP v%s", controller_agent_app_version); + } + else log_warn("Cannot get Agent APP version (obsolete RCP firmware?)"); + + agent_app_version_received_or_not_available = true; +} + +static void __controller_get_agent_bus_speed_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + uint32_t bus_speed = 0; + + if ((status == STATUS_OK || status == STATUS_IN_PROGRESS) && property_id == PROP_BUS_SPEED_VALUE) + { + CHECK_ERROR(property_value == NULL); + CHECK_ERROR(property_length != sizeof(uint32_t)); + + memcpy(&bus_speed, property_value, sizeof(uint32_t)); + + log_info("[Controller] Agent bus speed is %d", bus_speed); + + if (config.ep_hw.type == EP_TYPE_UART && bus_speed != config.ep_hw.baudrate) + { + log_error("Baudrate mismatch (%d) on the daemon versus (%d) on the agent", config.ep_hw.baudrate, bus_speed); + } + + agent_bus_speed_received = true; + } + else + { + log_warn("Could not obtain the agent's bus speed"); + failed_to_receive_agent_bus_speed = true; + } +} + +static void __controller_get_protocol_version_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + + uint8_t *version = (uint8_t *)property_value; + + if ((property_id != PROP_PROTOCOL_VERSION) + || (status != STATUS_OK && status != STATUS_IN_PROGRESS) + || (property_value == NULL || property_length != sizeof(uint8_t))) + { + log_error("Cannot get Agent Protocol version (obsolete RCP firmware?)"); + } + + controller_agent_protocol_version = *version; + log_info("[Controller] Agent Protocol v%d", controller_agent_protocol_version); + + protocol_version_received = true; +} + +static void __controller_capabilities_check(void) +{ + if ((config.ep_hw.type == EP_TYPE_UART) && (config.ep_hw.flowcontrol != (bool)(capabilities & CAPABILITIES_UART_FLOW_CONTROL_MASK))) + { + log_error("UART flow control configuration mismatch between EZMESHd (%s) and Agent (%s)", + config.ep_hw.flowcontrol ? "enabled" : "disabled", + (bool)(capabilities & CAPABILITIES_UART_FLOW_CONTROL_MASK) ? "enabled" : "disabled"); + } +} + +static void __controller_protocol_version_check(void) +{ + if (controller_agent_protocol_version != PROTOCOL_VERSION) + { + log_error("Agent Protocol v%d doesn't match EZMESHd Protocol v%d", + controller_agent_protocol_version, PROTOCOL_VERSION); + } +} + +static void __controller_reset_proc(void) +{ + switch (reset_sequence_state) + { + case E_RESET_SEQUENCE_DONE:{ + return;} + + case E_SET_REBOOT_MODE:{ + log_info("[Controller] Connecting to Agent..."); + const reboot_mode_t reboot_mode = REBOOT_APPLICATION; + pending_mode = reboot_mode; + sys_param_set(__controller_set_reset_mode_callback, + 1, 2000000, PROP_BOOTLOADER_REBOOT_MODE, + &reboot_mode, sizeof(reboot_mode), true); + reset_sequence_state = E_WAIT_REBOOT_MODE_ACK; + log_info("[Reset Seq] Reboot mode sent"); + break;} + + case E_WAIT_REBOOT_MODE_ACK:{ + if (set_reset_mode_ack) + { + sys_reboot(__controller_reset_callback, 5, 100000); + reset_sequence_state = E_WAIT_RESET_ACK; + set_reset_mode_ack = false; + log_info("[Reset Seq] Reboot mode reply received, reset request sent"); + } + break;} + + case E_WAIT_RESET_ACK:{ + if (reset_ack == true) + { + reset_sequence_state = E_WAIT_RESET_REASON; + reset_ack = false; + log_info("[Reset Seq] Reset request acknowledged"); + } + break;} + + case E_WAIT_RESET_REASON:{ + log_info("[Reset Seq] Waiting for reset reason"); + if (reset_reason_received) + { + log_info("[Reset Seq] Reset reason received"); + reset_sequence_state = E_WAIT_RX_CAPABILITY; + sys_param_get(__controller_get_rx_capability_callback, + PROP_RX_CAPABILITY, 5, 100000, true); + } + break;} + + case E_WAIT_RX_CAPABILITY:{ + if (rx_capability_received) + { + log_info("[Reset Seq] Get RX capability"); + log_info("[Controller] Connected to Agent"); + reset_sequence_state = E_WAIT_PROTOCOL_VERSION; + sys_param_get(__controller_get_protocol_version_callback, + PROP_PROTOCOL_VERSION, 5, 100000, true); + } + break;} + + case E_WAIT_PROTOCOL_VERSION:{ + if (protocol_version_received) + { + log_info("[Reset Seq] Get Protocol version"); + __controller_protocol_version_check(); + reset_sequence_state = E_WAIT_CAPABILITIES; + sys_param_get(__controller_get_capabilities_callback, + PROP_CAPABILITIES, 5, 100000, true); + } + break;} + + case E_WAIT_CAPABILITIES:{ + if (capabilities_received) + { + log_info("[Reset Seq] Get Capabilites"); + __controller_capabilities_check(); + reset_sequence_state = E_WAIT_SECONDARY_BUS_SPEED; + sys_param_get(__controller_get_agent_bus_speed_callback, + PROP_BUS_SPEED_VALUE, 5, 100000, true); + } + break;} + + case E_WAIT_SECONDARY_EZMESH_VERSION:{ + if (agent_ezmesh_version_received) + { + log_info("[Reset Seq] Get Agent EZMESH version"); + reset_sequence_state = E_WAIT_SECONDARY_APP_VERSION; + sys_param_get(__controller_get_agent_app_version_callback, + PROP_SECONDARY_APP_VERSION, 5, 100000, true); + } + break;} + + case E_WAIT_SECONDARY_BUS_SPEED:{ + if (agent_bus_speed_received || failed_to_receive_agent_bus_speed) + { + reset_sequence_state = E_WAIT_SECONDARY_EZMESH_VERSION; + sys_param_get(__controller_get_agent_ezmesh_version_callback, + PROP_SECONDARY_EZMESH_VERSION, 5, 100000, true); + } + break;} + + case E_WAIT_SECONDARY_APP_VERSION:{ + if (agent_app_version_received_or_not_available) + { + reset_sequence_state = E_RESET_SEQUENCE_DONE; + ctl_init(); + log_info("Daemon startup was successful. Waiting for client connections"); + } + break;} + + default:{ + FATAL("Impossible state"); + break;} + } +} + +static void __controller_cleanup(hal_epoll_event_data_t *event_data) +{ + (void)event_data; + + log_info("Server ezmeshd cleanup"); + sys_cleanup(); + pthread_exit(0); +} + +bool controller_reset_sequence_in_progress(void) { return reset_sequence_state != E_RESET_SEQUENCE_DONE; } + + +uint32_t controller_get_agent_rx_capability(void) +{ + CHECK_ERROR(rx_capability == 0); + return rx_capability; +} + +void controller_kill_signal(void) +{ + ssize_t ret = 0; + const uint64_t event_value = 1; + + if (kill_eventfd == -1) return; + + ret = write(kill_eventfd, &event_value, sizeof(event_value)); + CHECK_ERROR(ret != sizeof(event_value)); +} + +pthread_t controller_init(int fd_socket_driver_ezmeshd, int fd_socket_driver_ezmeshd_notify) +{ + char *socket_folder = NULL; + struct stat sb = { 0 }; + pthread_t controller_thread = { 0 }; + int ret = 0; + static hal_epoll_event_data_t event_data = {0}; + + core_init(fd_socket_driver_ezmeshd, fd_socket_driver_ezmeshd_notify); + sys_init(); + sys_set_last_status_callback(__controller_unsolicited_callback); + + const size_t path_len = strlen(config.ep_hw.socket_path) + strlen("/") + strlen(config.ep_hw.name) + sizeof(char); + + socket_folder = (char *)calloc(1, path_len); + CHECK_ERROR(socket_folder == NULL); + + ret = snprintf(socket_folder, path_len, "%s/%s", config.ep_hw.socket_path, config.ep_hw.name); + CHECK_ERROR(ret < 0 || (size_t)ret >= path_len); + + if (stat(socket_folder, &sb) == 0 && S_ISDIR(sb.st_mode)) + { + log_info("[Controller] Remove socket folder %s", socket_folder); + __controller_remove_socket_folder(socket_folder); + } + else + { + log_info("[Controller] Remove socket folder %s", socket_folder); + recursive_mkdir(socket_folder, strlen(socket_folder), S_IRWXU | S_IRWXG | S_ISVTX); + ret = access(socket_folder, W_OK); + CHECK_ERROR(ret < 0); + } + + free(socket_folder); + + kill_eventfd = eventfd(0, EFD_CLOEXEC); + CHECK_ERROR(kill_eventfd == -1); + + event_data.callback = __controller_cleanup; + event_data.file_descriptor = kill_eventfd; + event_data.endpoint_number = 0; + hal_epoll_register(&event_data); + + CHECK_ERROR(pthread_create(&controller_thread, NULL, __controller_loop, NULL) != 0); + CHECK_ERROR(pthread_setname_np(controller_thread, "primary_ezmeshd") != 0); + return controller_thread; +} + +char *controller_get_agent_app_version(void) +{ + CHECK_FATAL(controller_agent_app_version == NULL); + return controller_agent_app_version; +} diff --git a/module/controller/daemon/controller.h b/module/controller/daemon/controller.h index e69de29..863d827 100644 --- a/module/controller/daemon/controller.h +++ b/module/controller/daemon/controller.h @@ -0,0 +1,17 @@ + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#define _GNU_SOURCE +#include + +#include +#include + +bool controller_reset_sequence_in_progress(void); +uint32_t controller_get_agent_rx_capability(void); +void controller_kill_signal(void); +pthread_t controller_init(int fd_socket_driver_ezmeshd, int fd_socket_driver_ezmeshd_notify); +char *controller_get_agent_app_version(void); + +#endif diff --git a/module/controller/daemon/hdlc/core.c b/module/controller/daemon/hdlc/core.c index e69de29..04d0385 100644 --- a/module/controller/daemon/hdlc/core.c +++ b/module/controller/daemon/hdlc/core.c @@ -0,0 +1,1520 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utility/log.h" +#include "utility/config.h" +#include "utility/list.h" +#include "utility/utility.h" + +#include "daemon/primary/primary.h" +#include "host/hal_epoll.h" +#include "core.h" + + +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#define X_ENUM_TO_STR(x) #x +#define ENUM_TO_STR(x) X_ENUM_TO_STR(x) + +/******************************************************************************* + *************************** GLOBAL VARIABLES ******************************* + ******************************************************************************/ +dbg_cts_t primary_cpcd_debug_counters; +dbg_cts_t secondary_cpcd_debug_counters; + +/******************************************************************************* + *************************** LOCAL DECLARATIONS ***************************** + ******************************************************************************/ + +/******************************************************************************* + *************************** LOCAL VARIABLES ******************************** + ******************************************************************************/ +static int hal_sock_fd; +static int hal_sock_notify_fd; +static int timer_fd; +static endpoint_t core_endpoints[EP_MAX_COUNT]; +static list_node_t *transmit_queue = NULL; +static list_node_t *pending_on_security_ready_queue = NULL; +static list_node_t *pending_on_tx_complete = NULL; + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + *****************************************************************************/ +static void core_proc_rx_hal_notification(hal_epoll_event_data_t *event_data); +static void core_proc_rx_hal(hal_epoll_event_data_t *event_data); +static void core_proc_endpoint_timeout(hal_epoll_event_data_t *event_data); +static void core_proc_rx_iframe(frame_t *rx_frame); +static void core_proc_rx_sframe(frame_t *rx_frame); +static void core_proc_rx_uframe(frame_t *rx_frame); +static bool core_proc_tx_data(void); +static void core_clear_tx_queue(list_node_t **head, int endpoint_id); +static void proc_ack(endpoint_t *endpoint, uint8_t ack); +static void send_ack(endpoint_t *endpoint); +static void retry_frame(endpoint_t *endpoint); +static bool is_seq_valid(uint8_t seq, uint8_t ack); +static endpoint_t *find_endpoint(uint8_t endpoint_number); +static void transmit_reject(endpoint_t *endpoint, uint8_t address, uint8_t ack, reject_reason_t reason); +static void stop_retry_timer(endpoint_t *endpoint); +static void start_retry_timer(endpoint_t *endpoint, struct timespec offset); +static void core_push_frame_to_hal(const void *frame, size_t frame_len); +static bool core_pull_frame_from_hal(frame_t **frame_buf, size_t *frame_buf_len); +static status_t core_push_data_to_server(uint8_t ep_id, const void *data, size_t data_len); +static void core_fetch_secondary_debug_counters(hal_epoll_event_data_t *event_data); + +/******************************************************************************* + ************************** IMPLEMENTATION ******************************** + ******************************************************************************/ + +typedef union +{ + uint8_t bytes[2]; + uint16_t uint16; +}uint16_u; + +static inline uint16_t __hdlc_get_hcs(const uint8_t *header_buf) +{ + uint16_u u; + u.bytes[0] = header_buf[HDLC_HCS_POS]; + u.bytes[1] = header_buf[HDLC_HCS_POS + 1]; + return le16_to_cpu(u.uint16); +} + +static inline bool __hdlc_is_poll_final(uint8_t control) { return (control & (1 << HDLC_CONTROL_P_F_POS))? true: false; } + +static inline void __hdlc_set_ctrl_ack(uint8_t *control, + uint8_t ack) +{ + *control = (uint8_t)(*control & ~0x03); + *control |= ack; +} + + +static status_t state_passer(ez_err_t val) { return (val == NO_ERROR)? STATUS_OK : STATUS_FAIL; } + +ep_state_t core_endpoint_state(uint8_t state) +{ + #define STATE_FREED 6 // State freed, internal to Secondary + + switch (state) + { + case ENDPOINT_STATE_OPEN: + case ENDPOINT_STATE_CLOSED: + case ENDPOINT_STATE_CLOSING: + case ENDPOINT_STATE_ERROR_DEST_UNREACH: + case ENDPOINT_STATE_ERROR_FAULT: + return state; + case STATE_FREED: + return ENDPOINT_STATE_CLOSED; + default: + log_crash("A new state (%d) has been added to the Secondary that has no equivalent on the daemon.", state); + } + return state; +} + +const char *core_stringify_state(ep_state_t state) +{ + switch (state) + { + case ENDPOINT_STATE_OPEN: + return ENUM_TO_STR(ENDPOINT_STATE_OPEN); + case ENDPOINT_STATE_CLOSED: + return ENUM_TO_STR(ENDPOINT_STATE_CLOSED); + case ENDPOINT_STATE_CLOSING: + return ENUM_TO_STR(ENDPOINT_STATE_CLOSING); + case ENDPOINT_STATE_ERROR_DEST_UNREACH: + return ENUM_TO_STR(ENDPOINT_STATE_ERROR_DEST_UNREACH); + case ENDPOINT_STATE_ERROR_FAULT: + return ENUM_TO_STR(ENDPOINT_STATE_ERROR_FAULT); + default: + log_crash("A new state (%d) has been added to the Secondary that has no equivalent on the daemon.", state); + } + return ENUM_TO_STR(state); +} + +static void disconnect_notification_callback(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + (void)property_length; + (void)property_value; + + uint8_t ep_id = ((uint8_t)(property_id & 0x000000FF)); + + CHECK_ERROR(core_endpoints[ep_id].state == ENDPOINT_STATE_OPEN); + + switch (status) + { + case STATUS_IN_PROGRESS: + case STATUS_OK: + log_info("Disconnection notification received for ep#%d", ep_id); + core_set_endpoint_state(ep_id, ENDPOINT_STATE_CLOSED); + break; + + case STATUS_TIMEOUT: + case STATUS_ABORT: + core_set_endpoint_in_error(ep_id, ENDPOINT_STATE_ERROR_DEST_UNREACH); + log_warn("Failed to receive disconnection notification for ep#%d", ep_id); + break; + default: + log_error("Unknown status during disconnection notification"); + break; + } +} + +static void core_calculate_retry_timeout(endpoint_t *endpoint) +{ + static bool first_rtt_measurement = true; + struct timespec current_time = {0}; + int64_t current_timestamp_ms = 0; + int64_t previous_timestamp_ms = 0; + long round_trip_time_ms = 0; + long rto = 0; + + const uint8_t k = 4; + + CHECK_ERROR(endpoint == NULL); + + clock_gettime(CLOCK_MONOTONIC, ¤t_time); + + current_timestamp_ms = (current_time.tv_sec * 1000) + (current_time.tv_nsec / 1000000); + previous_timestamp_ms = (endpoint->last_iframe_sent_timestamp.tv_sec * 1000) + (endpoint->last_iframe_sent_timestamp.tv_nsec / 1000000); + round_trip_time_ms = (long)(current_timestamp_ms - previous_timestamp_ms); + + if (round_trip_time_ms <= 0) + { + round_trip_time_ms = 1; + } + CHECK_ERROR(round_trip_time_ms < 0); + + if (first_rtt_measurement) + { + endpoint->smoothed_rtt = round_trip_time_ms; + endpoint->rtt_variation = round_trip_time_ms / 2; + first_rtt_measurement = false; + } + else + { + // RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'| where beta is 0.25 + endpoint->rtt_variation = 3 * (endpoint->rtt_variation / 4) + ABS(endpoint->smoothed_rtt - round_trip_time_ms) / 4; + + //SRTT <- (1 - alpha) * SRTT + alpha * R' where alpha is 0.125 + endpoint->smoothed_rtt = 7 * (endpoint->smoothed_rtt / 8) + round_trip_time_ms / 8; + } + + if (endpoint->rtt_variation < MIN_RE_TRANSMIT_TIMEOUT_MINIMUM_VARIATION_MS) + { + endpoint->rtt_variation = MIN_RE_TRANSMIT_TIMEOUT_MINIMUM_VARIATION_MS; + } + rto = endpoint->smoothed_rtt + k * endpoint->rtt_variation; + CHECK_ERROR(rto <= 0); + + if (rto > MAX_RE_TRANSMIT_TIMEOUT_MS) + { + rto = MAX_RE_TRANSMIT_TIMEOUT_MS; + } + else if (rto < MIN_RE_TRANSMIT_TIMEOUT_MS) + { + rto = MIN_RE_TRANSMIT_TIMEOUT_MS; + } + endpoint->retry_timeout_ms = rto; +} + +void core_init(int hal_fd, int hal_notify_fd) +{ + hal_sock_fd = hal_fd; + hal_sock_notify_fd = hal_notify_fd; + size_t i = 0; + + for (i = 0; i < EP_MAX_COUNT; i++) + { + core_endpoints[i].id = (uint8_t)i; + core_endpoints[i].state = ENDPOINT_STATE_CLOSED; + core_endpoints[i].ack = 0; + core_endpoints[i].configured_tx_win_size = 1; + core_endpoints[i].current_tx_window_space = 1; + core_endpoints[i].retry_timer_data = NULL; + core_endpoints[i].on_uframe_data_reception = NULL; + core_endpoints[i].on_iframe_data_reception = NULL; + core_endpoints[i].last_iframe_sent_timestamp = (struct timespec){0}; + core_endpoints[i].smoothed_rtt = 0; + core_endpoints[i].rtt_variation = 0; + core_endpoints[i].retry_timeout_ms = MAX_RE_TRANSMIT_TIMEOUT_MS; + core_endpoints[i].packet_retry_count = 0; + } + + static hal_epoll_event_data_t event[2] = {0}; + + event[0].callback = core_proc_rx_hal; + event[0].file_descriptor = hal_fd; + event[0].endpoint_number = 0; + hal_epoll_register(&event[0]); + + event[1].callback = core_proc_rx_hal_notification; + event[1].file_descriptor = hal_notify_fd; + event[1].endpoint_number = 0; + hal_epoll_register(&event[1]); + + + if (config.stats_interval > 0) + { + int ret = 0; + struct itimerspec timeout_time = {0}; + hal_epoll_event_data_t *event_epoll = NULL; + + // log_info("timeout: %d\r\n", config.stats_interval); + timeout_time.it_interval.tv_sec = config.stats_interval; + timeout_time.it_interval.tv_nsec = 0; + timeout_time.it_value.tv_sec = config.stats_interval; + timeout_time.it_value.tv_nsec = 0; + + timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + CHECK_ERROR(timer_fd < 0); + ret = timerfd_settime(timer_fd, 0, &timeout_time, NULL); + CHECK_ERROR(ret < 0); + + event_epoll = (hal_epoll_event_data_t *)calloc(1, sizeof(hal_epoll_event_data_t)); + CHECK_ERROR(event_epoll == NULL); + + event_epoll->callback = core_fetch_secondary_debug_counters; + event_epoll->file_descriptor = timer_fd; + hal_epoll_register(event_epoll); + } + + list_init(&pending_on_tx_complete); +} + +void core_process_transmit_queue(void) +{ + do + { + if (transmit_queue == NULL && pending_on_security_ready_queue == NULL) break; + if (!core_proc_tx_data()) break; + } while(1); +} + +ep_state_t core_get_endpoint_state(uint8_t ep_id) +{ + CHECK_ERROR(ep_id == 0); + return core_endpoints[ep_id].state; +} + +void core_set_endpoint_state(uint8_t ep_id, ep_state_t state) +{ + if (core_endpoints[ep_id].state != state) + { + log_info("Changing ep#%d state from %s to %s", ep_id, core_stringify_state(core_endpoints[ep_id].state), core_stringify_state(state)); + core_endpoints[ep_id].state = state; + EP_set_state(ep_id, state); + } +} + +bool core_get_endpoint_encryption(uint8_t ep_id) +{ + (void)ep_id; + return false; +} + +static void cpcd_update_secondary_debug_counter(sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status) +{ + (void)handle; + + if (status == STATUS_TIMEOUT) + { + log_warn("Secondary counters query timed out"); + return; + } + else if (status == STATUS_ABORT) + { + log_warn("Secondary counters query aborted"); + return; + } + if (status != STATUS_OK && status != STATUS_IN_PROGRESS) log_crash("Exit"); + if (property_id == PROP_LAST_STATUS) log_error("Secondary does not handle the DEBUG_COUNTERS property, please update secondary or disable print-stats"); + CHECK_ERROR(property_id != PROP_EZMESHD_DEBUG_COUNTERS); + CHECK_ERROR(property_value == NULL || property_length > sizeof(dbg_cts_t)); + + memcpy(&secondary_cpcd_debug_counters, property_value, property_length); +} + +static void core_fetch_secondary_debug_counters(hal_epoll_event_data_t *event_data) +{ + int fd_timer = 0; + uint64_t expiration = 0; + + fd_timer = event_data->file_descriptor; + CHECK_ERROR(read(fd_timer, &expiration, sizeof(expiration)) < 0); + sys_param_get(cpcd_update_secondary_debug_counter, PROP_EZMESHD_DEBUG_COUNTERS, 0, 0, false); +} + +static void core_proc_rx_hal_notification(hal_epoll_event_data_t *event_data) +{ + uint8_t frame_type = 0; + list_node_t *node = NULL; + transmit_queue_item_t *item = NULL; + buffer_handle_t *frame = NULL; + struct timespec tx_complete_timestamp = {0}; + ssize_t ret = 0; + + (void)event_data; + + ret = recv(hal_sock_notify_fd, &tx_complete_timestamp, sizeof(tx_complete_timestamp), MSG_DONTWAIT); + + if (ret == 0) + { + int ret_close = 0; + + log_info("Driver closed the notification socket"); + ret_close = close(event_data->file_descriptor); + CHECK_ERROR(ret_close != 0); + return; + } + CHECK_ERROR(ret < 0); + + node = list_pop(&pending_on_tx_complete); + item = SLIST_ENTRY(node, transmit_queue_item_t, node); + CHECK_ERROR(item == NULL); + + frame = item->handle; + frame->pending_tx_complete = false; + + frame_type = frame->control >> HDLC_CONTROL_FRAME_TYPE_POS; + if (frame_type == 1 || frame_type == 0) + { + frame_type = HDLC_FRAME_TYPE_IFRAME; + } + + switch (frame_type) + { + case HDLC_FRAME_TYPE_IFRAME: + if (frame->endpoint->state != ENDPOINT_STATE_OPEN) core_clear_tx_queue(&core_endpoints[frame->endpoint->id].retry_queue, -1); + else + { + if (frame->endpoint->packet_retry_count == 0u) frame->endpoint->last_iframe_sent_timestamp = tx_complete_timestamp; + if (frame->endpoint->retry_queue != NULL && frame->acked == false) start_retry_timer(frame->endpoint, tx_complete_timestamp); + if (frame->acked) proc_ack(frame->endpoint, frame->pending_ack); + } + break; + + case HDLC_FRAME_TYPE_UFRAME: + case HDLC_FRAME_TYPE_SFRAME: + if (frame->data_length != 0) free((void *)frame->data); + free(frame->hdlc_header); + free(frame); + break; + + default: + log_crash("Exit"); + break; + } + + // log_info("4"); + // free(item); +} + +static void core_proc_rx_hal(hal_epoll_event_data_t *event_data) +{ + frame_t *rx_frame = NULL; + size_t frame_size = 0; + uint16_t hcs = 0; + uint16_t data_length = 0; + uint8_t address = 0; + uint8_t control = 0; + uint8_t type = 0; + uint8_t ack = 0; + endpoint_t *endpoint = NULL; + + (void)event_data; + + if (core_pull_frame_from_hal(&rx_frame, &frame_size) == false) return; + + hcs = __hdlc_get_hcs(rx_frame->header); + + if (!core_check_crc_sw(rx_frame->header, HDLC_HEADER_SIZE, hcs)) + { + // log_info_INVALID_HEADER_CHECKSUM(); + free(rx_frame); + return; + } + + data_length = rx_frame->header[HDLC_LENGTH_POS] | (rx_frame->header[HDLC_LENGTH_POS + 1] << 8); + address = rx_frame->header[HDLC_ADDRESS_POS]; + control = rx_frame->header[HDLC_CONTROL_POS]; + type = control >> HDLC_CONTROL_FRAME_TYPE_POS; + if (type == 1 || type == 0) + { + type = HDLC_FRAME_TYPE_IFRAME; + } + ack = control & 0x03; + + CHECK_ERROR(data_length != frame_size - HDLC_HEADER_RAW_SIZE); + + endpoint = find_endpoint(address); + + if (endpoint->state != ENDPOINT_STATE_OPEN) + { + if (type != HDLC_FRAME_TYPE_SFRAME) transmit_reject(NULL, address, 0, HDLC_REJECT_UNREACHABLE_ENDPOINT); + free(rx_frame); + return; + } + + if (type == HDLC_FRAME_TYPE_IFRAME || type == HDLC_FRAME_TYPE_SFRAME) proc_ack(endpoint, ack); + + switch (type) + { + case HDLC_FRAME_TYPE_IFRAME:{ + core_proc_rx_iframe(rx_frame); + break;} + case HDLC_FRAME_TYPE_SFRAME:{ + core_proc_rx_sframe(rx_frame); + break;} + case HDLC_FRAME_TYPE_UFRAME:{ + core_proc_rx_uframe(rx_frame); + break;} + default:{ + transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_ERROR); + log_info("[Core] EP #%u: rxd S-frame dropped", endpoint->id); + break;} + } + + free(rx_frame); +} + +bool core_endpoint_is_closing(uint8_t ep_id) { return (core_endpoints[ep_id].state == ENDPOINT_STATE_CLOSING); } + +void core_process_endpoint_change(uint8_t endpoint_number, ep_state_t ep_state) +{ + if (ep_state != ENDPOINT_STATE_OPEN) + { + core_close_endpoint(endpoint_number, true, false); + return ; + } + if (core_endpoints[endpoint_number].state != ENDPOINT_STATE_OPEN) core_open_endpoint(endpoint_number, 0, 1); + return; +} + +bool core_ep_is_busy(uint8_t ep_id) { return (core_endpoints[ep_id].holding_list != NULL); } + +static void core_proc_rx_iframe(frame_t *rx_frame) +{ + endpoint_t *endpoint = NULL; + uint8_t address = 0; + uint16_t payload_length = 0; + uint16_t fcs = 0; + uint8_t control = 0; + uint8_t seq = 0; + + address = rx_frame->header[HDLC_ADDRESS_POS]; + endpoint = &core_endpoints[address]; + + log_info("[Core] EP #%u: rxd I-frame", endpoint->id); + + if (endpoint->id != 0 && (endpoint->state != ENDPOINT_STATE_OPEN || EP_list_empty(endpoint->id))) + { + transmit_reject(endpoint, address, 0, HDLC_REJECT_UNREACHABLE_ENDPOINT); + return; + } + + payload_length = rx_frame->header[HDLC_LENGTH_POS] | (rx_frame->header[HDLC_LENGTH_POS + 1] << 8); + CHECK_ERROR(payload_length < HDLC_FCS_SIZE); + payload_length = (uint16_t)(payload_length - HDLC_FCS_SIZE); + fcs = rx_frame->payload[payload_length] | (rx_frame->payload[payload_length + 1] << 8); + + if (!core_check_crc_sw(rx_frame->payload, payload_length, fcs)) + { + log_warn("payload_length: %d, fcs: %04X", payload_length, fcs); + transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_CHECKSUM_MISMATCH); + // log_info_INVALID_PAYLOAD_CHECKSUM(); + return; + } + + control = rx_frame->header[HDLC_CONTROL_POS]; + seq = (control >> HDLC_CONTROL_SEQ_POS) & 0x03; + + if (seq == endpoint->ack) + { + if (control & (1 << HDLC_CONTROL_P_F_POS)) + { + CHECK_ERROR(endpoint->id != 0); + CHECK_ERROR(endpoint->poll_final.on_final == NULL); + endpoint->poll_final.on_final(endpoint->id, (void *)HDLC_FRAME_TYPE_IFRAME, rx_frame->payload, payload_length); + } + else + { + if (endpoint->id == EP_SYSTEM) + { + if (endpoint->on_iframe_data_reception != NULL) endpoint->on_iframe_data_reception(endpoint->id, rx_frame->payload, payload_length); + } + else + { + status_t status = core_push_data_to_server(endpoint->id, rx_frame->payload, payload_length); + if (status == STATUS_FAIL) + { + core_close_endpoint(endpoint->id, true, false); + return; + } + else if (status == STATUS_WOULD_BLOCK) + { + transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_OUT_OF_MEMORY); + return; + } + } + } + + log_info("[Core] EP #%u: rxd I-frame queued", endpoint->id); + endpoint->ack++; + endpoint->ack %= 4; + send_ack(endpoint); + } + else if (is_seq_valid(seq, endpoint->ack)) + { + log_info("EP #%u: rxd duplicate I-frame", endpoint->id); + send_ack(endpoint); + } + else + { + transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_SEQUENCE_MISMATCH); + return; + } +} + +static void core_proc_rx_sframe(frame_t *rx_frame) +{ + endpoint_t *endpoint = NULL; + bool fatal_error = false; + ep_state_t new_state = 0; + uint8_t sframe_function = 0; + uint8_t address = 0; + uint8_t control = 0; + uint16_t data_length = 0; + reject_reason_t reason = 0; + + address = rx_frame->header[HDLC_ADDRESS_POS]; + endpoint = find_endpoint(address); + new_state = endpoint->state; + control = rx_frame->header[HDLC_CONTROL_POS]; + sframe_function = (control >> HDLC_CONTROL_SFRAME_FUNCTION_ID_POS) & 0x03; + data_length = rx_frame->header[HDLC_LENGTH_POS] | (rx_frame->header[HDLC_LENGTH_POS + 1] << 8); + data_length = (data_length > 2) ? (uint16_t)(data_length - 2) : 0; + log_info("[Core] EP #%u: rxd S-frame", endpoint->id); + + switch (sframe_function) + { + case HDLC_ACK_SFRAME_FUNCTION:{ + log_info("[Core] EP #%u: rxd S-frame processed", endpoint->id); + break;} + + case HDLC_REJECT_SFRAME_FUNCTION:{ + log_info("[Core] EP #%u: rxd S-frame rejected", endpoint->id); + CHECK_ERROR(data_length != HDLC_REJECT_PAYLOAD_SIZE); + + reason = *((reject_reason_t *)rx_frame->payload); + switch (reason) + { + case HDLC_REJECT_SEQUENCE_MISMATCH: + // This is not a fatal error when the tx window is > 1 + fatal_error = true; + new_state = ENDPOINT_STATE_ERROR_FAULT; + log_info("[Core] EP #%u: rxd reject seq mismatch", endpoint->id); + log_warn("Sequence mismatch on endpoint #%d", endpoint->id); + break; + + case HDLC_REJECT_CHECKSUM_MISMATCH: + if (endpoint->retry_queue != NULL) retry_frame(endpoint); + log_info("[Core] EP #%u: rxd reject checksum mismatch", endpoint->id); + log_warn("Remote received a packet with an invalid checksum"); + break; + + case HDLC_REJECT_OUT_OF_MEMORY: + log_info("[Core] EP #%u: rxd reject out of memory", endpoint->id); + break; + + case HDLC_REJECT_UNREACHABLE_ENDPOINT: + fatal_error = true; + new_state = ENDPOINT_STATE_ERROR_DEST_UNREACH; + log_info("[Core] EP #%u: rxd reject destination unreachable", endpoint->id); + log_warn("Unreachable endpoint #%d", endpoint->id); + break; + + case HDLC_REJECT_ERROR: + default: + fatal_error = true; + new_state = ENDPOINT_STATE_ERROR_FAULT; + log_info("[Core] EP #%u: rxd reject fault", endpoint->id); + log_warn("Endpoint #%d fault", endpoint->id); + break; + } + break;} + + default:{ + log_crash("Illegal switch"); + break;} + } + + if (fatal_error) + { + log_warn("Fatal error %d, endoint #%d is in error.", reason, endpoint->id); + core_set_endpoint_in_error(endpoint->id, new_state); + } +} + +static void core_proc_rx_uframe(frame_t *rx_frame) +{ + uint16_t payload_length = 0; + uint8_t type = 0; + endpoint_t *endpoint = NULL; + uint8_t address = 0; + uint8_t control = 0; + uint16_t fcs = 0; + + address = rx_frame->header[HDLC_ADDRESS_POS]; + endpoint = find_endpoint(address); + log_info("EP #%u: rxd U-frame", endpoint->id); + + control = rx_frame->header[HDLC_CONTROL_POS]; + type = (control >> HDLC_CONTROL_UFRAME_TYPE_POS) & HDLC_CONTROL_UFRAME_TYPE_MASK; + + payload_length = rx_frame->header[HDLC_LENGTH_POS] | (rx_frame->header[HDLC_LENGTH_POS + 1] << 8); + payload_length = (payload_length < 2) ? 0 : (uint16_t)(payload_length - HDLC_FCS_SIZE); + + if (payload_length > 0) + { + fcs = rx_frame->payload[payload_length] | (rx_frame->payload[payload_length + 1] << 8); + + if (!core_check_crc_sw(rx_frame->payload, payload_length, fcs)) + { + // log_info_INVALID_PAYLOAD_CHECKSUM(); + log_info("[Core] EP #%d: U-frame dropped : Bad payload checksum", ((endpoint == NULL) ? -1 : (signed)endpoint->id)); + return; + } + } + if (!(endpoint->flags & OPEN_EP_FLAG_UFRAME_ENABLE)) + { + log_info("[Core] EP #%d: U-frame dropped : U-Frame not enabled on endoint", ((endpoint == NULL) ? -1 : (signed)endpoint->id)); + return; + } + + if ((type == HDLC_CONTROL_UFRAME_TYPE_INFORMATION) && + (endpoint->flags & OPEN_EP_FLAG_UFRAME_INFORMATION_DISABLE)) + { + log_info("[Core] EP #%d: U-frame dropped : Information U-Frame not enabled on endpoint", ((endpoint == NULL) ? -1 : (signed)endpoint->id)); + return; + } + + switch (type) + { + case HDLC_CONTROL_UFRAME_TYPE_INFORMATION:{ + if (endpoint->on_uframe_data_reception != NULL) endpoint->on_uframe_data_reception(endpoint->id, rx_frame->payload, payload_length); + break;} + + case HDLC_CONTROL_UFRAME_TYPE_POLL_FINAL: + if (endpoint->id != EP_SYSTEM) log_error("Received an unnumbered final frame but it was not addressed to the system enpoint"); + else if (endpoint->poll_final.on_final != NULL) endpoint->poll_final.on_final(endpoint->id, (void *)HDLC_FRAME_TYPE_UFRAME, rx_frame->payload, payload_length); + else log_crash("Exit"); + break; + + case HDLC_CONTROL_UFRAME_TYPE_ACKNOWLEDGE: + CHECK_ERROR(endpoint->id != EP_SYSTEM); + sys_ep_no_found_ack(); + break; + + default: + log_info("[Core] EP #%d: U-frame dropped : U-Frame not enabled on endpoint", ((endpoint == NULL) ? -1 : (signed)endpoint->id)); + return; + } + + log_info("[Core] EP #%u: U-frame processed", endpoint->id); +} + +void core_write(uint8_t endpoint_number, const void *message, size_t message_len, uint8_t flags) +{ + endpoint_t *endpoint = NULL; + buffer_handle_t *buffer_handle = NULL; + transmit_queue_item_t *transmit_queue_item = NULL; + bool iframe = true; + bool poll = (flags & FLAG_INFORMATION_POLL) ? true : false; + uint8_t type = HDLC_CONTROL_UFRAME_TYPE_UNKNOWN; + void *payload = NULL; + uint16_t fcs = 0; + + CHECK_ERROR(message_len > UINT16_MAX); + + endpoint = find_endpoint(endpoint_number); + + if (endpoint->state != ENDPOINT_STATE_OPEN) + { + log_warn("Tried to write on closed endpoint #%d", endpoint_number); + return; + } + + if ((flags & FLAG_UFRAME_INFORMATION) || (flags & FLAG_UFRAME_RESET_COMMAND) || (flags & FLAG_UFRAME_POLL)) + { + CHECK_ERROR(!(endpoint->flags & OPEN_EP_FLAG_UFRAME_ENABLE)); + iframe = false; + if (flags & FLAG_UFRAME_INFORMATION)type = HDLC_CONTROL_UFRAME_TYPE_INFORMATION; + else if (flags & FLAG_UFRAME_RESET_COMMAND) type = HDLC_CONTROL_UFRAME_TYPE_RESET_SEQ; + else if ((flags & FLAG_UFRAME_POLL)) type = HDLC_CONTROL_UFRAME_TYPE_POLL_FINAL; + } + else CHECK_ERROR(endpoint->flags & OPEN_EP_FLAG_IFRAME_DISABLE); + + do + { + buffer_handle = (buffer_handle_t *)calloc(1, sizeof(buffer_handle_t)); + CHECK_ERROR(buffer_handle == NULL); + + payload = calloc(1, message_len); + CHECK_ERROR(payload == NULL); + memcpy(payload, message, message_len); + + buffer_handle->data = payload; + buffer_handle->data_length = (uint16_t)message_len; + buffer_handle->endpoint = endpoint; + buffer_handle->address = endpoint_number; + + if (iframe) + { + uint8_t control = 0; + + control = HDLC_FRAME_TYPE_IFRAME << HDLC_CONTROL_FRAME_TYPE_POS; + control |= (uint8_t)(endpoint->seq << HDLC_CONTROL_SEQ_POS); + control |= endpoint->ack; + control |= (uint8_t)((uint8_t)poll << HDLC_CONTROL_P_F_POS); + buffer_handle->control = control; + endpoint->seq++; + endpoint->seq %= 4; + log_info("Sequence # is now %d on ep %d", endpoint->seq, endpoint->id); + } + else + { + CHECK_ERROR(type == HDLC_CONTROL_UFRAME_TYPE_UNKNOWN); + + uint8_t control = 0; + + control = HDLC_FRAME_TYPE_UFRAME << HDLC_CONTROL_FRAME_TYPE_POS; + control |= type << HDLC_CONTROL_UFRAME_TYPE_POS; + + buffer_handle->control = control; + } + + fcs = core_get_crc_sw(message, (uint16_t)message_len); + + buffer_handle->fcs[0] = (uint8_t)fcs; + buffer_handle->fcs[1] = (uint8_t)(fcs >> 8); + } while(0); + + transmit_queue_item = (transmit_queue_item_t *)calloc(1, sizeof(transmit_queue_item_t)); + CHECK_ERROR(transmit_queue_item == NULL); + + transmit_queue_item->handle = buffer_handle; + + if (iframe == false) + { + list_push_back(&transmit_queue, &transmit_queue_item->node); + core_process_transmit_queue(); + } + else if (endpoint->current_tx_window_space <= 0) list_push_back(&endpoint->holding_list, &transmit_queue_item->node); + else + { + endpoint->current_tx_window_space--; + list_push_back(&transmit_queue, &transmit_queue_item->node); + core_process_transmit_queue(); + } +} + +void core_open_endpoint(uint8_t endpoint_number, uint8_t flags, uint8_t tx_win_size) +{ + endpoint_t *ep = NULL; + ep_state_t previous_state = 0; + int timer_fd = 0; + hal_epoll_event_data_t *event = NULL; + + CHECK_ERROR(tx_win_size < TRANSMIT_WINDOW_MIN_SIZE); + CHECK_ERROR(tx_win_size > TRANSMIT_WINDOW_MAX_SIZE); + + ep = &core_endpoints[endpoint_number]; + + if (ep->state != ENDPOINT_STATE_CLOSED) + { + log_crash("Endpoint already opened"); + return; + } + + previous_state = ep->state; + memset(ep, 0x00, sizeof(endpoint_t)); + ep->state = previous_state; + core_set_endpoint_state(endpoint_number, ENDPOINT_STATE_OPEN); + + ep->id = endpoint_number; + ep->flags = flags; + ep->configured_tx_win_size = tx_win_size; + ep->current_tx_window_space = ep->configured_tx_win_size; + ep->retry_timeout_ms = MIN_RE_TRANSMIT_TIMEOUT_MS; + + timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + CHECK_ERROR(timer_fd < 0); + + + event = (hal_epoll_event_data_t *)calloc(1, sizeof(hal_epoll_event_data_t)); + CHECK_ERROR(event == NULL); + ep->retry_timer_data = event; + event->callback = core_proc_endpoint_timeout; + event->file_descriptor = timer_fd; + event->endpoint_number = endpoint_number; + hal_epoll_register(event); + + list_init(&ep->retry_queue); + list_init(&ep->holding_list); + + // log_info_OPEN_ENDPOINT(ep->id); + return; +} + +void core_set_endpoint_in_error(uint8_t endpoint_number, ep_state_t new_state) +{ + if (endpoint_number == 0) + { + log_warn("System endpoint in error, new state: %s. Restarting it.", core_stringify_state(new_state)); + sys_sequence_reset(); + } + else + { + log_warn("Setting ep#%d in error, new state: %s", endpoint_number, core_stringify_state(new_state)); + EP_close(endpoint_number, true); + core_close_endpoint(endpoint_number, false, false); + core_set_endpoint_state(endpoint_number, new_state); + } +} + +void core_reset_endpoint_sequence(uint8_t endpoint_number) +{ + core_endpoints[endpoint_number].seq = 0; + core_endpoints[endpoint_number].ack = 0; +} + +static void core_clear_tx_queue(list_node_t **head, int endpoint_id) +{ + list_node_t *current_node = NULL; + list_node_t *next_node = NULL; + bool filter_with_endpoint_id = false; + uint8_t ep_id = 0; + + if (!*head) return; + + if (endpoint_id < 0) filter_with_endpoint_id = false; + else + { + filter_with_endpoint_id = true; + ep_id = (uint8_t)endpoint_id; + } + + current_node = *head; + + while (current_node) + { + next_node = current_node->node; + + transmit_queue_item_t *item = SLIST_ENTRY(current_node, transmit_queue_item_t, node); + if (!filter_with_endpoint_id + || (filter_with_endpoint_id && item->handle->address == ep_id)) + { + if (item->handle->pending_tx_complete == false) + { + free(item->handle->hdlc_header); + if (item->handle->data_length != 0) free((void *)item->handle->data); + free(item->handle); + list_remove(head, &item->node); + free(item); + } + } + + current_node = next_node; + } +} + +status_t core_close_endpoint(uint8_t endpoint_number, bool notify_secondary, bool force_close) +{ + endpoint_t *ep = NULL; + ep = find_endpoint(endpoint_number); + CHECK_ERROR(ep->state == ENDPOINT_STATE_CLOSED); + log_info("Closing endpoint #%d", endpoint_number); + stop_retry_timer(ep); + + core_clear_tx_queue(&ep->retry_queue, -1); + core_clear_tx_queue(&ep->holding_list, -1); + core_clear_tx_queue(&transmit_queue, endpoint_number); + core_clear_tx_queue(&pending_on_security_ready_queue, endpoint_number); + + if (notify_secondary) + { + core_set_endpoint_state(ep->id, ENDPOINT_STATE_CLOSING); + sys_param_set(disconnect_notification_callback, 5, /* 5 retries */ 100000, /* 100ms between retries*/ + EP_ID_TO_PROPERTY_STATE(ep->id), &ep->state, sizeof(ep_state_t), false); + } + + if (ep->retry_timer_data != NULL) + { + hal_epoll_unregister(ep->retry_timer_data); + close(((hal_epoll_event_data_t *)ep->retry_timer_data)->file_descriptor); + free(ep->retry_timer_data); + ep->retry_timer_data = NULL; + } + + if (force_close) + { + core_set_endpoint_state(ep->id, ENDPOINT_STATE_CLOSED); + // log_trace_CLOSE_ENDPOINT(ep->id); + } + + return STATUS_OK; +} + +void core_set_endpoint_option(uint8_t endpoint_number, + endpoint_option_t option, + void *value) +{ + endpoint_t *ep = NULL; + + ep = &core_endpoints[endpoint_number]; + CHECK_ERROR(ep->state != ENDPOINT_STATE_OPEN); + + switch (option) + { + case EP_ON_IFRAME_RECEIVE:{ + ep->on_iframe_data_reception = (on_data_reception_t)value; + break;} + + case EP_ON_UFRAME_RECEIVE:{ + ep->on_uframe_data_reception = (on_data_reception_t)value; + break;} + + case EP_ON_FINAL:{ + ep->poll_final.on_final = value; + break;} + + case EP_ON_POLL_ARG: + case EP_ON_FINAL_ARG:{ + ep->poll_final.on_fnct_arg = value; + break;} + + case EP_ON_POLL: + case EP_ON_IFRAME_RECEIVE_ARG: + case EP_ON_UFRAME_RECEIVE_ARG: + case EP_ON_IFRAME_WRITE_COMPLETED: + case EP_ON_IFRAME_WRITE_COMPLETED_ARG: + case EP_ON_UFRAME_WRITE_COMPLETED: + case EP_ON_UFRAME_WRITE_COMPLETED_ARG: + default:{ + log_crash("invalid option"); + break;} + } +} + +static void proc_ack(endpoint_t *endpoint, uint8_t ack) +{ + transmit_queue_item_t *item = NULL; + list_node_t *item_node = NULL; + buffer_handle_t *frame = NULL; + uint8_t control = 0; + uint8_t seq_number = 0; + uint8_t ack_range_min = 0; + uint8_t ack_range_max = 0; + uint8_t frames_count_ack = 0; + + if (endpoint->retry_queue == NULL) return; + item = SLIST_ENTRY(endpoint->retry_queue, transmit_queue_item_t, node); + frame = item->handle; + + control = ((uint8_t *)frame->hdlc_header)[HDLC_CONTROL_POS]; + seq_number = (control >> HDLC_CONTROL_SEQ_POS) & 0x03; + + ack_range_min = (uint8_t)(seq_number + 1); + ack_range_min %= 4; + ack_range_max = (uint8_t)(seq_number + endpoint->frames_count_retry_queue); + ack_range_max %= 4; + + if (ack_range_max >= ack_range_min) + { + if (ack < ack_range_min || ack > ack_range_max) return; + } + else if (ack > ack_range_max && ack < ack_range_min) return; + + if (ack > seq_number) frames_count_ack = (uint8_t)(ack - seq_number); + else + { + frames_count_ack = (uint8_t)(4 - seq_number); + frames_count_ack = (uint8_t)(frames_count_ack + ack); + } + stop_retry_timer(endpoint); + + if (frame->pending_tx_complete == true) + { + frame->acked = true; + frame->pending_ack = ack; + return; + } + + endpoint->packet_retry_count = 0u; + + log_info("%d Received ack %d seq number %d", endpoint->id, ack, seq_number); + core_calculate_retry_timeout(endpoint); + + for (uint8_t i = 0; i < frames_count_ack; i++) + { + item_node = list_pop(&endpoint->retry_queue); + CHECK_ERROR(item_node == NULL); + + item = SLIST_ENTRY(item_node, transmit_queue_item_t, node); + frame = item->handle; + control = ((uint8_t *)frame->hdlc_header)[HDLC_CONTROL_POS]; + + uint8_t type = 0; + + type = frame->control >> HDLC_CONTROL_FRAME_TYPE_POS; + if (type == 1 || type == 0) + { + type = HDLC_FRAME_TYPE_IFRAME; + } + CHECK_ERROR(type != HDLC_FRAME_TYPE_IFRAME); + + +#ifdef USE_ON_WRITE_COMPLETE + on_write_completed(endpoint->id, STATUS_OK); +#endif + + if (endpoint->id == EP_SYSTEM && __hdlc_is_poll_final(control)) sys_poll_ack(frame->data); + free((void *)frame->data); + free(frame->hdlc_header); + free(frame); + free(item); + + endpoint->frames_count_retry_queue--; + endpoint->current_tx_window_space++; + + if (endpoint->retry_queue == NULL) break; + } + + while (endpoint->holding_list != NULL && endpoint->current_tx_window_space > 0) + { + list_node_t *item = list_pop(&endpoint->holding_list); + list_push_back(&transmit_queue, item); + endpoint->current_tx_window_space--; + hal_epoll_watch_back(endpoint->id); + } + + log_info("[Core] EP #%u: rxd ack %u", endpoint->id, ack); +} + +static void send_ack(endpoint_t *endpoint) +{ + buffer_handle_t *handle = NULL; + transmit_queue_item_t *item = NULL; + + handle = (buffer_handle_t *)calloc(1, sizeof(buffer_handle_t)); + CHECK_ERROR(handle == NULL); + + handle->endpoint = endpoint; + handle->address = endpoint->id; + uint8_t control = 0; + + control = HDLC_FRAME_TYPE_SFRAME << HDLC_CONTROL_FRAME_TYPE_POS; + control |= (uint8_t)(0 << HDLC_CONTROL_SFRAME_FUNCTION_ID_POS); + control |= endpoint->ack; + handle->control = control; + + item = (transmit_queue_item_t *)calloc(1, sizeof(transmit_queue_item_t)); + CHECK_ERROR(item == NULL); + + item->handle = handle; + + list_push_back(&transmit_queue, &item->node); + log_info("Endpoint #%d sent ACK: %d", endpoint->id, endpoint->ack); + core_process_transmit_queue(); + log_info("[Core] EP #%u: txd ack", endpoint->id); +} + +static void retry_frame(endpoint_t *endpoint) +{ + transmit_queue_item_t *item = NULL; + list_node_t *item_node = NULL; + + item_node = list_pop(&endpoint->retry_queue); + + CHECK_ERROR(item_node == NULL); + + item = SLIST_ENTRY(item_node, transmit_queue_item_t, node); + + if (item->handle->pending_tx_complete == true) + { + list_push(&endpoint->retry_queue, &item->node); + return; + } + + // CHECK_ERROR(__hdlc_get_frame_type(item->handle->control) != HDLC_FRAME_TYPE_IFRAME); + uint8_t type = 0; + + type = item->handle->control >> HDLC_CONTROL_FRAME_TYPE_POS; + if (type == 1 || type == 0) + { + type = HDLC_FRAME_TYPE_IFRAME; + } + CHECK_ERROR(type != HDLC_FRAME_TYPE_IFRAME); + + free(item->handle->hdlc_header); + + endpoint->packet_retry_count++; + endpoint->frames_count_retry_queue--; + + list_push(&transmit_queue, &item->node); + + primary_cpcd_debug_counters.retxd_data_frame++; + log_info("[Core] EP #%u: re-txd data frame", endpoint->id); + return; +} + +static void transmit_reject(endpoint_t *endpoint, uint8_t address, uint8_t ack, reject_reason_t reason) +{ + uint16_t fcs = 0; + buffer_handle_t *handle = NULL; + transmit_queue_item_t *item = NULL; + + handle = (buffer_handle_t *)calloc(1, sizeof(buffer_handle_t)); + CHECK_ERROR(handle == NULL); + + handle->address = address; + uint8_t control = 0; + + control = HDLC_FRAME_TYPE_SFRAME << HDLC_CONTROL_FRAME_TYPE_POS; + control |= (uint8_t)(HDLC_REJECT_SFRAME_FUNCTION << HDLC_CONTROL_SFRAME_FUNCTION_ID_POS); + control |= ack; + handle->control = control; + + handle->data = calloc(1, sizeof(uint8_t)); + CHECK_ERROR(handle->data == NULL); + + *((uint8_t *)handle->data) = (uint8_t)reason; + handle->data_length = sizeof(uint8_t); + + fcs = core_get_crc_sw(handle->data, 1); + handle->fcs[0] = (uint8_t)(fcs && 0xFF); + handle->fcs[1] = (uint8_t)(fcs >> 8); + + item = (transmit_queue_item_t *)calloc(1, sizeof(transmit_queue_item_t)); + CHECK_ERROR(item == NULL); + + item->handle = handle; + + list_push_back(&transmit_queue, &item->node); + + if (endpoint != NULL) + { + switch (reason) + { + case HDLC_REJECT_CHECKSUM_MISMATCH:{ + log_error("[Core] EP #%u: txd reject checksum mismatch", endpoint->id); + log_warn("Host received a packet with an invalid checksum on ep %d", endpoint->id); + break;} + + case HDLC_REJECT_SEQUENCE_MISMATCH:{ + log_error("[Core] EP #%u: txd reject seq mismatch", endpoint->id); + break;} + + case HDLC_REJECT_OUT_OF_MEMORY:{ + log_error("[Core] EP #%u: txd reject out of memory", endpoint->id); + break;} + + case HDLC_REJECT_SECURITY_ISSUE:{ + log_error("[Core] EP #%u: txd reject security issue", endpoint->id); + break;} + + case HDLC_REJECT_UNREACHABLE_ENDPOINT:{ + log_error("[Core] EP #%d: txd reject destination unreachable", (endpoint == NULL) ? -1 : (signed)endpoint->id); + break;} + + case HDLC_REJECT_ERROR: + default:{ + log_error("[Core] EP #%u: txd reject fault", endpoint->id); + break;} + } + } + else + { + switch (reason) + { + case HDLC_REJECT_UNREACHABLE_ENDPOINT:{ + // log_info_TXD_REJECT_DESTINATION_UNREACHABLE(); + break;} + + default:{ + log_error("Exit"); + break;} + } + } +} + +static bool core_proc_tx_data(void) +{ + list_node_t *node = NULL; + transmit_queue_item_t *item = NULL; + transmit_queue_item_t *tx_complete_item = NULL; + buffer_handle_t *frame = NULL; + uint16_t total_length = 0; + uint8_t frame_type = 0; + + uint16_t encrypted_data_length = 0; + uint8_t *encrypted_payload = 0; + size_t frame_length = 0; + frame_t *frame_buffer = NULL; + + if (pending_on_security_ready_queue != NULL) + { + log_info("Sending packet that were hold back because security was not ready"); + node = list_pop(&pending_on_security_ready_queue); + } + else + { + if (transmit_queue == NULL) + { + log_info("transmit_queue is empty and cpcd is not ready yet to process hold back packets"); + return false; + } + + node = list_pop(&transmit_queue); + } + + item = SLIST_ENTRY(node, transmit_queue_item_t, node); + frame = item->handle; + + frame->hdlc_header = calloc(1, HDLC_HEADER_RAW_SIZE); + CHECK_ERROR(frame->hdlc_header == NULL); + + total_length = (frame->data_length != 0) ? (uint16_t)(frame->data_length + 2) : 0; + frame_type = frame->control >> HDLC_CONTROL_FRAME_TYPE_POS; + if (frame_type == 1 || frame_type == 0) + { + frame_type = HDLC_FRAME_TYPE_IFRAME; + } + + if (frame_type == HDLC_FRAME_TYPE_IFRAME) __hdlc_set_ctrl_ack(&frame->control, frame->endpoint->ack); + else if (frame_type == HDLC_FRAME_TYPE_UFRAME) CHECK_ERROR(frame->endpoint->id != EP_SYSTEM); + + // log_info("[Core] frame address: %02x", frame->address); + hdlc_create_header(frame->hdlc_header, frame->address, total_length, frame->control); + + encrypted_data_length = frame->data_length; + encrypted_payload = (uint8_t *)frame->data; + frame_length = HDLC_HEADER_RAW_SIZE + total_length; + frame_buffer = (frame_t *)calloc(1, frame_length); + CHECK_ERROR(frame_buffer == NULL); + + memcpy(frame_buffer->header, frame->hdlc_header, HDLC_HEADER_RAW_SIZE); + memcpy(frame_buffer->payload, encrypted_payload, encrypted_data_length); + + if (encrypted_data_length != 0) memcpy(&frame_buffer->payload[encrypted_data_length], frame->fcs, sizeof(frame->fcs)); + frame->pending_tx_complete = true; + tx_complete_item = (transmit_queue_item_t *)malloc(sizeof(transmit_queue_item_t)); + CHECK_ERROR(tx_complete_item == NULL); + tx_complete_item->handle = frame; + + list_push_back(&pending_on_tx_complete, &tx_complete_item->node); + core_push_frame_to_hal(frame_buffer, frame_length); + free(frame_buffer); + if (frame->data != encrypted_payload) free((void *)encrypted_payload); + log_info("[Core] EP #%d: frame transmit submitted", (frame->endpoint == NULL) ? -1 : (signed)frame->endpoint->id); + + if (frame_type == HDLC_FRAME_TYPE_IFRAME) + { + list_push_back(&frame->endpoint->retry_queue, &item->node); + frame->endpoint->frames_count_retry_queue++; + } + else free(item); + return true; +} + +static void retry_timeout(endpoint_t *endpoint) +{ + if (endpoint->packet_retry_count >= RE_TRANSMIT) + { + log_warn("Retransmit limit reached on endpoint #%d", endpoint->id); + core_set_endpoint_in_error(endpoint->id, ENDPOINT_STATE_ERROR_DEST_UNREACH); + } + else + { + endpoint->retry_timeout_ms *= 2; + if (endpoint->retry_timeout_ms > MAX_RE_TRANSMIT_TIMEOUT_MS) endpoint->retry_timeout_ms = MAX_RE_TRANSMIT_TIMEOUT_MS; + log_info("New RTO calculated on ep %d, after re_transmit timeout: %ldms", endpoint->id, endpoint->retry_timeout_ms); + retry_frame(endpoint); + } +} + +static bool is_seq_valid(uint8_t seq, uint8_t ack) { return ((seq == (ack - 1u)) || (ack == 0u && seq == 3u)); } + +static endpoint_t *find_endpoint(uint8_t endpoint_number) { return &core_endpoints[endpoint_number]; } + +static void stop_retry_timer(endpoint_t *endpoint) +{ + hal_epoll_event_data_t *fd_timer_data = NULL; + struct itimerspec cancel_time = {0}; + + fd_timer_data = endpoint->retry_timer_data; + if (fd_timer_data == NULL) return; + + cancel_time.it_interval.tv_sec = 0; + cancel_time.it_interval.tv_nsec = 0; + cancel_time.it_value.tv_sec = 0; + cancel_time.it_value.tv_nsec = 0; + + CHECK_ERROR(timerfd_settime(fd_timer_data->file_descriptor, 0, &cancel_time, NULL) < 0); +} + +static double diff_timespec_ms(const struct timespec *final, const struct timespec *initial) { return (double)((final->tv_sec - initial->tv_sec) * 1000) + (double)(final->tv_nsec - initial->tv_nsec) / 1000000.0; } + +static void start_retry_timer(endpoint_t *endpoint, struct timespec offset) +{ + hal_epoll_event_data_t *fd_timer_data = NULL; + + struct timespec current_timestamp = {0}; + clock_gettime(CLOCK_MONOTONIC, ¤t_timestamp); + + long offset_in_ms = 0; + struct itimerspec timeout_time = {0}; + + + offset_in_ms = (long)diff_timespec_ms(&offset, ¤t_timestamp); + fd_timer_data = endpoint->retry_timer_data; + + if (offset_in_ms < 0) offset_in_ms = 0; + if (endpoint->state != ENDPOINT_STATE_OPEN) return; + CHECK_ERROR(fd_timer_data == NULL); + CHECK_ERROR(fd_timer_data->file_descriptor < 0); + + timeout_time.it_interval.tv_sec = 0; + timeout_time.it_interval.tv_nsec = 0; + timeout_time.it_value.tv_sec = ((offset_in_ms + endpoint->retry_timeout_ms) / 1000); + timeout_time.it_value.tv_nsec = (((offset_in_ms + endpoint->retry_timeout_ms) % 1000) * 1000000); + + CHECK_ERROR(timerfd_settime(fd_timer_data->file_descriptor, 0, &timeout_time, NULL) < 0); +} + +static void core_proc_endpoint_timeout(hal_epoll_event_data_t *event_data) +{ + int fd_timer = 0; + uint8_t endpoint_number = 0; + uint64_t expiration = 0; + + fd_timer = event_data->file_descriptor; + endpoint_number = event_data->endpoint_number; + + CHECK_ERROR(read(fd_timer, &expiration, sizeof(expiration)) < 0); + CHECK_WARN(expiration != 1); + retry_timeout(&core_endpoints[endpoint_number]); +} + +static void core_push_frame_to_hal(const void *frame, size_t frame_len) +{ + ssize_t ret = 0; + + log_info_hexdump("[Core] Push frame to hal (host uart tx): ", frame, frame_len); + ret = send(hal_sock_fd, frame, frame_len, 0); + CHECK_ERROR(ret < 0); + CHECK_ERROR((size_t)ret != frame_len); + // log_info_TXD_TRANSMIT_COMPLETED(); +} + +static bool core_pull_frame_from_hal(frame_t **frame_buf, size_t *frame_buf_len) +{ + size_t datagram_length = 0; + ssize_t retval = 0; + ssize_t ret = 0; + + CHECK_ERROR(retval < 0); + + retval = recv(hal_sock_fd, NULL, 0, MSG_PEEK | MSG_TRUNC | MSG_DONTWAIT); + if (retval == 0) + { + log_info("Driver closed the data socket"); + int ret_close = close(hal_sock_fd); + CHECK_ERROR(ret_close != 0); + return false; + } + + datagram_length = (size_t)retval; + CHECK_ERROR(datagram_length == 0); + CHECK_ERROR(datagram_length < sizeof(frame_t)); + + *frame_buf = (frame_t *)calloc(1, (size_t)datagram_length); + CHECK_ERROR(*frame_buf == NULL); + + ret = recv(hal_sock_fd, *frame_buf, (size_t)datagram_length, 0); + CHECK_ERROR(ret < 0); + CHECK_ERROR((size_t)ret != (size_t)datagram_length); + + *frame_buf_len = (size_t)datagram_length; + + log_info_hexdump("[Core] Pull frame from hal (host uart rx): ", *frame_buf, *frame_buf_len); + + return true; +} + +static status_t core_push_data_to_server(uint8_t ep_id, const void *data, size_t data_len) { return state_passer(EP_push_data(ep_id, (uint8_t *)data, data_len)); } + +uint16_t core_get_crc_sw(const void *buf, uint16_t length) +{ + uint16_t crc = 0; + for (uint16_t i = 0; i < length; i++) crc = core_compute_crc16((uint8_t)((uint8_t *)buf)[i], crc); + return crc; +} + +bool core_check_crc_sw(const void *buf, uint16_t length, uint16_t expected_crc) { return (core_get_crc_sw(buf, length) == expected_crc); } + +uint16_t core_compute_crc16(uint8_t new_byte, uint16_t prev_result) +{ +#if (EZMESH_CRC_0 == 1) + prev_result = ((uint16_t)(prev_result >> 8)) | ((uint16_t)(prev_result << 8)); + prev_result ^= new_byte; + prev_result ^= (prev_result & 0xff) >> 4; + prev_result ^= (uint16_t)(((uint16_t)(prev_result << 8)) << 4); + prev_result ^= ((uint8_t)(((uint8_t)(prev_result & 0xff)) << 5)) + | ((uint16_t)((uint16_t)((uint8_t)(((uint8_t)(prev_result & 0xff)) >> 3)) << 8)); +#else + uint8_t bit; + + for (bit = 0; bit < 8; bit++) + { + prev_result ^= (new_byte & 0x01); + prev_result = (prev_result & 0x01) ? (prev_result >> 1) ^ 0x8408 : (prev_result >> 1); + new_byte = new_byte >> 1; + } +#endif + return prev_result; +} + +void hdlc_create_header(uint8_t *hdr, + uint8_t address, + uint16_t length, + uint8_t control) +{ + uint16_t cal_crc16 = 0; + + hdr[0] = HDLC_FLAG_VAL; + hdr[1] = address; + hdr[2] = (uint8_t)(length & 0xFF); + hdr[3] = (uint8_t)((length >> 8) & 0xFF); + hdr[4] = control; + + cal_crc16 = core_get_crc_sw(hdr, HDLC_HEADER_SIZE); + + hdr[5] = (uint8_t)(cal_crc16 & 0xFF); + hdr[6] = (uint8_t)((cal_crc16 >> 8) & 0xFF); +} \ No newline at end of file diff --git a/module/controller/daemon/hdlc/core.h b/module/controller/daemon/hdlc/core.h index e69de29..3a6c7ce 100644 --- a/module/controller/daemon/hdlc/core.h +++ b/module/controller/daemon/hdlc/core.h @@ -0,0 +1,207 @@ +#ifndef CORE_H +#define CORE_H +#include +#include "library/libezmesh.h" +#include "utility/list.h" +#include "utility/utility.h" +#include "daemon/hdlc/core.h" +#include "daemon/primary/primary.h" + +#include +#include +#include +#include + +#define OPEN_EP_FLAG_IFRAME_DISABLE 0x01 << 0 +#define OPEN_EP_FLAG_UFRAME_ENABLE 0x01 << 1 +#define OPEN_EP_FLAG_UFRAME_INFORMATION_DISABLE 0x01 << 2 +#define FLAG_UFRAME_INFORMATION 0x01 << 1 +#define FLAG_UFRAME_POLL 0x01 << 2 +#define FLAG_UFRAME_RESET_COMMAND 0x01 << 3 +#define FLAG_INFORMATION_POLL 0x01 << 4 +// Maximum number of retry while sending a frame +#define RE_TRANSMIT 10 +#define MAX_RE_TRANSMIT_TIMEOUT_MS 5000 +#define MIN_RE_TRANSMIT_TIMEOUT_MS 50 +#define MIN_RE_TRANSMIT_TIMEOUT_MINIMUM_VARIATION_MS 5 +#define TRANSMIT_WINDOW_MIN_SIZE 1u +#define TRANSMIT_WINDOW_MAX_SIZE 1u +#define VERSION_MAJOR 1u +#define VERSION_MINOR 1u +#define EP_MAX_COUNT 256 + +#define HDLC_FLAG_VAL (0x14) + +#define HDLC_HEADER_SIZE (5) +#define HDLC_HEADER_RAW_SIZE (7) +#define HDLC_FCS_SIZE (2) +#define HDLC_REJECT_PAYLOAD_SIZE (1) +#define HDLC_CONTROL_UFRAME_TYPE_MASK (0x37) +#define HDLC_ACK_SFRAME_FUNCTION (0) +#define HDLC_REJECT_SFRAME_FUNCTION (1) + +// Data Types +typedef void (*on_final_t) (uint8_t endpoint_id, void *arg, void *answer, uint32_t answer_lenght); +typedef struct +{ + void *on_fnct_arg; + on_final_t on_final; +} poll_final_t; +typedef void (*on_data_reception_t) (uint8_t endpoint_id, const void *data, size_t data_len); +/* + * Internal state for the endpoints. Will be filled by cpc_register_endpoint() + */ +typedef struct endpoint +{ + uint8_t id; + uint8_t flags; + uint8_t seq; + uint8_t ack; + uint8_t configured_tx_win_size; + uint8_t current_tx_window_space; + uint8_t frames_count_retry_queue; + uint8_t packet_retry_count; + long retry_timeout_ms; + void *retry_timer_data; + ep_state_t state; + list_node_t *retry_queue; + list_node_t *holding_list; + on_data_reception_t on_uframe_data_reception; + on_data_reception_t on_iframe_data_reception; + poll_final_t poll_final; + struct timespec last_iframe_sent_timestamp; + long smoothed_rtt; + long rtt_variation; +} endpoint_t; + +typedef struct +{ + uint32_t frame_counter; +} security_frame_t; + +typedef struct +{ + void *hdlc_header; + const void *data; + uint16_t data_length; + uint8_t fcs[2]; + uint8_t control; + uint8_t address; + endpoint_t *endpoint; + uint8_t pending_ack; + bool acked; + bool pending_tx_complete; +} buffer_handle_t; + +typedef struct +{ + list_node_t node; + buffer_handle_t *handle; +} transmit_queue_item_t; + +typedef struct +{ + uint8_t header[HDLC_HEADER_RAW_SIZE]; + uint8_t payload[]; // last two bytes are little endian 16bits +} frame_t; + +typedef struct +{ + uint32_t endpoint_opened; + uint32_t endpoint_closed; + uint32_t rxd_frame; + uint32_t txd_reject_destination_unreachable; + uint32_t txd_completed; + uint32_t retxd_data_frame; + uint32_t invalid_header_checksum; + uint32_t invalid_payload_checksum; +} dbg_cts_t; + +extern dbg_cts_t primary_cpcd_debug_counters; +extern dbg_cts_t secondary_cpcd_debug_counters; + +typedef enum endpoint_option +{ + EP_ON_IFRAME_RECEIVE = 0, + EP_ON_IFRAME_RECEIVE_ARG, + EP_ON_UFRAME_RECEIVE, + EP_ON_UFRAME_RECEIVE_ARG, + EP_ON_IFRAME_WRITE_COMPLETED, + EP_ON_IFRAME_WRITE_COMPLETED_ARG, + EP_ON_UFRAME_WRITE_COMPLETED, + EP_ON_UFRAME_WRITE_COMPLETED_ARG, + EP_ON_POLL, + EP_ON_POLL_ARG, + EP_ON_FINAL, + EP_ON_FINAL_ARG, +} endpoint_option_t; + +typedef enum hdlc_frame_type +{ + HDLC_FRAME_TYPE_IFRAME = 0, + HDLC_FRAME_TYPE_SFRAME = 2, + HDLC_FRAME_TYPE_UFRAME = 3 +} hdlc_frame_type_t; + +typedef enum hdlc_frame_pos +{ + HDLC_FLAG_POS = 0, + HDLC_ADDRESS_POS = 1, + HDLC_LENGTH_POS = 2, + HDLC_CONTROL_POS = 4, + HDLC_HCS_POS = 5 +} hdlc_frame_pos_t; + +typedef enum hdlc_frame_shift +{ + HDLC_CONTROL_UFRAME_TYPE_POS = 0, + HDLC_CONTROL_P_F_POS = 2, + HDLC_CONTROL_SEQ_POS = 3, + HDLC_CONTROL_SFRAME_FUNCTION_ID_POS = 4, + HDLC_CONTROL_FRAME_TYPE_POS = 6 +} hdlc_frame_shift_t; + +typedef enum hdlc_frame_ctrl_u +{ + HDLC_CONTROL_UFRAME_TYPE_INFORMATION = 0x00, + HDLC_CONTROL_UFRAME_TYPE_POLL_FINAL = 0x04, + HDLC_CONTROL_UFRAME_TYPE_ACKNOWLEDGE = 0x0E, + HDLC_CONTROL_UFRAME_TYPE_RESET_SEQ = 0x31, + HDLC_CONTROL_UFRAME_TYPE_UNKNOWN = 0xFF +} hdlc_frame_ctrl_u_t; + +typedef enum reject_reason +{ + HDLC_REJECT_NO_ERROR = 0, + HDLC_REJECT_CHECKSUM_MISMATCH, + HDLC_REJECT_SEQUENCE_MISMATCH, + HDLC_REJECT_OUT_OF_MEMORY, + HDLC_REJECT_SECURITY_ISSUE, + HDLC_REJECT_UNREACHABLE_ENDPOINT, + HDLC_REJECT_ERROR +} reject_reason_t; + +void hdlc_create_header(uint8_t *hdr, uint8_t address, uint16_t length, uint8_t control); +void core_init(int driver_fd, int driver_notify_fd); +void core_open_endpoint(uint8_t endpoit_number, uint8_t flags, uint8_t tx_win_size); +void core_process_transmit_queue(void); +void core_reset_endpoint_sequence(uint8_t endpoint_number); +bool core_ep_is_busy(uint8_t ep_id); +status_t core_close_endpoint(uint8_t endpoint_number, bool notify_secondary, bool force_close); +ep_state_t core_get_endpoint_state(uint8_t ep_id); +bool core_get_endpoint_encryption(uint8_t ep_id); +void core_set_endpoint_state(uint8_t ep_id, ep_state_t state); +ep_state_t core_endpoint_state(uint8_t state); +const char *core_stringify_state(ep_state_t state); +void core_write(uint8_t endpoint_number, const void *message, size_t message_len, uint8_t flags); +void core_process_endpoint_change(uint8_t endpoint_number, ep_state_t ep_state); +bool core_endpoint_is_closing(uint8_t ep_id); +void core_set_endpoint_in_error(uint8_t endpoint_number, ep_state_t new_state); +void core_set_endpoint_option(uint8_t endpoint_number, endpoint_option_t option, void *value); +uint16_t core_compute_crc16(uint8_t new_byte, uint16_t prev_result); +uint16_t core_get_crc_sw(const void *buffer, uint16_t buffer_length); +bool core_check_crc_sw(const void *buffer, uint16_t buffer_length, uint16_t expected_crc); + +// ----------------------------------------------------------------------------- + +#endif diff --git a/module/controller/daemon/main.c b/module/controller/daemon/main.c deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/daemon/primary/primary.c b/module/controller/daemon/primary/primary.c index e69de29..fff8205 100644 --- a/module/controller/daemon/primary/primary.c +++ b/module/controller/daemon/primary/primary.c @@ -0,0 +1,1410 @@ + +#include "primary.h" +#include "library/libezmesh.h" +#include "utility/log.h" +#include "utility/config.h" +#include "utility/list.h" +#include "daemon/hdlc/core.h" +#include "daemon/controller.h" +#include "host/hal_epoll.h" + +#include +#include + +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" + +// ================================ +// private define +// ================================ +#define CORE_EXC_SIZE sizeof(ezmesh_croe_exange_buffer_t) + sizeof(int) +#define CHECK_EXIT(cond) if (cond) { return; } +#define RETRY_COUNT 5 +#define RETRY_TIMEOUT 100000 +#define SIZEOF_SYSTEM_COMMAND(command) (sizeof(sys_cmd_t) + command->length) +#define UFRAME_ACK_TIMEOUT_SECONDS 2 + +#define SYS_TO_ERR_STATUE(err) ERR_SYS_STATUS_OK + err + +typedef struct { + list_node_t node; + ez_epoll_t data; +} ez_socket_list_t; + +typedef struct { + list_node_t node; + int fd_data_socket; + int socket_fd; +} ez_socket_close_t; + +typedef struct { + list_node_t node; + uint8_t ep; + int socket_fd; +} conn_list_t; + +typedef struct +{ + list_node_t node; + ez_epoll_t data_socket_epoll_port_data; + pid_t pid; +}ctrl_socket_data_list_t; + +typedef struct { + ep_state_t key; + ezmesh_evt_type_t val; +} key_val_map_t; +static const key_val_map_t evt_map[] = { + {ENDPOINT_STATE_OPEN, EVT_EP_OPENED}, + {ENDPOINT_STATE_CLOSED, EVT_EP_CLOSED}, + {ENDPOINT_STATE_CLOSING, EVT_EP_CLOSING}, + {ENDPOINT_STATE_ERROR_DEST_UNREACH, EVT_EP_ERROR_DESTINATION_UNREACHABLE}, + {ENDPOINT_STATE_ERROR_FAULT, EVT_EP_ERROR_FAULT}}; + +// ================================ +// public define +// ================================ +static list_node_t *connections; +static list_node_t *ctl_connections; +ez_open_ep_t sys_ep_state = OPEN_EP_IDLE; +ep_ctl_t ep_ctx[PRIMARY_EP_MAX_COUNTS]; +int ctl_create_conn = 0; +int open_conn_fd = 0; +bool reset_sequence_ack = true; +extern bool ignore_reset_reason; + +static list_node_t *pending_commands; +static list_node_t *commands; +static list_node_t *retries; +static list_node_t *commands_in_error; +static list_node_t *prop_last_status_callbacks; + +#define SYS_CMD_HDR_SIZE sizeof(sys_cmd_t) + sizeof(property_id_t) + +ez_err_t EP_close(uint8_t ep, bool state); +static void on_timer_expired(ez_epoll_t *private_data); +static void close_main_node_connection(int fd_data_socket); + +#define SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len) \ + ret = send(fd, interface_buffer, buffer_len, 0); \ + if (ret < 0 && errno == EPIPE) { close_main_node_connection(fd); break; } \ + CHECK_ERROR(ret < 0 && errno != EPIPE); \ + CHECK_ERROR((size_t)ret != (buffer_len)); + +// ================================ +// private function +// ================================ +static int gen_socket(int ep) { + struct sockaddr_un *p_sock = calloc(1, sizeof(struct sockaddr_un)); + int fd; + + fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + CHECK_ERROR(fd == -1); + + p_sock->sun_family = AF_UNIX; + snprintf(p_sock->sun_path, sizeof(p_sock->sun_path)-1, "%s/%s/ep%d.sock", config.ep_hw.socket_path, config.ep_hw.name, ep); + + log_info("[Sys] Try Generate socket on fd: %d, path: %s", fd, p_sock->sun_path); + CHECK_ERROR(bind(fd, (const struct sockaddr *)p_sock, sizeof(struct sockaddr_un)) < 0); + CHECK_ERROR(listen(fd, 5) < 0); + log_info("[Sys] Generate socket success fd: %d, path: %s", fd, p_sock->sun_path); + free(p_sock); + return fd; +} + +static int accept_socket(ez_epoll_t *p_data) { + int socket; + CHECK_FATAL(p_data->ep < 0 || ep_ctx[p_data->ep].socket_instance.fd == -1); + socket = accept(p_data->fd, NULL, NULL); + CHECK_ERROR(socket < 0); + CHECK_ERROR(fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, NULL) | O_NONBLOCK) < 0); + return socket; +} + +static void del_socket(int ep, bool state) { + int fd; + struct sockaddr_un *p_sock = calloc(1, sizeof(struct sockaddr_un)); + + fd = ep_ctx[ep].socket_instance.fd; + if (fd > 0) { + hal_epoll_unregister((hal_epoll_event_data_t*)&ep_ctx[ep].socket_instance); + CHECK_ERROR(shutdown(fd, SHUT_RDWR) < 0); + CHECK_ERROR(close(fd) < 0); + } + + p_sock->sun_family = AF_UNIX; + snprintf(p_sock->sun_path, sizeof(p_sock->sun_path)-1, "%s/%s/ep%d.sock", config.ep_hw.socket_path, config.ep_hw.name, ep); + + log_info("[Sys] Try delete socket on fd: %d, path: %s", fd, p_sock->sun_path); + CHECK_ERROR(unlink(p_sock->sun_path) < 0 && errno != ENOENT); + log_info("[Sys] Delete socket success fd: %d, path: %s", fd, p_sock->sun_path); + free(p_sock); + + ep_ctx[ep].socket_instance.fd = -1; + ep_ctx[ep].conn_count = 0; + if (state) ep_ctx[ep].pending_close = ep_ctx[ep].conn_count; +} + +static bool handle_epoll_close(int fd_data_socket, uint8_t ep) { + + ez_socket_close_t *item, *next_item; + ezmesh_croe_exange_buffer_t *buffer; + bool notified = false; + + item = SLIST_ENTRY(ep_ctx[ep].ctl_socket_data, ez_socket_close_t, node); + buffer = calloc(CORE_EXC_SIZE, sizeof(uint8_t)); + + while (item) { + next_item = SLIST_ENTRY((item)->node.node, ez_socket_close_t, node); + + if (item->fd_data_socket == fd_data_socket && item->socket_fd > 0) { + list_remove(&ep_ctx[ep].ctl_socket_data, &item->node); + if (!notified) { + log_warn("notified"); + buffer->endpoint_number = ep; + buffer->type = EXCHANGE_CLOSE_EP_QUERY; + *((int *)buffer->payload) = fd_data_socket; + if (send(item->socket_fd, buffer, CORE_EXC_SIZE, 0) == (ssize_t)CORE_EXC_SIZE) notified = true; + else if (errno != EPIPE) log_warn("ep notify send() failed, errno = %d", errno); + } + free(item); + } + item = next_item; + } + free(buffer); + return notified; +} + +static void handle_user_closed_ep(int fd, uint8_t ep) +{ + ez_socket_list_t *item, *next_item; + item = SLIST_ENTRY(ep_ctx[ep].epoll_data, ez_socket_list_t, node); + if (item == NULL) log_error("data connection not found in the linked list of the endpoint"); + + do{ + next_item = SLIST_ENTRY((item)->node.node, ez_socket_list_t, node); + if (item->data.fd == fd) + { + hal_epoll_unregister((hal_epoll_event_data_t *)&item->data); + list_remove(&ep_ctx[ep].epoll_data, &item->node); + + handle_epoll_close(item->data.fd, ep); + CHECK_ERROR(shutdown(fd, SHUT_RDWR) < 0); + CHECK_ERROR(close(fd) < 0); + CHECK_ERROR(ep_ctx[ep].conn_count == 0); + ep_ctx[ep].conn_count--; + + log_info("Endpoint socket #%d: Client disconnected. %d connections", ep, ep_ctx[ep].conn_count); + if (ep_ctx[ep].conn_count == 0) + { + log_info("Closing endpoint socket, no more listeners"); + EP_close(ep, false); + if (ep_ctx[ep].pending_close == 0) + { + log_info("No pending close on the endpoint, closing it"); + core_close_endpoint(ep, true, false); + } + } + free(item); + } + item = next_item; + } while (item != NULL); +} + +static int EP_pull_data(int fd_data_socket, uint8_t **buffer_ptr, size_t *buffer_len_ptr) +{ + int datagram_length; + uint8_t *buffer; + ssize_t rc; + + CHECK_ERROR(ioctl(fd_data_socket, FIONREAD, &datagram_length) < 0); + CHECK_FATAL(datagram_length == 0); + + buffer = (uint8_t *)calloc(1, PAD_TO_ALIGNMENT(datagram_length, sizeof(uint8_t)*8)); + CHECK_ERROR(buffer == NULL); + + rc = recv(fd_data_socket, buffer, (size_t)datagram_length, 0); + if (rc < 0) { log_info("[PRI] recv() failed with %d", errno); } + + if (rc == 0 || (rc < 0 && errno == ECONNRESET)) + { + log_info("[PRI] Client is closed"); + free(buffer); + return -1; + } + CHECK_ERROR(rc < 0); + + *buffer_ptr = buffer; + *buffer_len_ptr = (size_t)rc; + return 0; +} + +static void handle_node_event(ez_epoll_t *p_data) { + + uint8_t *buf; + size_t buf_len; + int fd = p_data->fd, length; + uint8_t ep = p_data->ep; + + if (core_ep_is_busy(ep)) { + hal_epoll_unwatch((hal_epoll_event_data_t*)p_data); + return; + } + + CHECK_ERROR(ioctl(fd, FIONREAD, &length) < 0); + if (length == 0) { + handle_user_closed_ep(fd, ep); + return; + } + + if (EP_pull_data(fd, &buf, &buf_len) != 0) { + handle_user_closed_ep(fd, ep); + return; + } + + if (core_get_endpoint_state(ep) == ENDPOINT_STATE_OPEN) core_write(ep, buf, buf_len, 0); + else { + log_warn("Push data to close ep #%d, state: %d", ep, core_get_endpoint_state(ep)); + EP_close(ep, false); + } + free(buf); +} + + +static void close_main_node_connection(int fd_data_socket) +{ + ctrl_socket_data_list_t *item; + ctrl_socket_data_list_t *next_item; + + item = SLIST_ENTRY(ctl_connections, ctrl_socket_data_list_t, node); + if (item == NULL) log_error("ctrl data connection not found in the linked list of the ctrl socket"); + + do { + next_item = SLIST_ENTRY((item)->node.node, ctrl_socket_data_list_t, node); + if (item->data_socket_epoll_port_data.fd == fd_data_socket) + { + hal_epoll_unregister((hal_epoll_event_data_t *)&item->data_socket_epoll_port_data); + list_remove(&ctl_connections, &item->node); + CHECK_ERROR(shutdown(fd_data_socket, SHUT_RDWR) < 0); + CHECK_ERROR(close(fd_data_socket) < 0); + log_info("Client disconnected"); + free(item); + } + item = next_item; + } while (item != NULL); +} + +static void EP_push_close_socket_pair(int fd_data_socket, int fd_ctrl_data_socket, uint8_t endpoint_number) +{ + ez_socket_close_t *item; + item = calloc(1, sizeof(ez_socket_close_t)); + CHECK_ERROR(item == NULL); + item->fd_data_socket = fd_data_socket; + item->socket_fd = fd_ctrl_data_socket; + list_push(&ep_ctx[endpoint_number].ctl_socket_data, &item->node); +} + +static bool EP_find_close_socket_pair(int fd_data_socket, int fd_ctrl_data_socket, uint8_t endpoint_number) +{ + + ez_socket_close_t *item; + ez_socket_close_t *next_item; + bool found = false; + item = SLIST_ENTRY(ep_ctx[endpoint_number].ctl_socket_data, ez_socket_close_t, node); + + do { + next_item = SLIST_ENTRY((item)->node.node, ez_socket_close_t, node); + if (item->fd_data_socket == fd_data_socket && item->socket_fd == fd_ctrl_data_socket) + { + list_remove(&ep_ctx[endpoint_number].ctl_socket_data, &item->node); + free(item); + found = true; + break; + } + item = next_item; + } while (item != NULL); + return found; +} + +static void handle_main_node_event(ez_epoll_t *p_data) { + int fd, length; + uint8_t *buffer; + ezmesh_croe_exange_buffer_t *interface_buffer; + size_t buffer_len; + ssize_t ret; + + fd = p_data->fd; + CHECK_ERROR(ioctl(fd, FIONREAD, &length)<0); + + if (length == 0) + { + close_main_node_connection(fd); + return; + } + + CHECK_ERROR(EP_pull_data(fd, &buffer, &buffer_len) != 0); + CHECK_ERROR(buffer_len < sizeof(ezmesh_croe_exange_buffer_t)); + interface_buffer = (ezmesh_croe_exange_buffer_t *)buffer; + + switch (interface_buffer->type) + { + case EXCHANGE_EP_STATUS_QUERY: { + /* Client requested an endpoint status */ + ep_state_t ep_state; + log_info("Received an endpoint status query"); + CHECK_ERROR(buffer_len != sizeof(ezmesh_croe_exange_buffer_t) + sizeof(ep_state_t)); + ep_state = core_get_endpoint_state(interface_buffer->endpoint_number); + memcpy(interface_buffer->payload, &ep_state, sizeof(ep_state_t)); + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + break;} + + case EXCHANGE_MAX_WRITE_SIZE_QUERY: { + /* Client requested maximum write size */ + log_info("Received an maximum write size query"); + CHECK_ERROR(buffer_len != sizeof(ezmesh_croe_exange_buffer_t) + sizeof(uint32_t)); + size_t rx_capability = (size_t)controller_get_agent_rx_capability(); + memcpy(interface_buffer->payload, &rx_capability, sizeof(uint32_t)); + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + break;} + + case EXCHANGE_VERSION_QUERY:{ + /* Client requested the version of the daemon*/ + char *version = (char *)interface_buffer->payload; + bool do_close_client = false; + CHECK_ERROR(interface_buffer->payload == NULL); + log_info("Received a version query"); + + if (buffer_len != sizeof(ezmesh_croe_exange_buffer_t) + sizeof(char) * PROJECT_MAX_VERSION_SIZE) + { + log_warn("Client used invalid version buffer_len = %zu", buffer_len); + break; + } + + if (strnlen(version, PROJECT_MAX_VERSION_SIZE) == PROJECT_MAX_VERSION_SIZE) + { + do_close_client = true; + log_warn("Client used invalid library version, version string is invalid"); + } + else if (strcmp(version, PROJECT_VER) != 0) + { + do_close_client = true; + log_warn("Client used invalid library version, (v%s) expected (v%s)", version, PROJECT_VER); + } + else log_info("New client connection using library v%s", version); + + //Reuse the receive buffer to send back the response + strncpy(version, PROJECT_VER, PROJECT_MAX_VERSION_SIZE); + ret = send(fd, interface_buffer, buffer_len, 0); + if ((ret < 0 && errno == EPIPE )|| do_close_client) { close_main_node_connection(fd); break; } + CHECK_ERROR(ret < 0 && errno != EPIPE); + CHECK_ERROR((size_t)ret != (buffer_len)); + break;} + + case EXCHANGE_OPEN_EP_QUERY:{ + /* Client requested to open an endpoint socket*/ + log_info("Received an endpoint open query"); + CHECK_ERROR(buffer_len != sizeof(ezmesh_croe_exange_buffer_t) + sizeof(bool)); + conn_list_t *conn = calloc(1, sizeof(conn_list_t)); + CHECK_ERROR(conn == NULL); + conn->ep = interface_buffer->endpoint_number; + conn->socket_fd = fd; + list_push_back(&connections, &conn->node); + break;} + + case EXCHANGE_CLOSE_EP_QUERY: { + log_info("Received a endpoint close query"); + /* Endpoint was closed by agent */ + CHECK_ERROR(buffer_len != sizeof(ezmesh_croe_exange_buffer_t) + sizeof(int)); + if (ep_ctx[interface_buffer->endpoint_number].pending_close > 0) + { + ep_ctx[interface_buffer->endpoint_number].pending_close--; + if (ep_ctx[interface_buffer->endpoint_number].pending_close == 0) core_close_endpoint(interface_buffer->endpoint_number, true, false); + + // Ack the close query + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + if (ret >= 0 || errno != EPIPE){ + // And notify the caller + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + } + } else + { + /* Endpoint was already closed by a client (same ctrl data socket, multiple instances of the same endpoint) */ + if (core_get_endpoint_state(interface_buffer->endpoint_number) == ENDPOINT_STATE_CLOSED) + { + // Ack the close query + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + if (ret >= 0 || errno != EPIPE){ + // And notify the caller + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + } + } else + { + /* Endpoint is about to be closed by a client */ + int fd_data_socket = *(int *)interface_buffer->payload; + bool fd_data_socket_closed = EP_find_close_socket_pair(fd_data_socket, -1, interface_buffer->endpoint_number); + if (!fd_data_socket_closed) EP_push_close_socket_pair(fd_data_socket, fd, interface_buffer->endpoint_number); + // Socket already closed, ack the close query + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + } + } + } + break; + + case EXCHANGE_SET_PID_QUERY:{ + log_info("Received set PID"); + bool can_connect = true; + memcpy(interface_buffer->payload, &can_connect, sizeof(bool)); + CHECK_ERROR(buffer_len < sizeof(bool)); + SEND_DATA_TO_CORE(ret, fd, interface_buffer, buffer_len); + break;} + + case EXCHANGE_GET_AGENT_APP_VERSION_QUERY:{ + char *app_version = (char *)interface_buffer->payload; + strncpy(app_version, controller_get_agent_app_version(), PROJECT_MAX_VERSION_SIZE); + log_info("%s", app_version); + + send(fd, interface_buffer, buffer_len, 0); + break;} + default:{break;} + } + free(buffer); +} + +static void handle_epoll_conn(ez_epoll_t *p_data) { + + uint8_t ep; + int socket; + ez_socket_list_t *node; + + ep = p_data->ep; + socket = accept_socket(p_data); + node = calloc(1, sizeof(ez_socket_list_t)); + CHECK_ERROR(node == NULL); + list_push(&ep_ctx[ep].epoll_data, &node->node); + node->data.callback = (ep == 0)? handle_main_node_event : handle_node_event; + node->data.ep = ep; + node->data.fd = socket; + hal_epoll_register((hal_epoll_event_data_t*)&node->data); + + if(ep == 0){ list_push(&ctl_connections, &node->node); } + else + { + ezmesh_croe_exange_buffer_t *buffer; + + ep_ctx[ep].conn_count++; + log_info("[INFO] EP socket #%d: Client connected. %d connections", ep, ep_ctx[ep].conn_count); + + core_process_endpoint_change(ep, ENDPOINT_STATE_OPEN); + log_info("[PRI] Told ezmeshd to open ep#%u", ep); + + size_t buffer_len = sizeof(ezmesh_croe_exange_buffer_t) + sizeof(int); + buffer = calloc(1, buffer_len); + CHECK_ERROR(buffer == NULL); + buffer->endpoint_number = ep; + buffer->type = EXCHANGE_OPEN_EP_QUERY; + *((int *)buffer->payload) = socket; + CHECK_ERROR(send(socket, buffer, buffer_len, 0) != (ssize_t)buffer_len); + free(buffer); + } +} + +static void handle_ep_send(int fd_data_socket, int socket_fd, uint8_t ep) { + + ez_socket_close_t *item; + item = calloc(1, sizeof(ez_socket_close_t)); + CHECK_ERROR(item == NULL); + item->fd_data_socket = fd_data_socket; + item->socket_fd = socket_fd; + list_push(&ep_ctx[ep].ctl_socket_data, &item->node); + free(item); +} + +static void get_hw_state(sys_cmd_handle_t *handle, property_id_t id, void *p_data, + size_t p_length, status_t status) { + (void)handle; + bool create_flag = false, hw_attach = false; + uint8_t ep; + ep_state_t hw_ep_state; + ep_state_t sw_ep_state; + + switch (status) { + case STATUS_OK: + case STATUS_IN_PROGRESS:{ + CHECK_FATAL(p_length != sizeof(ep_state_t)); + log_info("[PRI] Successful callback"); + hw_ep_state = core_endpoint_state(*(uint8_t *)p_data); + hw_attach = true; + break;} + + case STATUS_TIMEOUT: + case STATUS_ABORT: + default: { + log_warn("PROP_EP_STATE: 0x%02x", status); + break;} + } + CHECK_FATAL(ctl_create_conn == 0 || (hw_attach && p_length != 1)); + ep = PROPERTY_ID_TO_EP_ID(id); + sw_ep_state = core_get_endpoint_state(ep); + + log_info("HW State: %d, SW State: %d", hw_ep_state, sw_ep_state); + + if (hw_attach && (hw_ep_state == ENDPOINT_STATE_OPEN) && (sw_ep_state == ENDPOINT_STATE_CLOSED || sw_ep_state == ENDPOINT_STATE_OPEN)) + create_flag = true; + + if (!create_flag && hw_attach) + log_info("[PRI] Cannot open EP #%d. HW state: %s. Daemon state: %s", ep, core_stringify_state(hw_ep_state), core_stringify_state(sw_ep_state)); + + if (!hw_attach) log_warn("Could not read EP state on the HW"); + + if (create_flag) EP_open(ep, sw_ep_state); + + const size_t buffer_len = sizeof(ezmesh_croe_exange_buffer_t) + sizeof(bool); + ezmesh_croe_exange_buffer_t *interface_buffer = calloc(1, buffer_len); + + interface_buffer->type = EXCHANGE_OPEN_EP_QUERY; + interface_buffer->endpoint_number = ep; + memcpy(interface_buffer->payload, &create_flag, sizeof(bool)); + + ssize_t ret = send(ctl_create_conn, interface_buffer, buffer_len, 0); + log_info("[PRI] Replied to endpoint open query on ep#%d", ep); + + if (ret == -1) log_warn("Failed to acknowledge the open request for endpoint #%d", ep); + else if ((size_t)ret != buffer_len) FATAL("Failed to acknowledge the open request for endpoint #%d. Sent %d, Expected %d", ep, (int)ret, (int)buffer_len); + + free(interface_buffer); + sys_ep_state = OPEN_EP_DONE; +} + +void EP_close_cb(sys_cmd_handle_t *handle, property_id_t id, void *property_value, + size_t property_length, status_t status){ + (void)handle; + (void)property_value; + (void)property_length; + uint8_t ep = PROPERTY_ID_TO_EP_ID(id); + switch (status) { + case STATUS_IN_PROGRESS: + case STATUS_OK: { + log_info("[PRI] ACK HW of async close ep#%d", ep); + break; + } + + case STATUS_TIMEOUT: + case STATUS_ABORT: + default: { + log_warn("HW did not receive ACK of async close ep#%d", ep); + break; + } + } +} + +bool EP_list_empty(uint8_t ep) { return ep_ctx[ep].conn_count == 0; } + +// ================================ +// public function +// ================================ +ez_err_t EP_open(uint8_t ep, ep_state_t state) { + CHECK_FATAL(ep == 0 && ep_ctx[ep].socket_instance.fd != -1 && ep_ctx[ep].epoll_data != NULL); + CHECK_FATAL(ep != 0 && ep_ctx[ep].socket_instance.fd == -1 && ep_ctx[ep].epoll_data != NULL); + + if(ep != 0 && ep_ctx[ep].socket_instance.fd != -1) { EP_close( ep, state); } + + ep_ctx[ep].socket_instance.callback = handle_epoll_conn; + ep_ctx[ep].socket_instance.ep = ep; + ep_ctx[ep].socket_instance.fd = gen_socket(ep); + + hal_epoll_register((hal_epoll_event_data_t*)&ep_ctx[ep].socket_instance); + log_info("[INFO] Opened connection socket for ep#%u", ep); + return NO_ERROR; +} + +ez_err_t EP_close(uint8_t ep, bool state) { + size_t idx = 0; + list_node_t *node; + ez_socket_list_t *item; + + CHECK_FATAL(ep == 0 ); + if(ep_ctx[ep].socket_instance.fd == -1) return NO_ERROR; + while (ep_ctx[ep].epoll_data != NULL) { + node = list_pop(&ep_ctx[ep].epoll_data); + item = SLIST_ENTRY(node, ez_socket_list_t, node); + idx++; + + hal_epoll_unregister((hal_epoll_event_data_t*)&item->data); + handle_epoll_close(item->data.fd, ep); + + CHECK_ERROR(shutdown(item->data.fd, SHUT_RDWR) < 0); + CHECK_ERROR(close(item->data.fd) < 0); + free(item); + log_info("[PRI] Closed data socket #%u on ep#%u", idx, ep); + } + del_socket(ep, state); + return NO_ERROR; +} + +bool EP_get_state(uint8_t ep) { return ep_ctx[ep].socket_instance.fd != -1; } + +bool EP_is_open(uint8_t ep) { return ep_ctx[ep].conn_count == 0; } + +ez_err_t EP_set_state(uint8_t ep, ep_state_t state) { + ez_socket_list_t *item; + ezmesh_ezmeshd_event_buffer_t *event; + event = calloc(1, sizeof(ezmesh_ezmeshd_event_buffer_t)); + CHECK_ERROR(event == NULL); + SLIST_FOR_EACH_ENTRY(ep_ctx[ep].epoll_event, item, ez_socket_list_t, node) { + event->type = evt_map[state].val; + event->endpoint_number = ep; + event->payload_length = 0; + + ssize_t ret = send(item->data.fd, event, sizeof(ezmesh_ezmeshd_event_buffer_t), MSG_DONTWAIT); + free(event); + if (ret < 0 && (errno == EPIPE || errno == ECONNRESET || errno == ECONNREFUSED)) {} + else if (ret < 0 && errno == EWOULDBLOCK) + { + log_warn("Client event socket is full, closing the socket.."); + CHECK_ERROR(shutdown(item->data.fd, SHUT_RDWR) < 0); + } + else { CHECK_FATAL(ret < 0 || (size_t)ret != sizeof(ezmesh_ezmeshd_event_buffer_t)); } + } + free(event); + return NO_ERROR; +} + +ez_err_t EP_push_data(uint8_t ep, uint8_t *data, size_t data_len) { + ez_socket_list_t *item; + int nb_clients = 0; + ssize_t wc; + + CHECK_FATAL(ep_ctx[ep].socket_instance.fd == -1); + CHECK_WARN(ep_ctx[ep].epoll_data == NULL); + + item = SLIST_ENTRY(ep_ctx[ep].epoll_data, ez_socket_list_t, node); + + while (item != NULL) { + wc = send(item->data.fd, data, data_len, MSG_DONTWAIT); + if (wc < 0) log_info("[PRI] send() failed with %d", errno); + + nb_clients++; + + if (wc < 0 && (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || + errno == EWOULDBLOCK)) { + log_warn("Unresponsive data socket on ep#%d, closing", ep); + + if (ep_ctx[ep].conn_count == 1 && nb_clients == 1 && + (errno == EAGAIN || errno == EWOULDBLOCK)) + return SYS_TO_ERR_STATUE(STATUS_WOULD_BLOCK); + + hal_epoll_unregister((hal_epoll_event_data_t*)&item->data); + handle_ep_send(item->data.fd, -1, ep); + + CHECK_ERROR(shutdown(item->data.fd, SHUT_RDWR) < 0); + CHECK_ERROR(close(item->data.fd) < 0); + list_remove(&ep_ctx[ep].epoll_data, &item->node); + free(item); + + CHECK_ERROR(ep_ctx[ep].conn_count == 0); + ep_ctx[ep].conn_count--; + log_info("[INFO] EP #%d: Client disconnected. %d connections", ep, ep_ctx[ep].conn_count); + + if (ep_ctx[ep].conn_count == 0) { + log_info("[PRI] EP was unresponsive, no more listeners"); + del_socket(ep, false); + return SYS_TO_ERR_STATUE(STATUS_FAIL); + } + + item = SLIST_ENTRY(ep_ctx[ep].epoll_data, ez_socket_list_t, node); + } else { + CHECK_ERROR(wc < 0); + CHECK_ERROR((size_t)wc != data_len); + item = SLIST_ENTRY((item)->node.node, ez_socket_list_t, node); + } + } + return SYS_TO_ERR_STATUE(STATUS_OK); +} + +void ctl_notify_HW_reset(void) +{ + ctrl_socket_data_list_t *item; + + SLIST_FOR_EACH_ENTRY(ctl_connections, item, ctrl_socket_data_list_t, node) + { + if (item->pid != getpid()) + { + if (item->pid > 1) { kill(item->pid, SIGUSR1); } + else { FATAL("Connected library's pid it not set"); } + } + } +} + +ez_err_t ctl_proc_conn(void) { + conn_list_t *item; + item = SLIST_ENTRY(connections, conn_list_t, node); + if (item == NULL) return NO_ERROR; + + if (core_endpoint_is_closing(item->ep)) { + log_info("[PRI] EP #%d is closing, waiting before opening", item->ep); + return NO_ERROR; + } + + switch (sys_ep_state) { + case OPEN_EP_IDLE: { + sys_ep_state = OPEN_EP_STATE_WAITING; + open_conn_fd = item->socket_fd; + ctl_create_conn = item->socket_fd; + sys_param_get(get_hw_state, (property_id_t)(PROP_EP_STATE_0 + item->ep), 5, 100000, false); + break; + } + case OPEN_EP_DONE: { + sys_ep_state = OPEN_EP_IDLE; + open_conn_fd = 0; + list_remove(&connections, &item->node); + free(item); + break; + } + case OPEN_EP_STATE_FETCHED: + default: { break; } + } + return NO_ERROR; +} + +ez_err_t ctl_init(void) { + ez_epoll_t *ep_data = calloc(1, sizeof(ez_epoll_t)); + + list_init(&ctl_connections); + list_init(&connections); + for (size_t i = 1; i != PRIMARY_EP_MAX_COUNTS; i++) { + ep_ctx[i].conn_count = 0; + ep_ctx[i].conn_event = 0; + ep_ctx[i].pending_close = 0; + ep_ctx[i].socket_instance.ep = (uint8_t)i; + ep_ctx[i].socket_instance.fd = -1; + ep_ctx[i].epoll_conn_event.fd = -1; + list_init(&ep_ctx[i].epoll_event); + list_init(&ep_ctx[i].epoll_data); + list_init(&ep_ctx[i].ctl_socket_data); + } + + ep_data->callback = handle_epoll_conn; + ep_data->fd = gen_socket(0); + ep_data->ep = EP_SYSTEM; + // log_info("EPOLL ADD EVENT: fd 0x%02x, EP %d, cb: %p", ep_data->fd , EP_SYSTEM, ep_data->callback); + hal_epoll_register((hal_epoll_event_data_t*)ep_data); + return NO_ERROR; +} + +static void sys_cmd_abort(sys_cmd_handle_t *handle, status_t error) +{ + // Stop the re_transmit timer + if (handle->retx_socket.fd != 0) + { + if (handle->is_uframe || handle->acked == true) hal_epoll_unregister((hal_epoll_event_data_t*)&handle->retx_socket); + close(handle->retx_socket.fd); + handle->retx_socket.fd = 0; + } + + handle->error_status = error; //This will be propagated when calling the callbacks + + switch (handle->command->command_id) + { + case CMD_SYSTEM_NOOP:{ + ((sys_noop_cb_t)handle->on_final)(handle, handle->error_status); + break;} + + case CMD_SYSTEM_RESET:{ + ((sys_reset_cmd_callback_t)handle->on_final)(handle, handle->error_status, SYS_STATUS_FAILURE); + break;} + + case CMD_SYSTEM_PROP_VALUE_GET: + case CMD_SYSTEM_PROP_VALUE_SET:{ + sys_property_cmd_t *tx_property_command = (sys_property_cmd_t *)handle->command->payload; + + ((sys_property_get_set_cmd_callback_t)handle->on_final)(handle, tx_property_command->property_id, + NULL, 0, handle->error_status); + break;} + + case CMD_SYSTEM_PROP_VALUE_IS: //fall through + default:{ + FATAL("Invalid command_id"); + break;} + } + + // Invalidate the command id, now that it is aborted + handle->command->command_id = CMD_SYSTEM_INVALID; +} + + +static void write_command(sys_cmd_handle_t *handle) +{ + int timer_fd; + uint8_t flags = FLAG_INFORMATION_POLL; + + handle->retry_forever = (handle->retry_count == 0)? true : false; + if (handle->is_uframe) flags = FLAG_UFRAME_POLL; + + list_push_back(&commands, &handle->node_commands); + handle->acked = false; + core_write(EP_SYSTEM, (void *)handle->command, SIZEOF_SYSTEM_COMMAND(handle->command), flags); + + log_info("[SYS] Submitted command_id #%d command_seq #%d, frame_type %d", handle->command->command_id, handle->command_seq, handle->is_uframe); + + if (handle->is_uframe) + { + const struct itimerspec timeout = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, + .it_value = { .tv_sec = (long int)handle->retry_timeout_us / 1000000, + .tv_nsec = ((long int)handle->retry_timeout_us * 1000) % 1000000000 } }; + + timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + CHECK_ERROR(timer_fd < 0); + int ret = timerfd_settime(timer_fd, 0, &timeout, NULL); + CHECK_ERROR(ret < 0); + + handle->retx_socket.ep = EP_SYSTEM; + handle->retx_socket.fd = timer_fd; + handle->retx_socket.callback = on_timer_expired; + hal_epoll_register((hal_epoll_event_data_t*)&handle->retx_socket); + } +} + + +void sys_ep_no_found_ack() +{ + list_node_t *item; + sys_cmd_handle_t *handle; + + log_info("[SYS] Received sequence numbers reset acknowledgement"); + reset_sequence_ack = true; + + // Send any pending commands + item = list_pop(&pending_commands); + while (item != NULL) + { + handle = SLIST_ENTRY(item, sys_cmd_handle_t, node_commands); + write_command(handle); + item = list_pop(&pending_commands); + } +} + +static void handle_ack_timeout(ez_epoll_t *private_data) { + list_node_t *item; + int timer_fd = private_data->fd; + sys_cmd_handle_t *handle; + uint64_t expiration; + ssize_t ret; + + handle = MEM_INDEX(private_data, sys_cmd_handle_t, retx_socket); + if (reset_sequence_ack) { + if (handle->retx_socket.fd != 0) { + hal_epoll_unregister((hal_epoll_event_data_t*)&handle->retx_socket); + close(handle->retx_socket.fd); + handle->retx_socket.fd = 0; + } + return; + } + + log_info("[SYS] Remote is unresponsive, retrying..."); + + ret = read(timer_fd, &expiration, sizeof(expiration)); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != sizeof(expiration)); + CHECK_WARN(expiration != 1); + + /* Drop any pending commands to prevent accumulation*/ + item = list_pop(&pending_commands); + while (item != NULL) { + handle = SLIST_ENTRY(item, sys_cmd_handle_t, node_commands); + + if (handle->command->command_id != CMD_SYSTEM_INVALID) sys_cmd_abort(handle, STATUS_ABORT); + free(handle); + item = list_pop(&pending_commands); + } + + core_write(EP_SYSTEM, NULL, 0, FLAG_UFRAME_RESET_COMMAND); +} + +// ================================ +// public function +// ================================ + +static void sys_init_cmd_handle(sys_cmd_handle_t *handle, void *on_final, uint8_t retry_count, uint32_t retry_timeout_us, bool is_uframe) +{ + static uint8_t next_command_seq = 0; + + CHECK_FATAL(handle == NULL); + CHECK_FATAL(on_final == NULL); + handle->acked = false; + handle->error_status = STATUS_OK; + + handle->on_final = on_final; + handle->retry_count = retry_count; + handle->retry_timeout_us = retry_timeout_us; + handle->command_seq = next_command_seq++; + handle->is_uframe = is_uframe; +} + +static void sys_abort(sys_cmd_handle_t *handle, status_t error) +{ + // Stop the re_transmit timer + if (handle->retx_socket.fd != 0) + { + if (handle->is_uframe || handle->acked == true) hal_epoll_unregister((hal_epoll_event_data_t*)&handle->retx_socket); + close(handle->retx_socket.fd); + handle->retx_socket.fd = 0; + } + + handle->error_status = error; //This will be propagated when calling the callbacks + + switch (handle->command->command_id) + { + case CMD_SYSTEM_NOOP:{ + ((sys_noop_cb_t)handle->on_final)(handle, handle->error_status); + break;} + + case CMD_SYSTEM_RESET:{ + ((sys_reset_cmd_callback_t)handle->on_final)(handle, handle->error_status, SYS_STATUS_FAILURE); + break;} + + case CMD_SYSTEM_PROP_VALUE_GET: + case CMD_SYSTEM_PROP_VALUE_SET:{ + ((sys_property_get_set_cmd_callback_t)handle->on_final)(handle, ((sys_property_cmd_t *)handle->command->payload)->property_id, + NULL, 0, handle->error_status); + break;} + + case CMD_SYSTEM_PROP_VALUE_IS: //fall through + default: + FATAL("Invalid command_id"); + break; + } + + // Invalidate the command id, now that it is aborted + handle->command->command_id = CMD_SYSTEM_INVALID; +} + + +static void on_timer_expired(ez_epoll_t *private_data) +{ + int timer_fd = private_data->fd; + sys_cmd_handle_t *handle = MEM_INDEX(private_data, sys_cmd_handle_t, retx_socket); + + log_info("[SYS] Command ID #%u SEQ #%u timer expired", handle->command->command_id, handle->command->command_seq); + + uint64_t expiration; + ssize_t retval; + retval = read(timer_fd, &expiration, sizeof(expiration)); + CHECK_ERROR(retval < 0); + CHECK_ERROR(retval != sizeof(expiration)); + CHECK_WARN(expiration != 1); /* we missed a timeout*/ + + if (!handle->retry_forever) handle->retry_count--; + + if (handle->retry_count > 0 || handle->retry_forever) + { + list_remove(&commands, &handle->node_commands); + handle->error_status = STATUS_IN_PROGRESS; //at least one timer retry occurred + write_command(handle); + if (handle->retry_forever) log_info("[SYS] Command ID #%u SEQ #%u retried", handle->command->command_id, handle->command->command_seq); + else log_info("[SYS] Command ID #%u SEQ #%u. %u retry left", handle->command->command_id, handle->command->command_seq, handle->retry_count); + } + else + { + SLIST_FOR_EACH_ENTRY(commands, handle, sys_cmd_handle_t, node_commands) + { + if (handle->command_seq == (handle->command)->command_seq) break; + } + if (handle == NULL || handle->command_seq != (handle->command)->command_seq) FATAL("A command timed out but it could not be found in the submitted commands list. SEQ#%d", (handle->command)->command_seq); + list_remove(&commands, &handle->node_commands); + log_info("[SYS] Command ID #%u SEQ #%u timeout", handle->command->command_id, handle->command->command_seq); + sys_abort(handle, STATUS_TIMEOUT); + free(handle->command); + free(handle); + } +} + +void sys_reboot(reset_cb_t cb, uint8_t count, uint32_t time) { + sys_cmd_handle_t *handle; + + handle = calloc(1, sizeof(sys_cmd_handle_t)); + CHECK_ERROR(handle == NULL); + + handle->command = calloc(1, sizeof(sys_cmd_t)); + CHECK_ERROR(handle->command == NULL); + + sys_init_cmd_handle(handle, (void *)cb, count, time, true); + handle->command->command_id = CMD_SYSTEM_RESET; + handle->command->command_seq = handle->command_seq; + handle->command->length = 0; + write_command(handle); + log_info("[SYS] reset (id #%u) sent", CMD_SYSTEM_RESET); +} + +void sys_param_get(param_get_cb_t cb, property_id_t id, uint8_t count, + uint32_t time, bool is_uframe) { + sys_cmd_handle_t *handle; + + handle = calloc(1, sizeof(sys_cmd_handle_t)); + CHECK_ERROR(handle == NULL); + + handle->command = calloc(1, PAD_TO_ALIGNMENT(SYS_CMD_HDR_SIZE, 8)); + CHECK_ERROR(handle->command == NULL); + + sys_init_cmd_handle(handle, (void *)cb, count, time, is_uframe); + + + sys_cmd_t *tx_command = handle->command; + sys_property_cmd_t *tx_property_command = (sys_property_cmd_t *)tx_command->payload; + + tx_command->command_id = CMD_SYSTEM_PROP_VALUE_GET; + tx_command->command_seq = handle->command_seq; + tx_command->length = sizeof(property_id_t); + tx_property_command->property_id = cpu_to_le32(id); + + write_command(handle); + log_info("[SYS] param-get (id #%u) sent with param #%u", CMD_SYSTEM_PROP_VALUE_GET, id); +} + +void sys_param_set(param_set_cb_t cb, uint8_t count, uint32_t time, + property_id_t id, const void *val, size_t length, + bool is_uframe) { + sys_cmd_handle_t *handle; + uint8_t *payload; + + handle = calloc(1, sizeof(sys_cmd_handle_t)); + CHECK_ERROR(handle == NULL); + handle->command = calloc(1, PAD_TO_ALIGNMENT(SYS_CMD_HDR_SIZE + length, 8)); + CHECK_ERROR(handle->command == NULL); + + sys_init_cmd_handle(handle, (void *)cb, count, time, is_uframe); + payload = ((sys_property_cmd_t *)handle->command->payload)->payload; + handle->command->command_id = CMD_SYSTEM_PROP_VALUE_SET; + handle->command->command_seq = handle->command_seq; + handle->command->length = (uint8_t)(sizeof(property_id_t) + length); + ((sys_property_cmd_t *)handle->command->payload)->property_id = + cpu_to_le32(id); + + switch (length) { + case 0: { + log_error("Can't send a property-set request with value of length 0"); + break;} + + case 1: { + memcpy(payload, val, length); + break;} + + case 2: { + uint16_t le16 = cpu_to_le16p((uint16_t *)val); + memcpy(payload, &le16, 2); + break;} + + case 4: { + uint32_t le32 = cpu_to_le32p((uint32_t *)val); + memcpy(payload, &le32, 4); + break;} + + case 8: { + uint64_t le64 = cpu_to_le64p((uint64_t *)val); + memcpy(payload, &le64, 8); + break;} + + default:{ + memcpy(payload, val, length); + break;} + } + + write_command(handle); + log_info("[SYS] property-set (id #%u) sent with property #%u", CMD_SYSTEM_PROP_VALUE_SET, id); +} + +static void on_reply(uint8_t endpoint_id, void *arg, void *answer, uint32_t answer_lenght) +{ + sys_cmd_handle_t *handle; + sys_cmd_t *reply = (sys_cmd_t *)answer; + size_t frame_type = (size_t)arg; + + CHECK_FATAL(endpoint_id != 0); + CHECK_ERROR(reply->length != answer_lenght - sizeof(sys_cmd_t)); + + SLIST_FOR_EACH_ENTRY(commands, handle, sys_cmd_handle_t, node_commands) + { + if (handle->command_seq != reply->command_seq) continue; + + log_info("[SYS] Processing command seq#%d of type %d", reply->command_seq, frame_type); + if (frame_type == HDLC_FRAME_TYPE_UFRAME || (frame_type == HDLC_FRAME_TYPE_IFRAME && handle->acked == true)) + { + CHECK_FATAL(handle->retx_socket.fd <= 0); + hal_epoll_unregister((hal_epoll_event_data_t*)&handle->retx_socket); + close(handle->retx_socket.fd); + handle->retx_socket.fd = 0; + } + + /* Call the appropriate callback */ + if (frame_type == HDLC_FRAME_TYPE_UFRAME) + { + CHECK_FATAL(handle->is_uframe == false); + switch (reply->command_id) + { + case CMD_SYSTEM_RESET:{ + log_info("[SYS] on_final_reset()"); + ignore_reset_reason = false; + // Deal with endianness of the returned status since its a 32bit value. + sys_status_t reset_status_le = *((sys_status_t *)(reply->payload)); + sys_status_t reset_status_cpu = le32_to_cpu(reset_status_le); + ((sys_reset_cmd_callback_t)handle->on_final)(handle, handle->error_status, reset_status_cpu); + break;} + + case CMD_SYSTEM_PROP_VALUE_IS:{ + sys_property_cmd_t *p_cmd = (sys_property_cmd_t *)reply->payload; + sys_property_get_set_cmd_callback_t cb = (sys_property_get_set_cmd_callback_t)handle->on_final; + + if (p_cmd->property_id != PROP_RX_CAPABILITY && p_cmd->property_id != PROP_CAPABILITIES + && p_cmd->property_id != PROP_BUS_SPEED_VALUE && p_cmd->property_id != PROP_PROTOCOL_VERSION + && p_cmd->property_id != PROP_SECONDARY_EZMESH_VERSION && p_cmd->property_id != PROP_SECONDARY_APP_VERSION + && p_cmd->property_id != PROP_BOOTLOADER_REBOOT_MODE) + { + log_error("Received on_final property_is %x as a u-frame", p_cmd->property_id); + } + /* Deal with endianness of the returned property-id since its a 32bit value. */ + property_id_t property_id_le = p_cmd->property_id; + property_id_t property_id_cpu = le32_to_cpu(property_id_le); + size_t value_length = reply->length - sizeof(sys_property_cmd_t); + if(cb) cb(handle, property_id_cpu, p_cmd->payload, value_length, handle->error_status); + break;} + + default:{ + log_error("system endpoint command id not recognized for u-frame"); + break;} + } + } else if (frame_type == HDLC_FRAME_TYPE_IFRAME) + { + CHECK_FATAL(handle->is_uframe == true); + switch (reply->command_id) + { + case CMD_SYSTEM_NOOP:{ + log_info("[SYS] on_final_noop()"); + ((sys_noop_cb_t)handle->on_final)(handle, handle->error_status); + break;} + + case CMD_SYSTEM_PROP_VALUE_IS:{ + sys_property_cmd_t *p_cmd = (sys_property_cmd_t *)reply->payload; + sys_property_get_set_cmd_callback_t cb = (sys_property_get_set_cmd_callback_t)handle->on_final; + property_id_t property_id_le = p_cmd->property_id; + property_id_t property_id_cpu = le32_to_cpu(property_id_le); + size_t value_length = reply->length - sizeof(sys_property_cmd_t); + + if(cb) cb(handle, property_id_cpu, p_cmd->payload, value_length, handle->error_status); + break;} + + case CMD_SYSTEM_PROP_VALUE_GET: + case CMD_SYSTEM_PROP_VALUE_SET:{ + log_error("its the primary who sends those"); + break;} + + default:{ + log_error("system endpoint command id not recognized for i-frame"); + break;} + } + } else log_error("Invalid frame_type"); + + /* Cleanup this command now that it's been serviced */ + list_remove(&commands, &handle->node_commands); + free(handle->command); + free(handle); + return; + } + + log_warn("Received a system final for which no pending poll is registered"); +} + +static void on_uframe_receive(uint8_t endpoint_id, const void *data, size_t data_len) +{ + CHECK_ERROR(endpoint_id != EP_SYSTEM); + log_info("[SYS] Unsolicited uframe received"); + sys_cmd_t *reply = (sys_cmd_t *)data; + CHECK_ERROR(reply->length != data_len - sizeof(sys_cmd_t)); + + if (reply->command_id == CMD_SYSTEM_PROP_VALUE_IS) + { + sys_property_cmd_t *property = (sys_property_cmd_t *)reply->payload; + if (property->property_id == PROP_LAST_STATUS) + { + last_status_callback_list_t *item; + SLIST_FOR_EACH_ENTRY(prop_last_status_callbacks, item, last_status_callback_list_t, node) + { + sys_status_t *status = (sys_status_t *)property->payload; + item->callback(*status); + } + } + } +} + +static void on_iframe_unsolicited(uint8_t endpoint_id, const void *data, size_t data_len) +{ + CHECK_ERROR(endpoint_id != EP_SYSTEM); + log_info("[SYS] Unsolicited i-frame received"); + if (controller_reset_sequence_in_progress()) + { + log_info("[SYS] Cannot process unsolicited i-frame during reset sequence, ignoring"); + return; + } + + sys_cmd_t *reply = (sys_cmd_t *)data; + CHECK_ERROR(reply->length != data_len - sizeof(sys_cmd_t)); + if (reply->command_id == CMD_SYSTEM_PROP_VALUE_IS) + { + sys_property_cmd_t *property = (sys_property_cmd_t *)reply->payload; + if (property->property_id >= PROP_EP_STATE_0 && property->property_id < PROP_EP_STATES) + { + uint8_t closed_endpoint_id = PROPERTY_ID_TO_EP_ID(property->property_id); + ep_state_t endpoint_state = core_endpoint_state(*(uint8_t *)property->payload); + + if (endpoint_state == ENDPOINT_STATE_CLOSING) + { + log_info("[SYS] Secondary closed the endpoint #%d", closed_endpoint_id); + if (!EP_list_empty(closed_endpoint_id) && core_get_endpoint_state(closed_endpoint_id) == ENDPOINT_STATE_OPEN) + core_set_endpoint_in_error(closed_endpoint_id, ENDPOINT_STATE_ERROR_DEST_UNREACH); + sys_param_set(EP_close_cb, RETRY_COUNT, RETRY_TIMEOUT, property->property_id, &endpoint_state, sizeof(ep_state_t), false); + } + else log_error("Invalid property id"); + } + } +} + +static void sys_open_endpoint() +{ + core_open_endpoint(EP_SYSTEM, OPEN_EP_FLAG_UFRAME_ENABLE, 1); + core_set_endpoint_option(EP_SYSTEM, EP_ON_FINAL, on_reply); + core_set_endpoint_option(EP_SYSTEM, EP_ON_UFRAME_RECEIVE, on_uframe_receive); + core_set_endpoint_option(EP_SYSTEM, EP_ON_IFRAME_RECEIVE, on_iframe_unsolicited); +} + +void sys_sequence_reset(void) { + int fd; + list_node_t *item; + sys_cmd_handle_t *handle; + + // Abort any pending commands + item = list_pop(&commands); + while (item != NULL) + { + handle = SLIST_ENTRY(item, sys_cmd_handle_t, node_commands); + + if (handle->command->command_id != CMD_SYSTEM_INVALID) + { + log_warn("Dropping system command id #%d seq#%d", handle->command->command_id, handle->command_seq); + sys_cmd_abort(handle, STATUS_ABORT); + } + + // Command payload will be freed once we close the endpoint + free(handle->command); + free(handle); + item = list_pop(&commands); + } + core_close_endpoint(EP_SYSTEM, false, true); + sys_open_endpoint(); + + log_info("[SYS] Requesting reset of sequence numbers on the remote"); + core_write(EP_SYSTEM, NULL, 0, FLAG_UFRAME_RESET_COMMAND); + + core_process_transmit_queue(); + const struct itimerspec timeout = { + .it_interval = {.tv_sec = UFRAME_ACK_TIMEOUT_SECONDS, .tv_nsec = 0}, + .it_value = {.tv_sec = UFRAME_ACK_TIMEOUT_SECONDS, .tv_nsec = 0}}; + + fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + CHECK_ERROR(fd < 0); + CHECK_ERROR(timerfd_settime(fd, 0, &timeout, NULL) < 0); + + handle = calloc(1, sizeof(sys_cmd_handle_t)); + CHECK_ERROR(handle == NULL); + handle->retx_socket.fd = fd; + handle->retx_socket.ep = EP_SYSTEM; + handle->retx_socket.callback = handle_ack_timeout; + + hal_epoll_register((hal_epoll_event_data_t*)&handle->retx_socket); + CHECK_ERROR(timerfd_settime(handle->retx_socket.fd, 0, &timeout, NULL) < 0); + reset_sequence_ack = false; +} + +void sys_set_last_status_callback(sys_unsolicited_status_callback_t callback) +{ + last_status_callback_list_t *item = calloc(1, sizeof(last_status_callback_list_t)); + CHECK_ERROR(item == NULL); + item->callback = callback; + list_push_back(&prop_last_status_callbacks, &item->node); +} + +void sys_poll_ack(const void *frame_data) +{ + int timer_fd; + sys_cmd_handle_t *handle; + CHECK_ERROR(frame_data == NULL); + sys_cmd_t *acked_command = (sys_cmd_t *)frame_data; + + SLIST_FOR_EACH_ENTRY(commands, handle, sys_cmd_handle_t, node_commands) + { + if (handle->command_seq != acked_command->command_seq) continue; + + log_info("[SYS] Secondary acknowledged command_id #%d command_seq #%d", handle->command->command_id, handle->command_seq); + const struct itimerspec timeout = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, + .it_value = { .tv_sec = (long int)handle->retry_timeout_us / 1000000, + .tv_nsec = ((long int)handle->retry_timeout_us * 1000) % 1000000000 } }; + + /* Setup timeout timer.*/ + if (handle->error_status == STATUS_OK) + { + timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + + CHECK_ERROR(timer_fd < 0); + CHECK_ERROR(timerfd_settime(timer_fd, 0, &timeout, NULL) < 0); + + /* Setup the timer in the primary_ezmeshd epoll set */ + handle->retx_socket.ep = EP_SYSTEM; //Irrelevant in this scenario + handle->retx_socket.fd = timer_fd; + handle->retx_socket.callback = on_timer_expired; + + hal_epoll_register((hal_epoll_event_data_t*)&handle->retx_socket); + } + else if (handle->error_status == STATUS_IN_PROGRESS) { CHECK_ERROR(timerfd_settime(handle->retx_socket.fd, 0, &timeout, NULL) < 0); } + else { log_warn("Received ACK on a command that timed out or is processed.. ignoring"); } + + handle->acked = true; + return; // Found the associated command + } + + log_warn("Received a system poll ack for which no pending poll is registered"); +} + +void sys_cleanup(void) +{ + list_node_t *item; + last_status_callback_list_t *cb_item; + + log_info("[Reset Seq] Server ezmeshd cleanup"); + + item = list_pop(&prop_last_status_callbacks); + while (item != NULL) + { + cb_item = SLIST_ENTRY(item, last_status_callback_list_t, node); + free(cb_item); + item = list_pop(&pending_commands); + } + core_close_endpoint(EP_SYSTEM, false, true); +} + +void sys_init(void) { + list_init(&commands); + list_init(&retries); + list_init(&pending_commands); + list_init(&commands_in_error); + list_init(&prop_last_status_callbacks); + + sys_open_endpoint(); +} diff --git a/module/controller/daemon/primary/primary.h b/module/controller/daemon/primary/primary.h index e69de29..a1c5ae5 100644 --- a/module/controller/daemon/primary/primary.h +++ b/module/controller/daemon/primary/primary.h @@ -0,0 +1,229 @@ +#ifndef PRIMARY_H +#define PRIMARY_H + +#include +#include +#include +#include "library/libezmesh.h" +#include "utility/list.h" + +#define PRIMARY_EP_MAX_COUNTS (256) +#define CAPABILITIES_PACKED_EP_MASK (1 << 1) +#define CAPABILITIES_UART_FLOW_CONTROL_MASK (1 << 3) +#define PROPERTY_ID_TO_EP_ID(property_id) ((uint8_t)(property_id & 0x000000FF)) + +#define EP_ID_TO_PROPERTY_ID(property, ep_id) ((property_id_t)((property) | ((ep_id) & 0x000000FF))) +#define EP_ID_TO_PROPERTY_STATE(ep_id) EP_ID_TO_PROPERTY_ID(PROP_EP_STATE_0, ep_id) + +typedef enum { + STATUS_OK = 0, + STATUS_FAIL, + STATUS_IN_PROGRESS = 5, + STATUS_ABORT, + STATUS_TIMEOUT, + STATUS_WOULD_BLOCK = 9, +} status_t; + +typedef enum { + OPEN_EP_IDLE, + OPEN_EP_STATE_WAITING, + OPEN_EP_STATE_FETCHED, + OPEN_EP_ENCRYPTION_WAITING, + OPEN_EP_ENCRYPTION_FETCHED, + OPEN_EP_DONE, +} ez_open_ep_t; + +typedef enum { + NO_ERROR, + + ERR_SYS_STATUS_OK = 0, + ERR_SYS_STATUS_FAILURE = 1, + ERR_SYS_STATUS_UNIMPLEMENTED = 2, + ERR_SYS_STATUS_INVALID_ARGUMENT = 3, + ERR_SYS_STATUS_INVALID_STATE = 4, + ERR_SYS_STATUS_INVALID_COMMAND = 5, + ERR_SYS_STATUS_INVALID_INTERFACE = 6, + ERR_SYS_STATUS_INTERNAL_ERROR = 7, + ERR_SYS_STATUS_PARSE_ERROR = 9, + ERR_SYS_STATUS_IN_PROGRESS = 10, + ERR_SYS_STATUS_NOMEM = 11, + ERR_SYS_STATUS_BUSY = 12, + ERR_SYS_STATUS_PROP_NOT_FOUND = 13, + ERR_SYS_STATUS_PACKET_DROPPED = 14, + ERR_SYS_STATUS_EMPTY = 15, + ERR_SYS_STATUS_CMD_TOO_BIG = 16, + ERR_SYS_STATUS_ALREADY = 19, + ERR_SYS_STATUS_ITEM_NOT_FOUND = 20, + ERR_SYS_STATUS_INVALID_COMMAND_FOR_PROP = 21, + ERR_SYS_STATUS_RESET_POWER_ON = 112, + ERR_SYS_STATUS_RESET_EXTERNAL = 113, + ERR_SYS_STATUS_RESET_SOFTWARE = 114, + ERR_SYS_STATUS_RESET_FAULT = 115, + ERR_SYS_STATUS_RESET_CRASH = 116, + ERR_SYS_STATUS_RESET_ASSERT = 117, + ERR_SYS_STATUS_RESET_OTHER = 118, + ERR_SYS_STATUS_RESET_UNKNOWN = 119, + ERR_SYS_STATUS_RESET_WATCHDOG = 120, +} ez_err_t; + +typedef struct ez_epoll ez_epoll_t; +typedef void (*epoll_cb_t)(ez_epoll_t *data); +struct ez_epoll { + epoll_cb_t callback; + int fd; + uint8_t ep; +}; + +typedef uint8_t sys_cmd_id_t; +enum sys_cmd_id_t_enum { + CMD_SYSTEM_NOOP = 0x00, + CMD_SYSTEM_RESET = 0x01, + CMD_SYSTEM_PROP_VALUE_GET = 0x02, + CMD_SYSTEM_PROP_VALUE_SET = 0x03, + CMD_SYSTEM_PROP_VALUE_IS = 0x06, + CMD_SYSTEM_INVALID = 0xFF, +}; + +typedef uint32_t sys_status_t; +enum sys_status_t_enum { + SYS_STATUS_OK = 0, + SYS_STATUS_FAILURE = 1, + SYS_STATUS_UNIMPLEMENTED = 2, + SYS_STATUS_INVALID_ARGUMENT = 3, + SYS_STATUS_INVALID_STATE = 4, + SYS_STATUS_INVALID_COMMAND = 5, + SYS_STATUS_INVALID_INTERFACE = 6, + SYS_STATUS_INTERNAL_ERROR = 7, + SYS_STATUS_PARSE_ERROR = 9, + SYS_STATUS_IN_PROGRESS = 10, + SYS_STATUS_NOMEM = 11, + SYS_STATUS_BUSY = 12, + SYS_STATUS_PROP_NOT_FOUND = 13, + SYS_STATUS_PACKET_DROPPED = 14, + SYS_STATUS_EMPTY = 15, + SYS_STATUS_CMD_TOO_BIG = 16, + SYS_STATUS_ALREADY = 19, + SYS_STATUS_ITEM_NOT_FOUND = 20, + SYS_STATUS_INVALID_COMMAND_FOR_PROP = 21, + + SYS_STATUS_RESET_POWER_ON = 112, + SYS_STATUS_RESET_EXTERNAL = 113, + SYS_STATUS_RESET_SOFTWARE = 114, + SYS_STATUS_RESET_FAULT = 115, + SYS_STATUS_RESET_CRASH = 116, + SYS_STATUS_RESET_ASSERT = 117, + SYS_STATUS_RESET_OTHER = 118, + SYS_STATUS_RESET_UNKNOWN = 119, + SYS_STATUS_RESET_WATCHDOG = 120, +} ; + +typedef uint32_t property_id_t; +enum property_id_t_enum { + PROP_LAST_STATUS = 0x00, + PROP_PROTOCOL_VERSION = 0x01, + PROP_CAPABILITIES = 0x02, + PROP_SECONDARY_EZMESH_VERSION = 0x03, + PROP_SECONDARY_APP_VERSION = 0x04, + PROP_RX_CAPABILITY = 0x20, + PROP_FC_VALIDATION_VALUE = 0x30, + PROP_BUS_SPEED_VALUE = 0x40, + + PROP_BOOTLOADER_REBOOT_MODE = 0x202, + + PROP_EZMESHD_DEBUG_COUNTERS = 0x400, + PROP_UFRAME_PROCESSING = 0x500, + + PROP_EP_STATE_0 = 0x1000, + + PROP_EP_STATES = 0x1100, +} ; + + +typedef uint32_t reboot_mode_t; +enum reboot_mode_t_enum { + REBOOT_APPLICATION = 0, + REBOOT_BOOTLOADER = 1 +}; + +typedef struct { + uint8_t command_id; ///< Identifier of the command. + uint8_t command_seq; ///< Command sequence number + uint16_t length; ///< Length of the payload in bytes. + uint8_t payload[]; ///< Command payload. +} sys_cmd_t; + +typedef struct { + property_id_t property_id; ///< Identifier of the property. + uint8_t payload[]; ///< Property value. +} sys_property_cmd_t; + +typedef struct { + list_node_t node_commands; + sys_cmd_t *command; + void *on_final; + uint8_t retry_count; + bool retry_forever; + bool is_uframe; + uint32_t retry_timeout_us; + status_t error_status; + uint8_t command_seq; + bool acked; + ez_epoll_t retx_socket; // for epoll for timerfd +} sys_cmd_handle_t; + +typedef struct { + uint32_t conn_count; + uint32_t conn_event; + uint32_t pending_close; + ez_epoll_t epoll_conn_event; + ez_epoll_t socket_instance; + list_node_t *epoll_event; + list_node_t *epoll_data; + list_node_t *ctl_socket_data; +} ep_ctl_t; + + +// extern ep_ctl_t ep_ctx[PRIMARY_EP_MAX_COUNTS]; + +void EP_close_cb(sys_cmd_handle_t *handle, property_id_t id, void *property_value, size_t property_length, status_t status); +ez_err_t EP_open(uint8_t ep, ep_state_t state); +ez_err_t EP_close(uint8_t ep, bool state); +bool EP_get_state(uint8_t ep); +bool EP_is_open(uint8_t ep); +ez_err_t EP_set_state(uint8_t ep, ep_state_t state); +ez_err_t EP_push_data(uint8_t ep, uint8_t *data, size_t data_len); +ez_err_t ctl_proc_conn(void); +ez_err_t ctl_init(void); +void ctl_notify_HW_reset(void); +bool EP_list_empty(uint8_t ep); + +typedef void (*sys_unsolicited_status_callback_t) (sys_status_t status); +typedef struct +{ + list_node_t node; + sys_unsolicited_status_callback_t callback; +}last_status_callback_list_t; + +typedef void (*sys_noop_cb_t) (sys_cmd_handle_t *handle, status_t status); +typedef void (*sys_reset_cmd_callback_t) (sys_cmd_handle_t *handle, status_t command_status, sys_status_t reset_status); + +typedef void (*sys_property_get_set_cmd_callback_t) (sys_cmd_handle_t *handle, + property_id_t property_id, + void *property_value, + size_t property_length, + status_t status); +typedef void (*reset_cb_t)(sys_cmd_handle_t *handle, status_t command_status, sys_status_t reset_status); +typedef void (*param_get_cb_t)(sys_cmd_handle_t *handle, property_id_t property_id, void *property_value, size_t property_length, status_t status); +typedef void (*param_set_cb_t)(sys_cmd_handle_t *handle, property_id_t property_id, void *property_value, size_t property_length, status_t status); + +void sys_sequence_reset(void); +void sys_poll_ack(const void *frame_data); +void sys_cleanup(void); +void sys_ep_no_found_ack(void); +void sys_set_last_status_callback(sys_unsolicited_status_callback_t callback); +void sys_init(void); +void sys_reboot(reset_cb_t cb, uint8_t count, uint32_t time); +void sys_param_get(param_get_cb_t cb, property_id_t id, uint8_t count, uint32_t time, bool is_uframe); +void sys_param_set(param_set_cb_t cb, uint8_t count, uint32_t time, property_id_t id, const void *val, size_t length, bool is_uframe); + +#endif diff --git a/module/controller/daemon/primary/system_ep.c b/module/controller/daemon/primary/system_ep.c deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/daemon/primary/system_ep.h b/module/controller/daemon/primary/system_ep.h deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/ez_config.ini b/module/controller/ez_config.ini new file mode 100644 index 0000000..27abfde --- /dev/null +++ b/module/controller/ez_config.ini @@ -0,0 +1,12 @@ +[log] ; Protocol configuration +mode = 0 ; System = 0, Developer +level = 2 ; LOG_TRACE = 0, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL + +[EZMESH_CONF] ; for ezmeshd_0 +name = ezmeshd_0 ; interface name +type = 0 ; UART=0, SPI +port = /dev/ttyUSB0 ; device file +baudrate = 500000 ; buad rate +flowcontrol = 0 ; flow control +socket_path = /dev/shm/ezmesh ; socket path + diff --git a/module/controller/host/dev_epoll.c b/module/controller/host/dev_epoll.c deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_epoll.h b/module/controller/host/dev_epoll.h deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_kill.c b/module/controller/host/dev_kill.c deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_kill.h b/module/controller/host/dev_kill.h deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_sleep.c b/module/controller/host/dev_sleep.c deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_sleep.h b/module/controller/host/dev_sleep.h deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_uart.c b/module/controller/host/dev_uart.c deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/dev_uart.h b/module/controller/host/dev_uart.h deleted file mode 100644 index e69de29..0000000 diff --git a/module/controller/host/hal_epoll.c b/module/controller/host/hal_epoll.c new file mode 100644 index 0000000..1867d88 --- /dev/null +++ b/module/controller/host/hal_epoll.c @@ -0,0 +1,132 @@ +#include "hal_epoll.h" +#include "utility/log.h" +#include "utility/list.h" +#include "utility/utility.h" +#include "daemon/hdlc/core.h" +#include "daemon/primary/primary.h" + +#include +#include +#include + +#define VALID_EPOLL_DATA(data) { \ + CHECK_ERROR(data == NULL); \ + CHECK_ERROR(data->callback == NULL || data->file_descriptor < 1); } + +typedef struct +{ + list_node_t node; + struct hal_epoll_event_data *unregistered_epoll_port_private_data; +} unwatched_endpoint_list_item_t; + +/* List to keep track of every connected library instance over the control socket */ +static list_node_t *unwatched_endpoint_list; +static list_node_t *register_list; +static int fd_epoll; + +void hal_epoll_init(void) +{ + fd_epoll = epoll_create1(EPOLL_CLOEXEC); + CHECK_ERROR(fd_epoll < 0); + list_init(&unwatched_endpoint_list); + list_init(®ister_list); +} + +// void hal_epoll_list_all(void) +// { +// unwatched_endpoint_list_item_t *item = NULL; +// log_info(""); +// SLIST_FOR_EACH_ENTRY(register_list, item, unwatched_endpoint_list_item_t, node) +// { +// log_info("[Epoll] List data fd 0x%02x, EP %d, cb %p", +// item->unregistered_epoll_port_private_data->file_descriptor, +// item->unregistered_epoll_port_private_data->endpoint_number, +// item->unregistered_epoll_port_private_data->callback); +// } +// log_info(""); +// } + +void hal_epoll_register(hal_epoll_event_data_t *data) +{ + VALID_EPOLL_DATA(data); + struct epoll_event event = {.events = EPOLLIN, .data.ptr = data}; + CHECK_ERROR(epoll_ctl(fd_epoll, EPOLL_CTL_ADD, data->file_descriptor, &event) < 0); + // hal_epoll_list_all(); + // log_info("[EPOLL] GEN: fd 0x%02x, ep %d, cb %p", data->file_descriptor, data->endpoint_number, data->callback); + + unwatched_endpoint_list_item_t *item = calloc(1, sizeof(unwatched_endpoint_list_item_t)); + CHECK_ERROR(item == NULL); + item->unregistered_epoll_port_private_data = data; + memcpy(item->unregistered_epoll_port_private_data, data, sizeof(hal_epoll_event_data_t)); + list_push(®ister_list, &item->node); + // hal_epoll_list_all(); + return ; +} + +void hal_epoll_unregister(hal_epoll_event_data_t *data) +{ + unwatched_endpoint_list_item_t *item = NULL; + VALID_EPOLL_DATA(data); + // hal_epoll_list_all(); + // log_info("[EPOLL] Remove data fd 0x%02x, EP %d, cb %p", data->file_descriptor, data->endpoint_number, data->callback); + SLIST_FOR_EACH_ENTRY(register_list, item, unwatched_endpoint_list_item_t, node) + { + if (memcmp(data, item->unregistered_epoll_port_private_data, sizeof(unwatched_endpoint_list_item_t))==0) + { + list_remove(®ister_list, &item->node); + free(item); + break; + } + } + // hal_epoll_list_all(); + + SLIST_FOR_EACH_ENTRY(unwatched_endpoint_list, item, unwatched_endpoint_list_item_t, node) + { + if (memcmp(data, item->unregistered_epoll_port_private_data, sizeof(unwatched_endpoint_list_item_t))==0) + { + list_remove(&unwatched_endpoint_list, &item->node); + free(item); + return; + } + } + CHECK_ERROR(epoll_ctl(fd_epoll, EPOLL_CTL_DEL, data->file_descriptor, NULL) < 0); +} + +void hal_epoll_unwatch(hal_epoll_event_data_t *data) +{ + hal_epoll_unregister(data); + unwatched_endpoint_list_item_t *item = calloc(1, sizeof(unwatched_endpoint_list_item_t)); + CHECK_ERROR(item == NULL); + item->unregistered_epoll_port_private_data = data; + list_push(&unwatched_endpoint_list, &item->node); +} + +void hal_epoll_watch_back(uint8_t endpoint_number) +{ + unwatched_endpoint_list_item_t *item = NULL; + + list_node_t *item_node = unwatched_endpoint_list; + while (1) + { + item = SLIST_ENTRY(item_node, unwatched_endpoint_list_item_t, node); + if (item == NULL) break; + item_node = item_node->node; + if (endpoint_number == item->unregistered_epoll_port_private_data->endpoint_number) + { + hal_epoll_register(item->unregistered_epoll_port_private_data); + list_remove(&unwatched_endpoint_list, &item->node); + free(item); + } + } +} + +size_t hal_epoll_wait_for_event(struct epoll_event events[], size_t event_number) +{ + int cnt = 0; + do + { + cnt = epoll_wait(fd_epoll, events, (int)event_number, -1); + } while ((cnt == -1) && (errno == EINTR)); + CHECK_ERROR(cnt <= 0); + return (size_t)cnt; +} diff --git a/module/controller/host/hal_epoll.h b/module/controller/host/hal_epoll.h new file mode 100644 index 0000000..9d70343 --- /dev/null +++ b/module/controller/host/hal_epoll.h @@ -0,0 +1,25 @@ +#ifndef HAL_EPOLL_H +#define HAL_EPOLL_H + +#include "stdint.h" +#include + +struct hal_epoll_event_data; +typedef struct hal_epoll_event_data hal_epoll_event_data_t; +typedef void (*hal_epoll_callback_t) (hal_epoll_event_data_t *data); +struct hal_epoll_event_data +{ + hal_epoll_callback_t callback; + int file_descriptor; + uint8_t endpoint_number; +}; + +void hal_epoll_init(void); +void hal_epoll_register(hal_epoll_event_data_t *data); +void hal_epoll_unregister(hal_epoll_event_data_t *data); +void hal_epoll_unwatch(hal_epoll_event_data_t *data); +void hal_epoll_watch_back(uint8_t endpoint_number); +uint8_t hal_epoll_check_vaild_event(struct hal_epoll_event_data *events); +size_t hal_epoll_wait_for_event(struct epoll_event events[], size_t event_number); + +#endif diff --git a/module/controller/host/hal_kill.c b/module/controller/host/hal_kill.c new file mode 100644 index 0000000..0ae440d --- /dev/null +++ b/module/controller/host/hal_kill.c @@ -0,0 +1,59 @@ +#define _GNU_SOURCE +#include +#include +#include + +#include +#include "hal_kill.h" +#include "utility/log.h" + +static int efd = -1; + +int hal_kill_init(void) +{ + efd = eventfd(0, EFD_CLOEXEC); + CHECK_ERROR(efd == -1); + return efd; +} + +void hal_kill_signal(void) +{ + ssize_t ret = 0; + const uint64_t event_value = 1; + + if (efd == -1) + { + return; + } + + ret = write(efd, &event_value, sizeof(event_value)); + CHECK_ERROR(ret != sizeof(event_value)); +} + +int hal_kill_join(void) +{ + void *join_value = NULL; + int ret = 0; + + extern pthread_t hal_thread; + ret = pthread_join(hal_thread, &join_value); + + return ret; +} + +int hal_kill_signal_and_join(void) +{ + int ret = 0; + const uint64_t event_value = 1; + void *join_value = NULL; + + if (efd == -1) return -1; + + ret = (int)write(efd, &event_value, sizeof(event_value)); + CHECK_ERROR(ret != sizeof(event_value)); + + extern pthread_t hal_thread; + ret = pthread_join(hal_thread, &join_value); + + return ret; +} \ No newline at end of file diff --git a/module/cpc/cpcd/hal/hal_kill.h b/module/controller/host/hal_kill.h similarity index 86% rename from module/cpc/cpcd/hal/hal_kill.h rename to module/controller/host/hal_kill.h index 7c2092e..a3be420 100644 --- a/module/cpc/cpcd/hal/hal_kill.h +++ b/module/controller/host/hal_kill.h @@ -1,14 +1,9 @@ - - #ifndef HAL_KILL_H #define HAL_KILL_H int hal_kill_init(void); - void hal_kill_signal(void); - int hal_kill_join(void); - int hal_kill_signal_and_join(void); -#endif //HAL_KILL_H +#endif diff --git a/module/controller/host/hal_sleep.c b/module/controller/host/hal_sleep.c new file mode 100644 index 0000000..3c33fa7 --- /dev/null +++ b/module/controller/host/hal_sleep.c @@ -0,0 +1,77 @@ +/** + * @file sleep.c + * @author Rex Huang (rex.huang@rafaelmicro.com) + * @brief + * @version 0.1 + * @date 2023-10-30 + * + * + */ + +#include "hal_sleep.h" +#include +#include + +int hal_sleep_ms(uint32_t ms) +{ + int val = 0; + struct timespec t = {0}; + + if (ms < 1000) + { + t.tv_sec = 0; + t.tv_nsec = (long)(ms * 1000000); + } + else + { + t.tv_sec = (time_t)(ms / 1000); + t.tv_nsec = (long)((ms % 1000) * 1000000); + } + + do + { + val = nanosleep(&t, &t); + } while (val != 0 && errno == EINTR); + + return val; +} + +int hal_sleep_us(uint32_t us) +{ + int val = 0; + struct timespec t = {0}; + + if (us < 1000000) + { + t.tv_sec = 0; + t.tv_nsec = (long)(us * 1000); + } + else + { + t.tv_sec = (time_t)(us / 1000000); + t.tv_nsec = (long)((us % 1000000) * 1000); + } + + do + { + val = nanosleep(&t, &t); + } while (val != 0 && errno == EINTR); + + return val; +} + +int hal_sleep_s(uint32_t s) +{ + int val = 0; + struct timespec t = {0}; + + t.tv_sec = (time_t)s; + t.tv_nsec = 0; + + do + { + val = nanosleep(&t, &t); + } while (val != 0 && errno == EINTR); + + return val; +} diff --git a/module/controller/host/hal_sleep.h b/module/controller/host/hal_sleep.h new file mode 100644 index 0000000..d5a2bbb --- /dev/null +++ b/module/controller/host/hal_sleep.h @@ -0,0 +1,10 @@ +#ifndef HAL_SLEEP_H +#define HAL_SLEEP_H + +#include + +int hal_sleep_ms(uint32_t ms); +int hal_sleep_us(uint32_t us); +int hal_sleep_s(uint32_t s); + +#endif diff --git a/module/controller/host/hal_uart.c b/module/controller/host/hal_uart.c new file mode 100644 index 0000000..74d9e8b --- /dev/null +++ b/module/controller/host/hal_uart.c @@ -0,0 +1,425 @@ +/** + * @file hal_uart.c + * @author Rex Huang (rex.huang@rafaelmicro.com) + * @brief + * @version 0.1 + * @date 2023-10-30 + * + * + */ +#define _GNU_SOURCE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utility/config.h" +#include "utility/log.h" +#include "host/hal_sleep.h" +#include "utility/utility.h" +#include "host/hal_uart.h" +#include "daemon/hdlc/core.h" +#include "host/hal_kill.h" + +//============================================================================= +// Constant Definition +//============================================================================= +//============================================================================= +// Macro Definition +//============================================================================= +#define UART_BUFFER_SIZE 4096 + HDLC_HEADER_RAW_SIZE +#define MAX_EPOLL_EVENTS 2 +#define EPOLL_TIMEOUT -1 +#define UNIT_1G 1000000000 +//============================================================================= +// Structure Definition +//============================================================================= +typedef struct notify_private_data +{ + int timer_file_descriptor; +} notify_private_data_t; + +typedef struct uartConfig +{ + unsigned int val; + int symbolic; +} uartConfig_t; + +typedef enum { PROC_HEADER, PROC_DATA } PROC_STATE; +//============================================================================= +// Global Data Definition +//============================================================================= +static int fd_uart; +static int fd_cpcd; +static int fd_cpcd_notify; +static int fd_stop; +static unsigned int drv_baudrate = 0; +static pthread_t rx_drv_thread; +static pthread_t tx_drv_thread; +static pthread_t cleanup_thread; + +uartConfig_t uart_config[] = { + { 9600, B9600 }, + { 115200, B115200 }, + { 500000, B500000 }, + { 2000000, B2000000 }, +}; +//============================================================================= +// Private Function Definition +//============================================================================= +static bool __hdlc_header_validate(uint8_t *hdr) +{ + uint16_t hcs = 0; + if (hdr[HDLC_FLAG_POS] != HDLC_FLAG_VAL) return false; + + hcs = (uint16_t)(hdr[HDLC_HCS_POS] | (hdr[HDLC_HCS_POS + 1] << 8)); + + + if (!core_check_crc_sw(hdr, HDLC_HEADER_SIZE, hcs)) + { + primary_cpcd_debug_counters.invalid_header_checksum++; + log_error("invalid header checksum in driver"); + return false; + } + + return true; +} + +static bool __sync_header(uint8_t *buffer, size_t *pos) +{ + size_t num_header_combination; + + if (*pos < HDLC_HEADER_RAW_SIZE) return false; + + num_header_combination = *pos - HDLC_HEADER_RAW_SIZE + 1; + + for (size_t i = 0; i < num_header_combination; i++) + { + if (__hdlc_header_validate(&buffer[i])) + { + if (i != 0) + { + memmove(&buffer[0], &buffer[i], *pos - i); + *pos -= i; + } + return true; + } + } + memmove(&buffer[0], &buffer[num_header_combination], HDLC_HEADER_RAW_SIZE - 1); + *pos = HDLC_HEADER_RAW_SIZE - 1; + + return false; +} + +static bool __push_valid_hdlc_frame(uint8_t *buffer, size_t *pos) +{ + uint16_t payload_len = 0; + size_t frame_size = 0; + size_t remaining = 0; + + if (*pos < HDLC_HEADER_RAW_SIZE) return false; + + payload_len = (uint16_t)(buffer[HDLC_LENGTH_POS] | (buffer[HDLC_LENGTH_POS + 1] << 8)); + + // log_info("length: %d", payload_len); + frame_size = payload_len + HDLC_HEADER_RAW_SIZE; + + if (frame_size > *pos) return false; + // log_info_hexdump("[uart rx]", buffer, frame_size); + write(fd_cpcd, buffer, frame_size); + + remaining = *pos - frame_size; + memmove(buffer, &buffer[frame_size], remaining); + *pos = remaining; + + return true; +} + +static size_t __hal_uart_get_fd_data(uint8_t *buffer, size_t pos, size_t size) +{ + uint8_t temp[UART_BUFFER_SIZE]; + + CHECK_ERROR(pos >= size); + + const size_t available_space = size - pos - 1; + + ssize_t val = read(fd_uart, temp, available_space); + CHECK_ERROR(val < 0); + + memcpy(&buffer[pos], temp, (size_t)val); + + return (size_t)val; +} + + +static long __drain_ns(uint32_t bytes_left) +{ + uint64_t bytes_per_sec = drv_baudrate / 8; + return (long)(bytes_left * (uint64_t)UNIT_1G / bytes_per_sec); +} + +static void __hal_uart_proc(void) +{ + int length = 0; + static uint8_t uart_buffer[UART_BUFFER_SIZE] = {0}; + ssize_t rval = 0; + ssize_t wval = 0; + struct timespec t = {0}; + + rval = read(fd_cpcd, uart_buffer, sizeof(uart_buffer)); + CHECK_ERROR(rval < 0); + + // log_info_hexdump("[uart tx]", uart_buffer, rval); + wval = write(fd_uart, uart_buffer, (size_t)rval); + CHECK_ERROR(wval < 0); + CHECK_ERROR((size_t)wval != (size_t)rval); + + CHECK_ERROR(ioctl(fd_uart, TIOCOUTQ, &length) < 0); + + clock_gettime(CLOCK_MONOTONIC, &t); + + long ns = __drain_ns((uint32_t)length); + if (t.tv_nsec + ns > UNIT_1G) t.tv_sec += (t.tv_nsec + ns) / UNIT_1G; + t.tv_nsec += ns; + t.tv_nsec %= UNIT_1G; + + wval = write(fd_cpcd_notify, &t, sizeof(t)); + CHECK_ERROR(wval != sizeof(t)); +} + +static void __hal_uart_proc_fd(void) +{ + static uint8_t uart_buffer[UART_BUFFER_SIZE] = {0}; + static size_t pos = 0; + static PROC_STATE state = PROC_HEADER; + + pos += __hal_uart_get_fd_data(uart_buffer, pos, sizeof(uart_buffer)); + + do + { + switch (state) + { + case PROC_HEADER: + if (__sync_header(uart_buffer, &pos)) + { + state = PROC_DATA; + // log_debug_hexdump("PROC_HEADER", uart_buffer, pos); + break; + } + + return; + + case PROC_DATA: + if (__push_valid_hdlc_frame(uart_buffer, &pos)) + { + state = PROC_HEADER; + // log_debug_hexdump("PROC_DATA", uart_buffer, pos); + break; + } + + return; + + default: + break; + } + } while(1); +} + +static void *__hal_uart_cleanup_thd(void *arg) +{ + (void)arg; + + pthread_join(tx_drv_thread, NULL); + pthread_join(rx_drv_thread, NULL); + + log_info("UART thd cancelled"); + + close(fd_uart); + close(fd_cpcd); + close(fd_cpcd_notify); + close(fd_stop); + + pthread_exit(0); + return NULL; +} + +static void *__hal_uart_transmit_thd(void *arg) +{ + bool running = false; + int fd_epoll = 0; + int cnt = 0; + struct epoll_event event[MAX_EPOLL_EVENTS] = + { + {.events = EPOLLIN, .data.fd = fd_cpcd}, + {.events = EPOLLIN, .data.fd = fd_stop} + }; + + (void)arg; + + log_info("[HAL] uart tx thread start"); + + fd_epoll = epoll_create1(EPOLL_CLOEXEC); + CHECK_ERROR(fd_epoll < 0); + + CHECK_ERROR(epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_cpcd, &event[0]) < 0); + CHECK_ERROR(epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_stop, &event[1]) < 0); + + while (!running) + { + do + { + cnt = epoll_wait(fd_epoll, event, MAX_EPOLL_EVENTS, EPOLL_TIMEOUT); + } while ((cnt == -1) && (errno == EINTR)); + + for (int i = 0; i < cnt; i++) + { + if (fd_cpcd == event[i].data.fd) __hal_uart_proc(); + else if (fd_stop == event[i].data.fd) running = true; + } + } + + close(fd_epoll); + return 0; +} + +static void *__hal_uart_receive_thd(void *arg) +{ + bool running = false; + int fd_epoll = 0; + int cnt = 0; + struct epoll_event event[MAX_EPOLL_EVENTS] = + { + {.events = EPOLLIN, .data.fd = fd_uart}, + {.events = EPOLLIN, .data.fd = fd_stop} + }; + + (void)arg; + + log_info("[HAL] uart rx thread start"); + + fd_epoll = epoll_create1(EPOLL_CLOEXEC); + CHECK_ERROR(fd_epoll < 0); + + CHECK_ERROR(epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_uart, &event[0]) < 0); + CHECK_ERROR(epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_stop, &event[1]) < 0); + + while (!running) + { + do + { + cnt = epoll_wait(fd_epoll, event, MAX_EPOLL_EVENTS, EPOLL_TIMEOUT); + } while ((cnt == -1) && (errno == EINTR)); + + for (int i = 0; i < cnt; i++) + { + if (fd_uart == event[i].data.fd) __hal_uart_proc_fd(); + else if (fd_stop == event[i].data.fd) running = true; + } + } + + close(fd_epoll); + return 0; +} + +void hal_uart_assert_rts(bool assert) +{ + int flag = TIOCM_RTS; + CHECK_ERROR(fd_uart < 0); + CHECK_ERROR(ioctl(fd_uart, (assert)? TIOCMBIS : TIOCMBIC, &flag) < 0); +} + +pthread_t hal_uart_init(int *fd_to_cpcd, int *fd_notify_cpcd, const char *device, unsigned int baudrate, bool hardflow) +{ + int fd_sockets[2]; + int fd_sockets_notify[2]; + + // log_info("%s", __FUNCTION__); + log_info("[HAL] dev: %s, baudrate: %d, hardflow: %d", device, baudrate, hardflow); + fd_uart = hal_uart_open(device, baudrate, hardflow); + + hal_sleep_ms(10); + tcflush(fd_uart, TCIOFLUSH); + + CHECK_ERROR(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd_sockets) < 0); + fd_cpcd = fd_sockets[0]; + *fd_to_cpcd = fd_sockets[1]; + + CHECK_ERROR(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd_sockets_notify) < 0); + fd_cpcd_notify = fd_sockets_notify[0]; + *fd_notify_cpcd = fd_sockets_notify[1]; + + fd_stop = hal_kill_init(); + + CHECK_ERROR(pthread_create(&tx_drv_thread, NULL, __hal_uart_transmit_thd, NULL) != 0); + CHECK_ERROR(pthread_create(&rx_drv_thread, NULL, __hal_uart_receive_thd, NULL) != 0); + CHECK_ERROR(pthread_create(&cleanup_thread, NULL, __hal_uart_cleanup_thd, NULL) != 0); + + CHECK_ERROR(pthread_setname_np(tx_drv_thread, "tx_drv_thread") != 0); + CHECK_ERROR(pthread_setname_np(rx_drv_thread, "rx_drv_thread") != 0); + + log_info("[HAL] Opening uart file %s", device); + log_info("[HAL] Init done"); + return cleanup_thread; +} + +// void hal_uart_print_overruns(void) +// { +// struct serial_icounter_struct counters; +// int retval = ioctl(fd_uart, TIOCGICOUNT, &counters); +// CHECK_ERROR(retval < 0); +// log_info("[HAL] Overruns %d,%d", counters.overrun, counters.buf_overrun); +// } + +int hal_uart_open(const char *device, unsigned int baudrate, bool hardflow) +{ + struct termios tty = {0}; + int sym_baudrate = -1; + int fd = 0; + + log_info("opening %s", device); + fd = open(device, O_RDWR | O_CLOEXEC); + CHECK_ERROR(fd < 0); + CHECK_ERROR(tcgetattr(fd, &tty) < 0); + + for (size_t i = 0; i < sizeof(uart_config) / sizeof(uartConfig_t); i++) + { + if (uart_config[i].val == baudrate) sym_baudrate = uart_config[i].symbolic; + } + + if (sym_baudrate < 0) log_info("wrong baudrate: %d", baudrate); + + cfsetispeed(&tty, (speed_t)sym_baudrate); + cfsetospeed(&tty, (speed_t)sym_baudrate); + cfmakeraw(&tty); + + drv_baudrate = baudrate; + + // Nonblocking + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + tty.c_iflag &= (unsigned)~(IXON); + tty.c_iflag &= (unsigned)~(IXOFF); + tty.c_iflag &= (unsigned)~(IXANY); + tty.c_cflag &= (unsigned)~(HUPCL); + tty.c_cflag |= CLOCAL; + tty.c_cflag = hardflow ? (tty.c_cflag | CRTSCTS) : (tty.c_cflag & ~CRTSCTS); + + CHECK_ERROR(tcsetattr(fd, TCSANOW, &tty) < 0); + + hal_sleep_ms(10); + tcflush(fd, TCIOFLUSH); + + return fd; +} \ No newline at end of file diff --git a/module/cpc/cpcd/hal/hal_uart.h b/module/controller/host/hal_uart.h similarity index 94% rename from module/cpc/cpcd/hal/hal_uart.h rename to module/controller/host/hal_uart.h index 77c444f..5b0b61f 100644 --- a/module/cpc/cpcd/hal/hal_uart.h +++ b/module/controller/host/hal_uart.h @@ -1,5 +1,3 @@ - - #ifndef HAL_UART_H #define HAL_UART_H @@ -8,10 +6,8 @@ #include pthread_t hal_uart_init(int *fd_to_cpcd, int *fd_notify_cpcd, const char *device, unsigned int baudrate, bool hardflow); - int hal_uart_open(const char *device, unsigned int baudrate, bool hardflow); void hal_uart_assert_rts(bool assert); - void hal_uart_print_overruns(void); -#endif //HAL_UART_H +#endif diff --git a/module/controller/library/libezmesh.c b/module/controller/library/libezmesh.c index e69de29..a5be9d9 100644 --- a/module/controller/library/libezmesh.c +++ b/module/controller/library/libezmesh.c @@ -0,0 +1,1057 @@ +/** + * @file libezmesh.c + * @author Rex Huang (rex.huang@rafaelmicro.com) + * @brief + * @version 0.1 + * @date 2023-11-02 + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libezmesh.h" +#include "version.h" +#include "utility/utility.h" +#include "host/hal_sleep.h" + +//============================================================================= +// Constant Definition +//============================================================================= +#ifndef DEFAULT_INSTANCE_NAME + #define DEFAULT_INSTANCE_NAME "ezmeshd_0" +#endif + +#define CTRL_SOCKET_TIMEOUT_SEC 2 + +#define DEFAULT_EP_SOCKET_SIZE LIB_EZMESH_READ_MINIMUM_SIZE +//============================================================================= +// Macro Definition +//============================================================================= +#define INIT_EZMESH_RET(type) type __ezmesh_ret = 0 +#define RETURN_EZMESH_RET return __ezmesh_ret +#define SET_EZMESH_RET(error) \ + do { \ + if (__ezmesh_ret == 0) { \ + __ezmesh_ret = error; \ + } \ + } while (0) + +//============================================================================= +// Structure Definition +//============================================================================= +typedef struct +{ + uint8_t id; + int server_sock_fd; + int sock_fd; + pthread_mutex_t sock_fd_lock; + ezmesh_handle_inst_t *lib_handle; +} __ezmesh_ep_t; + +typedef struct +{ + int endpoint_id; + int sock_fd; + pthread_mutex_t sock_fd_lock; + ezmesh_handle_inst_t *lib_handle; +} __ezmesh_ep_event_handle_t; + +//============================================================================= +// Global Data Definition +//============================================================================= +static ezmesh_reset_cb_t saved_reset_cb; +//============================================================================= +// Private Function Definition +//============================================================================= +static ezmesh_reset_cb_t saved_reset_cb; +int ezmesh_deinit(ezmesh_handle_t *handle); + +static void SIGUSR1_handler(int signum) +{ + (void)signum; + if (saved_reset_cb != NULL) saved_reset_cb(); +} + +static int ezmesh_query_exchange(ezmesh_handle_inst_t *lib_handle, int fd, ezmesh_ezmeshd_exchange_type_t type, uint8_t ep_id, + void *payload, size_t payload_sz) +{ + (void)lib_handle; + INIT_EZMESH_RET(int); + ezmesh_croe_exange_buffer_t *query = NULL; + ssize_t bytes_written = 0; + ssize_t bytes_read = 0; + const size_t query_len = sizeof(ezmesh_croe_exange_buffer_t) + payload_sz; + + query = calloc(1, query_len); + if (query == NULL) + { + SET_EZMESH_RET(-ENOMEM); + RETURN_EZMESH_RET; + } + + query->type = type; + query->endpoint_number = ep_id; + if (payload_sz) memcpy(query->payload, payload, payload_sz); + + bytes_written = send(fd, query, query_len, 0); + if (bytes_written < (ssize_t)query_len) + { + if (bytes_written == -1) SET_EZMESH_RET(-errno); + else SET_EZMESH_RET(-EBADE); + goto free_query; + } + + bytes_read = recv(fd, query, query_len, 0); + if (bytes_read != (ssize_t)query_len) + { + if (bytes_read == 0) SET_EZMESH_RET(-ECONNRESET); + else if (bytes_read == -1) SET_EZMESH_RET(-errno); + else SET_EZMESH_RET(-EBADE); + goto free_query; + } + + if (payload_sz) memcpy(payload, query->payload, payload_sz); + + free_query: + free(query); + + RETURN_EZMESH_RET; +} + +static int ezmesh_query_receive(ezmesh_handle_inst_t *lib_handle, int fd, void *payload, size_t payload_sz) +{ + (void)lib_handle; + INIT_EZMESH_RET(int); + ezmesh_croe_exange_buffer_t *query = NULL; + ssize_t bytes_read = 0; + const size_t query_len = sizeof(ezmesh_croe_exange_buffer_t) + payload_sz; + + query = calloc(1, query_len); + if (query == NULL) + { + SET_EZMESH_RET(-ENOMEM); + RETURN_EZMESH_RET; + } + + bytes_read = recv(fd, query, query_len, 0); + if (bytes_read != (ssize_t)query_len) + { + if (bytes_read == 0) SET_EZMESH_RET(-ECONNRESET); + else if (bytes_read == -1) SET_EZMESH_RET(-errno); + else SET_EZMESH_RET(-EBADE); + goto free_query; + } + + if (payload_sz && payload) memcpy(payload, query->payload, payload_sz); + + free_query: + free(query); + RETURN_EZMESH_RET; +} + +static int get_max_write(ezmesh_handle_inst_t *lib_handle) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + uint32_t max_write_size = 0; + + tmp_ret = ezmesh_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, + EXCHANGE_MAX_WRITE_SIZE_QUERY, 0, + (void *)&max_write_size, sizeof(max_write_size)); + + if (tmp_ret == 0) lib_handle->max_write_size = (size_t)max_write_size; + else SET_EZMESH_RET(tmp_ret); + + RETURN_EZMESH_RET; +} +static int get_agent_app_version(ezmesh_handle_inst_t *lib_handle) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + + char version[PROJECT_MAX_VERSION_SIZE]; + + + tmp_ret = ezmesh_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, + EXCHANGE_GET_AGENT_APP_VERSION_QUERY, 0, + (void *)version, PROJECT_MAX_VERSION_SIZE); + if (tmp_ret) + { + SET_EZMESH_RET(tmp_ret); + RETURN_EZMESH_RET; + } + + strncpy(lib_handle->agent_app_version, version, PROJECT_MAX_VERSION_SIZE); + + RETURN_EZMESH_RET; + +} + +static int check_version(ezmesh_handle_inst_t *lib_handle) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + char version[PROJECT_MAX_VERSION_SIZE]; + + strncpy(version, PROJECT_VER, PROJECT_MAX_VERSION_SIZE); + + tmp_ret = ezmesh_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, + EXCHANGE_VERSION_QUERY, 0, + (void *)version, PROJECT_MAX_VERSION_SIZE); + + if (tmp_ret) + { + SET_EZMESH_RET(tmp_ret); + RETURN_EZMESH_RET; + } + + if (strncmp(version, PROJECT_VER, PROJECT_MAX_VERSION_SIZE) != 0) + { + SET_EZMESH_RET(-ELIBBAD); + RETURN_EZMESH_RET; + } + + RETURN_EZMESH_RET; +} + + +static int set_pid(ezmesh_handle_inst_t *lib_handle) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + bool can_connect = false; + ssize_t bytes_written = 0; + const pid_t pid = getpid(); + const size_t set_pid_query_len = sizeof(ezmesh_croe_exange_buffer_t) + sizeof(pid_t); + uint8_t buf[set_pid_query_len]; + ezmesh_croe_exange_buffer_t *set_pid_query = (ezmesh_croe_exange_buffer_t *)buf; + + set_pid_query->type = EXCHANGE_SET_PID_QUERY; + set_pid_query->endpoint_number = 0; + + memcpy(set_pid_query->payload, &pid, sizeof(pid_t)); + + bytes_written = send(lib_handle->ctrl_sock_fd, set_pid_query, set_pid_query_len, 0); + if (bytes_written < (ssize_t)set_pid_query_len) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + + tmp_ret = ezmesh_query_receive(lib_handle, lib_handle->ctrl_sock_fd, &can_connect, sizeof(bool)); + if (tmp_ret == 0) + { + if (!can_connect) + { + SET_EZMESH_RET(-ELIBMAX); + RETURN_EZMESH_RET; + } + } else + { + SET_EZMESH_RET(tmp_ret); + RETURN_EZMESH_RET; + } + + RETURN_EZMESH_RET; +} + + +int libezmesh_init(ezmesh_handle_t *handle, const char *instance_name, ezmesh_reset_cb_t reset_cb) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + ezmesh_handle_inst_t *lib_handle = NULL; + struct sockaddr_un server_addr = { 0 }; + + if (handle == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + lib_handle = calloc(1, sizeof(ezmesh_handle_inst_t)); + if (lib_handle == NULL) + { + SET_EZMESH_RET(-ENOMEM); + RETURN_EZMESH_RET; + } + + saved_reset_cb = reset_cb; + + lib_handle->instance_name = strdup((instance_name == NULL)? DEFAULT_INSTANCE_NAME : instance_name); + if (lib_handle->instance_name == NULL) + { + SET_EZMESH_RET(-errno); + goto free_lib_handle; + } + + /* Create the control socket path */ + int nchars; + const size_t size = sizeof(server_addr.sun_path) - 1; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sun_family = AF_UNIX; + + nchars = snprintf(server_addr.sun_path, size, "%s/%s/ep0.sock", EZMESH_SOCKET_DIR, lib_handle->instance_name); + /* Make sure the path fitted entirely in the struct's static buffer */ + if (nchars < 0 || (size_t)nchars >= size) + { + SET_EZMESH_RET(-ERANGE); + goto free_instance_name; + } + + // Check if control socket exists + if (access(server_addr.sun_path, F_OK) != 0) + { + SET_EZMESH_RET(-errno); + goto free_instance_name; + } + + lib_handle->ctrl_sock_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + if (lib_handle->ctrl_sock_fd < 0) + { + SET_EZMESH_RET(-errno); + goto free_instance_name; + } + + if (connect(lib_handle->ctrl_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) + { + SET_EZMESH_RET(-errno); + goto close_ctrl_sock_fd; + } + + // Set ctrl socket timeout + struct timeval timeout; + timeout.tv_sec = CTRL_SOCKET_TIMEOUT_SEC; + timeout.tv_usec = 0; + + if (setsockopt(lib_handle->ctrl_sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + SET_EZMESH_RET(-errno); + goto close_ctrl_sock_fd; + } + + tmp_ret = check_version(lib_handle); + if (tmp_ret < 0) + { + SET_EZMESH_RET(tmp_ret); + goto close_ctrl_sock_fd; + } + + tmp_ret = get_agent_app_version(lib_handle); + + if (tmp_ret < 0) + { + SET_EZMESH_RET(tmp_ret); + goto close_ctrl_sock_fd; + } + + tmp_ret = set_pid(lib_handle); + if (tmp_ret < 0) + { + SET_EZMESH_RET(tmp_ret); + goto close_ctrl_sock_fd; + } + + // Check if reset callback is define + if (reset_cb != NULL) signal(SIGUSR1, SIGUSR1_handler); + + // Check if control socket exists + if (access(server_addr.sun_path, F_OK) != 0) + { + SET_EZMESH_RET(-errno); + goto close_ctrl_sock_fd; + } + + tmp_ret = get_max_write(lib_handle); + if (tmp_ret < 0) + { + SET_EZMESH_RET(tmp_ret); + goto close_ctrl_sock_fd; + } + + tmp_ret = pthread_mutex_init(&lib_handle->ctrl_sock_fd_lock, NULL); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + goto close_ctrl_sock_fd; + } + + lib_handle->initialized = true; + handle->ptr = (void *)lib_handle; + RETURN_EZMESH_RET; + + close_ctrl_sock_fd: + if (close(lib_handle->ctrl_sock_fd) < 0) SET_EZMESH_RET(-errno); + + free_instance_name: + free(lib_handle->instance_name); + + free_lib_handle: + free(lib_handle); + + RETURN_EZMESH_RET; +} + +int ezmesh_deinit(ezmesh_handle_t *handle) +{ + INIT_EZMESH_RET(int); + ezmesh_handle_inst_t *lib_handle = NULL; + + if (handle->ptr == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + lib_handle = (ezmesh_handle_inst_t *)handle->ptr; + + pthread_mutex_destroy(&lib_handle->ctrl_sock_fd_lock); + + free(lib_handle->instance_name); + free(lib_handle); + + handle->ptr = NULL; + + RETURN_EZMESH_RET; +} + +int libezmesh_reset(ezmesh_handle_t *handle) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + ezmesh_handle_inst_t *lib_handle = NULL; + + if (handle->ptr == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + lib_handle = (ezmesh_handle_inst_t *)handle->ptr; + + ezmesh_handle_inst_t *lib_handle_copy = calloc(1, sizeof(ezmesh_handle_inst_t)); + if (lib_handle_copy == NULL) + { + SET_EZMESH_RET(-ENOMEM); + RETURN_EZMESH_RET; + } + + memcpy(lib_handle_copy, lib_handle, sizeof(ezmesh_handle_inst_t)); + lib_handle_copy->instance_name = strdup(lib_handle->instance_name); + if (lib_handle_copy->instance_name == NULL) + { + free(lib_handle_copy); + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + + // De-init the original handle + if (lib_handle_copy->initialized) + { + tmp_ret = ezmesh_deinit(handle); + if (tmp_ret != 0) + { + // Restore the handle copy on failure + free(lib_handle_copy->instance_name); + lib_handle_copy->instance_name = lib_handle->instance_name; + handle->ptr = (void *)lib_handle_copy; + + SET_EZMESH_RET(tmp_ret); + RETURN_EZMESH_RET; + } + } + + // De-init was successful, invalidate copy + lib_handle_copy->initialized = false; + + // Attemps a connection + tmp_ret = libezmesh_init(handle, lib_handle_copy->instance_name, saved_reset_cb); + if (tmp_ret != 0) + { + hal_sleep_ms(EZMESHD_REBOOT_TIME_MS); // Wait for the minimum time it takes for EZMESHd to reboot + tmp_ret = libezmesh_init(handle, lib_handle_copy->instance_name, saved_reset_cb); + if (tmp_ret != 0) + { + // Restore the handle copy on failure + handle->ptr = (void *)lib_handle_copy; + + SET_EZMESH_RET(tmp_ret); + RETURN_EZMESH_RET; + } + } + + // On success we can free the lib_handle_copy + free(lib_handle_copy->instance_name); + free(lib_handle_copy); + + RETURN_EZMESH_RET; +} + +int libezmesh_open_ep(ezmesh_handle_t handle, ezmesh_ep_t *endpoint, uint8_t id, uint8_t tx_win_size) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + int tmp_ret2 = 0; + bool can_open = false; + ezmesh_handle_inst_t *lib_handle = NULL; + __ezmesh_ep_t *ep = NULL; + struct sockaddr_un ep_addr = { 0 }; + + if (id == EP_SYSTEM || endpoint == NULL || handle.ptr == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + lib_handle = (ezmesh_handle_inst_t *)handle.ptr; + + if (tx_win_size != 1) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + ep_addr.sun_family = AF_UNIX; + + /* Create the endpoint socket path */ + int nchars; + const size_t size = sizeof(ep_addr.sun_path) - 1; + nchars = snprintf(ep_addr.sun_path, size, "%s/%s/ep%d.sock", EZMESH_SOCKET_DIR, lib_handle->instance_name, id); + /* Make sure the path fitted entirely in the struct sockaddr_un's static buffer */ + if (nchars < 0 || (size_t)nchars >= size) + { + SET_EZMESH_RET(-ERANGE); + RETURN_EZMESH_RET; + } + + ep = calloc(1, sizeof(__ezmesh_ep_t)); + if (ep == NULL) + { + SET_EZMESH_RET(-ERANGE); + RETURN_EZMESH_RET; + } + + ep->id = id; + ep->lib_handle = lib_handle; + + tmp_ret = pthread_mutex_lock(&lib_handle->ctrl_sock_fd_lock); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + goto free_endpoint; + } + + tmp_ret = ezmesh_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, + EXCHANGE_OPEN_EP_QUERY, id, + (void *)&can_open, sizeof(can_open)); + + if (tmp_ret) { SET_EZMESH_RET(tmp_ret); } + + tmp_ret2 = pthread_mutex_unlock(&lib_handle->ctrl_sock_fd_lock); + if (tmp_ret2 != 0) + { + SET_EZMESH_RET(-tmp_ret2); + goto free_endpoint; + } + + if (tmp_ret) goto free_endpoint; + + if (can_open == false) + { + SET_EZMESH_RET(-EAGAIN); + goto free_endpoint; + } + + ep->sock_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + if (ep->sock_fd < 0) + { + SET_EZMESH_RET(-errno); + goto free_endpoint; + } + + tmp_ret = connect(ep->sock_fd, (struct sockaddr *)&ep_addr, sizeof(ep_addr)); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + goto close_sock_fd; + } + + tmp_ret = ezmesh_query_receive(lib_handle, ep->sock_fd, (void *)&ep->server_sock_fd, sizeof(ep->server_sock_fd)); + if (tmp_ret) + { + SET_EZMESH_RET(tmp_ret); + goto close_sock_fd; + } + + int ep_socket_size = DEFAULT_EP_SOCKET_SIZE; + tmp_ret = setsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDBUF, &ep_socket_size, sizeof(int)); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-errno); + goto close_sock_fd; + } + + tmp_ret = pthread_mutex_init(&ep->sock_fd_lock, NULL); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + goto close_sock_fd; + } + + endpoint->ptr = (void *)ep; + + SET_EZMESH_RET(ep->sock_fd); + RETURN_EZMESH_RET; + + close_sock_fd: + if (close(ep->sock_fd) < 0) + { + SET_EZMESH_RET(-errno); + } + + free_endpoint: + free(ep); + + RETURN_EZMESH_RET; +} + +int libezmesh_close_ep(ezmesh_ep_t *endpoint) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + ezmesh_handle_inst_t *lib_handle = NULL; + __ezmesh_ep_t *ep = NULL; + + if (endpoint == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + ep = (__ezmesh_ep_t *)endpoint->ptr; + if (ep == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + lib_handle = ep->lib_handle; + + tmp_ret = pthread_mutex_lock(&lib_handle->ctrl_sock_fd_lock); + if (tmp_ret != 0) + { + goto destroy_mutex; + } + + tmp_ret = ezmesh_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, + EXCHANGE_CLOSE_EP_QUERY, ep->id, + (void *)&ep->server_sock_fd, sizeof(ep->server_sock_fd)); + + if (close(ep->sock_fd) < 0) + { + goto unlock_mutex; + } + ep->sock_fd = -1; + + tmp_ret = ezmesh_query_receive(lib_handle, lib_handle->ctrl_sock_fd, NULL, sizeof(int)); + unlock_mutex: + tmp_ret = pthread_mutex_unlock(&lib_handle->ctrl_sock_fd_lock); + + + destroy_mutex: + tmp_ret = pthread_mutex_destroy(&ep->sock_fd_lock); + + free(ep); + endpoint->ptr = NULL; + + RETURN_EZMESH_RET; +} + +ssize_t libezmesh_read_ep(ezmesh_ep_t endpoint, void *buffer, size_t count, ezmesh_ep_read_flags_t flags) +{ + INIT_EZMESH_RET(ssize_t); + int sock_flags = 0; + ssize_t bytes_read = 0; + __ezmesh_ep_t *ep = NULL; + + if (buffer == NULL || count < LIB_EZMESH_READ_MINIMUM_SIZE || endpoint.ptr == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + ep = (__ezmesh_ep_t *)endpoint.ptr; + + + if (flags & EP_READ_FLAG_NON_BLOCKING) + { + sock_flags |= MSG_DONTWAIT; + } + + bytes_read = recv(ep->sock_fd, buffer, count, sock_flags); + if (bytes_read == 0) + { + SET_EZMESH_RET(-ECONNRESET); + } else if (bytes_read < 0) + { + SET_EZMESH_RET(-errno); + } else + { + SET_EZMESH_RET(bytes_read); + } + + RETURN_EZMESH_RET; +} + + +ssize_t libezmesh_write_ep(ezmesh_ep_t endpoint, const void *data, size_t data_length, ezmesh_ep_write_flags_t flags) +{ + INIT_EZMESH_RET(ssize_t); + int sock_flags = 0; + ssize_t bytes_written = 0; + __ezmesh_ep_t *ep = NULL; + + if (endpoint.ptr == NULL || data == NULL || data_length == 0) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + ep = (__ezmesh_ep_t *)endpoint.ptr; + + if (data_length > ep->lib_handle->max_write_size) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + if (flags & EP_WRITE_FLAG_NON_BLOCKING) + { + sock_flags |= MSG_DONTWAIT; + } + + bytes_written = send(ep->sock_fd, data, data_length, sock_flags); + if (bytes_written == -1) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } else + { + SET_EZMESH_RET(bytes_written); + } + assert((size_t)bytes_written == data_length); + + RETURN_EZMESH_RET; +} + +int libezmesh_get_ep_state(ezmesh_handle_t handle, uint8_t id, ep_state_t *state) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + ezmesh_handle_inst_t *lib_handle = NULL; + + if (state == NULL || handle.ptr == NULL || id == EP_SYSTEM) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + lib_handle = (ezmesh_handle_inst_t *)handle.ptr; + + tmp_ret = pthread_mutex_lock(&lib_handle->ctrl_sock_fd_lock); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + RETURN_EZMESH_RET; + } + + + tmp_ret = ezmesh_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, + EXCHANGE_EP_STATUS_QUERY, id, + (void *)state, sizeof(ep_state_t)); + + tmp_ret = pthread_mutex_unlock(&lib_handle->ctrl_sock_fd_lock); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + RETURN_EZMESH_RET; + } + + RETURN_EZMESH_RET; +} + +int libezmesh_set_ep_option(ezmesh_ep_t endpoint, ezmesh_option_t option, const void *optval, size_t optlen) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + __ezmesh_ep_t *ep = NULL; + + if (option == OPTION_NONE || endpoint.ptr == NULL || optval == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + ep = (__ezmesh_ep_t *)endpoint.ptr; + + if (option == OPTION_RX_TIMEOUT) + { + ezmesh_timeval_t *useropt = (ezmesh_timeval_t *)optval; + struct timeval sockopt; + + if (optlen != sizeof(ezmesh_timeval_t)) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + sockopt.tv_sec = useropt->seconds; + sockopt.tv_usec = useropt->microseconds; + + tmp_ret = setsockopt(ep->sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sockopt, (socklen_t)sizeof(sockopt)); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + } else if (option == OPTION_TX_TIMEOUT) + { + ezmesh_timeval_t *useropt = (ezmesh_timeval_t *)optval; + struct timeval sockopt; + + if (optlen != sizeof(ezmesh_timeval_t)) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + sockopt.tv_sec = useropt->seconds; + sockopt.tv_usec = useropt->microseconds; + + tmp_ret = setsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDTIMEO, &sockopt, (socklen_t)sizeof(sockopt)); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + } else if (option == OPTION_BLOCKING) + { + if (optlen != sizeof(bool)) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + tmp_ret = pthread_mutex_lock(&ep->sock_fd_lock); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + RETURN_EZMESH_RET; + } + + int flags = fcntl(ep->sock_fd, F_GETFL); + if (flags < 0) + { + SET_EZMESH_RET(-errno); + + tmp_ret = pthread_mutex_unlock(&ep->sock_fd_lock); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + } + + RETURN_EZMESH_RET; + } + + if (*(bool *)optval == true) + { + flags &= ~O_NONBLOCK; + } else + { + flags |= O_NONBLOCK; + } + + tmp_ret = fcntl(ep->sock_fd, F_SETFL, flags); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + } + + tmp_ret = pthread_mutex_unlock(&ep->sock_fd_lock); + if (tmp_ret != 0) + { + SET_EZMESH_RET(-tmp_ret); + } + + RETURN_EZMESH_RET; + } else if (option == OPTION_SOCKET_SIZE) + { + if (optlen != sizeof(int)) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + if (setsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDBUF, optval, (socklen_t)optlen) != 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + } else + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + RETURN_EZMESH_RET; +} + +int libezmesh_get_ep_option(ezmesh_ep_t endpoint, ezmesh_option_t option, void *optval, size_t *optlen) +{ + INIT_EZMESH_RET(int); + int tmp_ret = 0; + __ezmesh_ep_t *ep = NULL; + + if (option == OPTION_NONE || endpoint.ptr == NULL || optval == NULL || optlen == NULL) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + ep = (__ezmesh_ep_t *)endpoint.ptr; + + if (option == OPTION_RX_TIMEOUT) + { + ezmesh_timeval_t *useropt = (ezmesh_timeval_t *)optval; + struct timeval sockopt; + socklen_t socklen = sizeof(sockopt); + + if (*optlen != sizeof(ezmesh_timeval_t)) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + tmp_ret = getsockopt(ep->sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sockopt, &socklen); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + + // these values are "usually" of type long, so make sure they + // fit in integers (really, they should). + if (sockopt.tv_sec > INT_MAX || sockopt.tv_usec > INT_MAX) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + useropt->seconds = (int)sockopt.tv_sec; + useropt->microseconds = (int)sockopt.tv_usec; + } else if (option == OPTION_TX_TIMEOUT) + { + ezmesh_timeval_t *useropt = (ezmesh_timeval_t *)optval; + struct timeval sockopt; + socklen_t socklen = sizeof(sockopt); + + if (*optlen != sizeof(ezmesh_timeval_t)) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + tmp_ret = getsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDTIMEO, &sockopt, &socklen); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + + if (sockopt.tv_sec > INT_MAX || sockopt.tv_usec > INT_MAX) + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + useropt->seconds = (int)sockopt.tv_sec; + useropt->microseconds = (int)sockopt.tv_usec; + } else if (option == OPTION_BLOCKING) + { + if (*optlen < sizeof(bool)) + { + SET_EZMESH_RET(-ENOMEM); + RETURN_EZMESH_RET; + } + + *optlen = sizeof(bool); + + int flags = fcntl(ep->sock_fd, F_GETFL); + if (flags < 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + + if (flags & O_NONBLOCK) + { + *(bool *)optval = false; + } else + { + *(bool *)optval = true; + } + } else if (option == OPTION_SOCKET_SIZE) + { + socklen_t socklen = (socklen_t)*optlen; + + if (*optlen < sizeof(int)) + { + SET_EZMESH_RET(-ENOMEM); + RETURN_EZMESH_RET; + } + + tmp_ret = getsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDBUF, optval, &socklen); + if (tmp_ret < 0) + { + SET_EZMESH_RET(-errno); + RETURN_EZMESH_RET; + } + + *optlen = (size_t)socklen; + } else if (option == OPTION_MAX_WRITE_SIZE) + { + *optlen = sizeof(size_t); + memcpy(optval, &ep->lib_handle->max_write_size, sizeof(ep->lib_handle->max_write_size)); + } else + { + SET_EZMESH_RET(-EINVAL); + RETURN_EZMESH_RET; + } + + RETURN_EZMESH_RET; +} + +const char *libezmesh_get_lib_ver(void) +{ + return PROJECT_VER; +} + diff --git a/module/controller/library/libezmesh.h b/module/controller/library/libezmesh.h index e69de29..0a69d3b 100644 --- a/module/controller/library/libezmesh.h +++ b/module/controller/library/libezmesh.h @@ -0,0 +1,146 @@ +#ifndef _LIBEZMESH_H +#define _LIBEZMESH_H +#include +#include +#include +#if !defined(__linux__) +#error Wrong platform +#endif +#define EZMESH_ENUM_DECLARE(name) typedef uint8_t name; enum name ## _enum +#define EZMESH_ENUM_GENERIC_DECLARE(name, type) typedef type name; enum name ## _enum +#ifdef __cplusplus +extern "C" +{ +#endif +#define LIB_EZMESH_READ_MINIMUM_SIZE 4087 +EZMESH_ENUM_DECLARE(ep_state_t) +{ + ENDPOINT_STATE_OPEN = 0, + ENDPOINT_STATE_CLOSED, + ENDPOINT_STATE_CLOSING, + ENDPOINT_STATE_ERROR_DEST_UNREACH, + ENDPOINT_STATE_ERROR_FAULT, + EP_STATE_FREED = 6 +}; +EZMESH_ENUM_DECLARE(ezmesh_ep_write_flags_t) +{ + EP_WRITE_FLAG_NONE = 0, ///< No flag + EP_WRITE_FLAG_NON_BLOCKING = (1 << 0) ///< Set this transaction as non-blocking +}; +EZMESH_ENUM_DECLARE(ezmesh_ep_read_flags_t) +{ + EP_READ_FLAG_NONE = 0, ///< No flag + EP_READ_FLAG_NON_BLOCKING = (1 << 0) ///< Set this transaction as non-blocking +}; +EZMESH_ENUM_DECLARE(ezmesh_ep_event_flags_t) +{ + EP_EVENT_FLAG_NONE = 0, ///< No flag + EP_EVENT_FLAG_NON_BLOCKING = (1 << 0) ///< Set this transaction as non-blocking +}; +EZMESH_ENUM_DECLARE(ezmesh_option_t) +{ + OPTION_NONE = 0, + OPTION_BLOCKING, + OPTION_RX_TIMEOUT, + OPTION_TX_TIMEOUT, + OPTION_SOCKET_SIZE, + OPTION_MAX_WRITE_SIZE, +}; +EZMESH_ENUM_DECLARE(ezmesh_ep_event_option_t) +{ + EP_EVENT_OPTION_NONE = 0, + EP_EVENT_OPTION_BLOCKING, + EP_EVENT_OPTION_READ_TIMEOUT, +}; +EZMESH_ENUM_DECLARE(ezmesh_srv_ep_id_t) +{ + EP_SYSTEM = 0, + EP_ZIGBEE = 5, + EP_OPENTHREAD = 9, + EP_15_4 = 12, + EP_CLI = 13, + EP_BT_RCP = 14 +}; +EZMESH_ENUM_DECLARE(ezmesh_user_ep_id_t) +{ + EP_USER_ID_0 = 90, + EP_USER_ID_1 = 91, + EP_USER_ID_2 = 92, + EP_USER_ID_3 = 93, + EP_USER_ID_4 = 94, + EP_USER_ID_5 = 95, + EP_USER_ID_6 = 96, + EP_USER_ID_7 = 97, + EP_USER_ID_8 = 98, + EP_USER_ID_9 = 99, +}; +EZMESH_ENUM_DECLARE(ezmesh_evt_type_t) +{ + EVT_EP_UNKNOWN = 0, + EVT_EP_OPENED = 1, + EVT_EP_CLOSED = 2, + EVT_EP_CLOSING = 3, + EVT_EP_ERROR_DESTINATION_UNREACHABLE = 4, + EVT_EP_ERROR_SECURITY_INCIDENT = 5, + EVT_EP_ERROR_FAULT = 6, +}; +EZMESH_ENUM_GENERIC_DECLARE(ezmesh_ezmeshd_exchange_type_t, uint8_t) +{ + EXCHANGE_EP_STATUS_QUERY, + EXCHANGE_OPEN_EP_QUERY, + EXCHANGE_MAX_WRITE_SIZE_QUERY, + EXCHANGE_VERSION_QUERY, + EXCHANGE_CLOSE_EP_QUERY, + EXCHANGE_SET_PID_QUERY, + EXCHANGE_GET_AGENT_APP_VERSION_QUERY, +}; + +typedef struct +{ + int ctrl_sock_fd; + pthread_mutex_t ctrl_sock_fd_lock; + size_t max_write_size; + char agent_app_version[16]; + char *instance_name; + bool initialized; +} ezmesh_handle_inst_t; + +typedef struct +{ + ezmesh_ezmeshd_exchange_type_t type; + uint8_t endpoint_number; + uint8_t payload[]; +} ezmesh_croe_exange_buffer_t; +typedef struct +{ + ezmesh_evt_type_t type; + uint8_t endpoint_number; + uint32_t payload_length; + uint8_t payload[]; +} ezmesh_ezmeshd_event_buffer_t; +typedef struct +{ + void *ptr; +} ezmesh_handle_t, ezmesh_ep_t; +typedef struct +{ + int seconds; + int microseconds; +} ezmesh_timeval_t; +typedef uint8_t ezmesh_evts_flags_t; +typedef void (*ezmesh_reset_cb_t) (void); +typedef void (*ezmesh_ep_state_callback_t) (uint8_t endpoint_id, ep_state_t endpoint_state); +int libezmesh_init(ezmesh_handle_t *handle, const char *instance_name, ezmesh_reset_cb_t reset_cb); +int libezmesh_reset(ezmesh_handle_t *handle); +int libezmesh_open_ep(ezmesh_handle_t handle, ezmesh_ep_t *endpoint, uint8_t id, uint8_t tx_win_size); +int libezmesh_close_ep(ezmesh_ep_t *endpoint); +ssize_t libezmesh_read_ep(ezmesh_ep_t endpoint, void *buffer, size_t count, ezmesh_ep_read_flags_t flags); +ssize_t libezmesh_write_ep(ezmesh_ep_t endpoint, const void *data, size_t data_length, ezmesh_ep_write_flags_t flags); +int libezmesh_get_ep_state(ezmesh_handle_t handle, uint8_t id, ep_state_t *state); +int libezmesh_set_ep_option(ezmesh_ep_t endpoint, ezmesh_option_t option, const void *optval, size_t optlen); +int libezmesh_get_ep_option(ezmesh_ep_t endpoint, ezmesh_option_t option, void *optval, size_t *optlen); +const char *libezmesh_get_lib_ver(void); +#ifdef __cplusplus +} +#endif +#endif // _LIBEZMESH_H diff --git a/module/controller/main.c b/module/controller/main.c new file mode 100644 index 0000000..0dc9e1c --- /dev/null +++ b/module/controller/main.c @@ -0,0 +1,154 @@ +#define _GNU_SOURCE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "host/hal_kill.h" +#include "host/hal_epoll.h" +#include "daemon/controller.h" +#include "utility/config.h" +#include "utility/log.h" +#include "host/hal_sleep.h" +#include "version.h" + +#include "host/hal_uart.h" + +//============================================================================= +// Constant Definition +//============================================================================= + +//============================================================================= +// Macro Definition +//============================================================================= + +//============================================================================= +// Structure Definition +//============================================================================= + +//============================================================================= +// Global Data Definition +//============================================================================= + +typedef struct { + pthread_t thread; + sigset_t mask; + int crash_event_fd; + int crash_signal_fd; + int graceful_exit_fd; + int crash_epoll; + int socket; + int socket_notify; +} ez_daemon_t; + +static ez_daemon_t ez_daemon; + +pthread_t hal_thread = 0; +pthread_t primary_cpcd_thread = 0; + +static int exit_status = EXIT_SUCCESS; + +char **argv_g = 0; +int argc_g = 0; + +//============================================================================= +// Private Function Definition +//============================================================================= + +void main_wait_crash_or_graceful_exit(void); + +int main(int argc, char *argv[]) { + struct epoll_event event = {.events = EPOLLIN}; + + argc_g = argc; + argv_g = argv; + + ez_daemon.thread = pthread_self(); + pthread_setname_np(ez_daemon.thread, "ezmesh"); + + sigemptyset(&ez_daemon.mask); + sigaddset(&ez_daemon.mask, SIGINT); + sigaddset(&ez_daemon.mask, SIGTERM); + sigaddset(&ez_daemon.mask, SIGQUIT); + + CHECK_ERROR(sigprocmask(SIG_BLOCK, &ez_daemon.mask, NULL) == -1); + + ez_daemon.crash_epoll = epoll_create1(EPOLL_CLOEXEC); + CHECK_ERROR(ez_daemon.crash_epoll < 0); + + ez_daemon.crash_event_fd = eventfd(0, EFD_CLOEXEC); + CHECK_ERROR(ez_daemon.crash_event_fd == -1); + + CHECK_ERROR(epoll_ctl(ez_daemon.crash_epoll, EPOLL_CTL_ADD, ez_daemon.crash_event_fd, &event) < 0); + + ez_daemon.graceful_exit_fd = eventfd(0, EFD_CLOEXEC); + CHECK_ERROR(ez_daemon.graceful_exit_fd == -1); + + CHECK_ERROR(epoll_ctl(ez_daemon.crash_epoll, EPOLL_CTL_ADD, ez_daemon.graceful_exit_fd, &event) < 0); + + ez_daemon.crash_signal_fd = signalfd(-1, &ez_daemon.mask, SFD_CLOEXEC); + CHECK_ERROR(ez_daemon.crash_signal_fd == -1); + + CHECK_ERROR(epoll_ctl(ez_daemon.crash_epoll, EPOLL_CTL_ADD, ez_daemon.crash_signal_fd, &event) < 0); + hal_epoll_init(); + + log_info("[Daemon v%s] [Library v%d] [Protocol v%d]", PROJECT_VER, + LIBRARY_API_VERSION, PROTOCOL_VERSION); + log_info("Git commit: %s / branch: %s", GIT_SHA1, GIT_REFSPEC); + log_info("Sources hash: %s", SOURCES_HASH); + handle_cli_arg(argc, argv); + + log_info("Daemon Starting ... "); + hal_thread = hal_uart_init(&ez_daemon.socket, &ez_daemon.socket_notify, + config.ep_hw.port, config.ep_hw.baudrate, + config.ep_hw.flowcontrol); + + primary_cpcd_thread = controller_init(ez_daemon.socket, ez_daemon.socket_notify); + main_wait_crash_or_graceful_exit(); + return 0; +} + +static void exit_daemon(void) { + hal_kill_signal(); + pthread_join(hal_thread, NULL); + controller_kill_signal(); + pthread_join(primary_cpcd_thread, NULL); + log_info("Daemon exit : status %s", (exit_status == 0) ? "EXIT_SUCCESS" : "EXIT_FAILURE"); + exit(exit_status); +} + +void main_wait_crash_or_graceful_exit(void) { + int event_count; + struct epoll_event events; + + do { + event_count = epoll_wait(ez_daemon.crash_epoll, &events, 1, -1); + } while (errno == EINTR && event_count < 0); + + CHECK_ERROR(event_count <= 0); + + exit_daemon(); +} + +void signal_crash(void) { + uint64_t event_value; + exit_status = EXIT_FAILURE; + + hal_sleep_s(1); + if (pthread_self() == ez_daemon.thread) exit_daemon(); + else write(ez_daemon.crash_event_fd, &event_value, sizeof(event_value)); + + pthread_exit(0); +} \ No newline at end of file diff --git a/module/controller/utility/config.c b/module/controller/utility/config.c index e69de29..b08a7ed 100644 --- a/module/controller/utility/config.c +++ b/module/controller/utility/config.c @@ -0,0 +1,269 @@ + +/* inih -- simple .INI file parser +SPDX-License-Identifier: BSD-3-Clause +Copyright (C) 2009-2020, Ben Hoyt +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: https://github.com/benhoyt/inih +*/ +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "log.h" + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +sys_config config; + +/* Used by ini_parse_string() to keep track of string parsing state. */ +typedef struct { + const char *ptr; + size_t num_left; +} ini_parse_string_ctx; + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char *rstrip(char *s) { + char *p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char *lskip(const char *s) { + while (*s && isspace((unsigned char)(*s))) + s++; + return (char *)s; +} + +/* Return pointer to first char (of chars) or inline comment in given string, + or pointer to NUL at end of string if neither found. Inline comment must + be prefixed by a whitespace character to register as a comment. */ +static char *find_chars_or_comment(const char *s, const char *chars) { +#if INI_ALLOW_INLINE_COMMENTS + int was_space = 0; + while (*s && (!chars || !strchr(chars, *s)) && + !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { + was_space = isspace((unsigned char)(*s)); + s++; + } +#else + while (*s && (!chars || !strchr(chars, *s))) { + s++; + } +#endif + return (char *)s; +} + +/* Similar to strncpy, but ensures dest (size bytes) is + NUL-terminated, and doesn't pad with NULs. */ +static char *strncpy0(char *dest, const char *src, size_t size) { + /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */ + size_t i; + for (i = 0; i < size - 1 && src[i]; i++) + dest[i] = src[i]; + dest[i] = '\0'; + return dest; +} + +/* See documentation in header file. */ +static int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, + void *user) { + /* Uses a fair bit of stack (use heap instead if you need to) */ + char line[INI_MAX_LINE]; + size_t max_line = INI_MAX_LINE; + + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char *start; + char *end; + char *name; + char *value; + int lineno = 0; + int error = 0; + +#if INI_HANDLER_LINENO +#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) +#else +#define HANDLER(u, s, n, v) handler(u, s, n, v) +#endif + + /* Scan through stream line by line */ + while (reader(line, (int)max_line, stream) != NULL) { + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (strchr(INI_START_COMMENT_PREFIXES, *start)) { + /* Start-of-line comment */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { +#if INI_ALLOW_INLINE_COMMENTS + end = find_chars_or_comment(start, NULL); + if (*end) + *end = '\0'; + rstrip(start); +#endif + /* Non-blank line with leading whitespace, treat as continuation + of previous name's value (as per Python configparser). */ + if (!HANDLER(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_chars_or_comment(start + 1, "]"); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; +#if INI_CALL_HANDLER_ON_NEW_SECTION + if (!HANDLER(user, section, NULL, NULL) && !error) + error = lineno; +#endif + } else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } else if (*start) { + /* Not a comment, must be a name[=:]value pair */ + end = find_chars_or_comment(start, "=:"); + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = end + 1; +#if INI_ALLOW_INLINE_COMMENTS + end = find_chars_or_comment(value, NULL); + if (*end) + *end = '\0'; +#endif + value = lskip(value); + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!HANDLER(user, section, name, value) && !error) + error = lineno; + } else if (!error) { + /* No '=' or ':' found on name[=:]value line */ +#if INI_ALLOW_NO_VALUE + *end = '\0'; + name = rstrip(start); + if (!HANDLER(user, section, name, NULL) && !error) + error = lineno; +#else + error = lineno; +#endif + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + return error; +} + +/* See documentation in header file. */ +static int ini_parse_file(FILE *file, ini_handler handler, void *user) { + return ini_parse_stream((ini_reader)fgets, file, handler, user); +} + +/* See documentation in header file. */ +int ini_parse(const char *filename, ini_handler handler, void *user) { + FILE *file; + int error; + config.stats_interval = 0; + log_info("laod config file: %s", filename); + file = fopen(filename, "r"); + if (!file) return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +} + +int config_handler(void *user, const char *section, const char *name, + const char *value) { + #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 + sys_config *pc = (sys_config *)user; + log_debug("load %s, %s, %s", section, name, value); + + if (MATCH("EZMESH_CONF", "name")) pc->ep_hw.name = strdup(value); + else if (MATCH("EZMESH_CONF", "type")) pc->ep_hw.type = atoi(value); + else if (MATCH("EZMESH_CONF", "port")) pc->ep_hw.port = strdup(value); + else if (MATCH("EZMESH_CONF", "baudrate")) pc->ep_hw.baudrate = (unsigned int)atoi(value); + else if (MATCH("EZMESH_CONF", "flowcontrol")) pc->ep_hw.flowcontrol = (uint8_t)atoi(value); + else if (MATCH("EZMESH_CONF", "socket_path")) pc->ep_hw.socket_path = strdup(value); + else if (MATCH("log", "level")) pc->log_level = atoi(value); + else if (MATCH("log", "mode")) pc->log_mode = atoi(value); + else { + log_error("Nn match Config, label: %s, value: %s", section, name); + return 0; + } + return 1; +} + +const struct option argv_list[] = +{ + { "config", required_argument, 0, 'c' }, + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { 0, 0, 0, 0 } +}; + +static void config_print_help(int exit_code) +{ + log_info("Start EZMESH daemon\n Usage:\n"); + log_info("\t-c/--config : Set config file.\n"); + log_info("\t-v/--version : Show version\n"); + log_info("\t-h/--help : Help message.\n"); + exit(exit_code); +} + +static void config_print_version(int exit_code) +{ + log_info("version: %s %s\n", GIT_REFSPEC, GIT_SHA1); + exit(exit_code); +} + +void handle_cli_arg(int argc, char *argv[]) +{ + int opt; + + while (1) + { + opt = getopt_long(argc, argv, "c:h:v", argv_list, NULL); + if (opt == -1) break; + switch (opt) + { + case 'c':{ + if (ini_parse(optarg, config_handler, &config) < 0) log_error("Load Config file Failed"); + log_set_info(config.log_mode, config.log_level); + break;} + case 'v':{ config_print_version(0); break;} + case 'h':{ config_print_help(0); break;} + default:{ config_print_help(1); break;} + } + } +} + + +void config_restart(char **argv) +{ + log_info("Restarting EzMesh..."); + execv("/proc/self/exe", argv); +} \ No newline at end of file diff --git a/module/controller/utility/config.h b/module/controller/utility/config.h index e69de29..57c530f 100644 --- a/module/controller/utility/config.h +++ b/module/controller/utility/config.h @@ -0,0 +1,127 @@ + +/* inih -- simple .INI file parser +SPDX-License-Identifier: BSD-3-Clause +Copyright (C) 2009-2020, Ben Hoyt +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: https://github.com/benhoyt/inih +*/ +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef enum +{ + EP_TYPE_UART, + EP_TYPE_SPI +}ez_ep_type_t; + +typedef struct +{ + const char *name; + ez_ep_type_t type; + const char *port; + const char *socket_path; + unsigned int baudrate; + uint8_t flowcontrol; +}ez_ep_t; + + +typedef struct { + int log_mode; + int log_level; + ez_ep_t ep_hw; + int stats_interval; +} sys_config; + +extern sys_config config; + +/* Nonzero if ini_handler callback should accept lineno parameter. */ +#ifndef INI_HANDLER_LINENO +#define INI_HANDLER_LINENO 0 +#endif + +/* Typedef for prototype of handler function. */ +#if INI_HANDLER_LINENO +typedef int (*ini_handler)(void *user, const char *section, const char *name, + const char *value, int lineno); +#else +typedef int (*ini_handler)(void *user, const char *section, const char *name, + const char *value); +#endif + +/* Typedef for prototype of fgets-style reader function. */ +typedef char *(*ini_reader)(char *str, int num, void *stream); + +int ini_parse(const char *filename, ini_handler handler, void *user); + +int config_handler(void *user, const char *section, const char *name, + const char *value); + +void handle_cli_arg(int argc, char *argv[]); +void config_restart(char **argv); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + configparser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See https://github.com/benhoyt/inih/issues/21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Chars that begin a start-of-line comment. Per Python configparser, allow + both ; and # comments at the start of a line by default. */ +#ifndef INI_START_COMMENT_PREFIXES +#define INI_START_COMMENT_PREFIXES ";#" +#endif + +/* Nonzero to allow inline comments (with valid inline comment characters + specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match + Python 3.2+ configparser behaviour. */ +#ifndef INI_ALLOW_INLINE_COMMENTS +#define INI_ALLOW_INLINE_COMMENTS 1 +#endif +#ifndef INI_INLINE_COMMENT_PREFIXES +#define INI_INLINE_COMMENT_PREFIXES ";" +#endif + +/* Maximum line length for any line in INI file (stack or heap). Note that + this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +/* Stop parsing on first error (default is to keep parsing). */ +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 1 +#endif + +/* Nonzero to call the handler at the start of each new section (with + name and value NULL). Default is to only call the handler on + each name=value pair. */ +#ifndef INI_CALL_HANDLER_ON_NEW_SECTION +#define INI_CALL_HANDLER_ON_NEW_SECTION 0 +#endif + +/* Nonzero to allow a name without a value (no '=' or ':' on the line) and + call the handler with value NULL in this case. Default is to treat + no-value lines as an error. */ +#ifndef INI_ALLOW_NO_VALUE +#define INI_ALLOW_NO_VALUE 0 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* INI_H */ \ No newline at end of file diff --git a/module/controller/utility/list.c b/module/controller/utility/list.c index e69de29..695fecd 100644 --- a/module/controller/utility/list.c +++ b/module/controller/utility/list.c @@ -0,0 +1,41 @@ + +#include "list.h" +#include + +void list_init(list_node_t **head) { *head = 0; } + +void list_push(list_node_t **head, list_node_t *item) { + item->node = *head; + *head = item; +} + +void list_push_back(list_node_t **head, list_node_t *item) { + list_node_t **node_ptr = head; + + while (*node_ptr != NULL) node_ptr = &((*node_ptr)->node); + item->node = NULL; + *node_ptr = item; +} + +list_node_t *list_pop(list_node_t **head) { + list_node_t *item; + + item = *head; + if (item == NULL) return NULL; + *head = item->node; + item->node = NULL; + return (item); +} + +void list_remove(list_node_t **head, list_node_t *item) { + list_node_t **node_ptr; + node_ptr = head; + while (*node_ptr != NULL) { + if (*node_ptr == item) { + *node_ptr = item->node; + break; + } + node_ptr = &((*node_ptr)->node); + } + return; +} diff --git a/module/controller/utility/list.h b/module/controller/utility/list.h index e69de29..9f549ac 100644 --- a/module/controller/utility/list.h +++ b/module/controller/utility/list.h @@ -0,0 +1,40 @@ +#ifndef LIST_H +#define LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +// List node type +typedef struct slist_node list_node_t; + +// List node +struct slist_node { + list_node_t *node; // < List node +}; + +#define SLIST_ENTRY(ptr, T, member) \ + (T *)((void *)(ptr) - ((void *)(&((T *)0)->member))) + +// #define SLIST_ENTRY MEM_INDEX + +#define SLIST_FOR_EACH(slist_head, iterator) \ + for ((iterator) = (slist_head); (iterator) != NULL; \ + (iterator) = (iterator)->node) + +#define SLIST_FOR_EACH_ENTRY(slist_head, entry, type, member) \ + for ((entry) = SLIST_ENTRY(slist_head, type, member); \ + (type *)(entry) != SLIST_ENTRY(NULL, type, member); \ + (entry) = SLIST_ENTRY((entry)->member.node, type, member)) + +void list_init(list_node_t **head); +void list_push(list_node_t **head, list_node_t *item); +void list_push_back(list_node_t **head, list_node_t *item); +list_node_t *list_pop(list_node_t **head); +void list_remove(list_node_t **head, list_node_t *item); + +#ifdef __cplusplus +} +#endif + +#endif /* LIST_H */ diff --git a/module/controller/utility/log.c b/module/controller/utility/log.c index e69de29..110990d 100644 --- a/module/controller/utility/log.c +++ b/module/controller/utility/log.c @@ -0,0 +1,123 @@ + +#include +#include "log.h" + +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + +static struct { + void *udata; + log_LockFn lock; + int level; + int mode; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char *level_strings[] = {"TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL", "CRASH"}; + +static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m", "\x1b[35m"}; + +static void stdout_callback(log_Event *ev) { + char buf[16]; + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; + + if (L.mode == LOG_MODE_SYS) fprintf(ev->udata, "%s %s%-5s\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level]); + else fprintf(ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level], ev->file, ev->line); + + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void stdout_callback_hex(log_Event *ev, const char *tag, uint8_t *data, const size_t len) { + char buf[16]; + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; + if (L.mode == LOG_MODE_SYS) fprintf(ev->udata, "%s %s%-5s\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level]); + else fprintf(ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level], ev->file, ev->line); + fprintf(ev->udata, "%s ", tag); + + for (size_t i = 0; i < len; ++i) fprintf(ev->udata, "%02X ", data[i]); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +// static void file_callback(log_Event *ev) { +// char buf[64]; +// buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; +// fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line); +// vfprintf(ev->udata, ev->fmt, ev->ap); +// fprintf(ev->udata, "\n"); +// fflush(ev->udata); +// } + +static void lock(void) { if (L.lock) L.lock(true, L.udata); } + +static void unlock(void) { if (L.lock) L.lock(false, L.udata); } + +void log_set_info(int mode, int level) { + if (mode == 2) L.quiet = true; + L.mode = mode; + L.level = level; +} + +static void init_event(log_Event *ev, void *udata) { + if (!ev->time) { + time_t t = time(NULL); + ev->time = localtime(&t); + } + ev->udata = udata; +} + +void log_dump(int level, const char *file, int line, const char *tag, const void *data, const size_t len) { + log_Event ev = { + .file = file, + .line = line, + .level = level, + }; + + lock(); + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + stdout_callback_hex(&ev, tag, (uint8_t *)data, len); + } + unlock(); + if (level == LOG_CRASH) { signal_crash(); } +} + +void log_log(int level, const char *file, int line, const char *fmt, ...) { + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; + + lock(); + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + unlock(); + if (level == LOG_CRASH) { signal_crash(); } +} + diff --git a/module/controller/utility/log.h b/module/controller/utility/log.h index e69de29..b9cd627 100644 --- a/module/controller/utility/log.h +++ b/module/controller/utility/log.h @@ -0,0 +1,65 @@ + +#ifndef LOG_H +#define LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include + + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL, LOG_CRASH }; +enum { LOG_MODE_SYS, LOG_MODE_DEV }; + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) +#define log_crash(...) log_log(LOG_CRASH, __FILE__, __LINE__, __VA_ARGS__) + +#define log_trace_hexdump(...) log_dump(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug_hexdump(...) log_dump(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info_hexdump(...) log_dump(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn_hexdump(...) log_dump(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error_hexdump(...) log_dump(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal_hexdump(...) log_dump(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) +#define log_crash_hexdump(...) log_dump(LOG_CRASH, __FILE__, __LINE__, __VA_ARGS__) + +__attribute__((noreturn)) void signal_crash(void); + +#define CHECK_WARN(cond) {if (cond) { log_warn("Warn... ");}} +#define CHECK_ERROR(cond) {if (cond) { log_error("Error: Crash!!!"); signal_crash();}} +#define CHECK_FATAL(cond) {if (cond) { log_fatal("Error: Fatal!!!"); signal_crash();}} +#define FATAL(...) do{ log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__); signal_crash(); }while(0) + +const char *log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); +void log_set_info(int mode, int level); +void log_log(int level, const char *file, int line, const char *fmt, ...); +void log_dump(int level, const char *file, int line, const char *tag, const void *data, const size_t len); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/module/controller/utility/utility.c b/module/controller/utility/utility.c index e69de29..b2e6d70 100644 --- a/module/controller/utility/utility.c +++ b/module/controller/utility/utility.c @@ -0,0 +1,41 @@ + +#include + +#include "log.h" +#include "utility.h" + +#define SYS_ERROR(cond, tmp) {if(cond){ free(tmp); return 0; }} + +int recursive_mkdir(const char *dir, size_t len, const mode_t mode) { + char *tmp = NULL; + char *p = NULL; + struct stat sb; + int ret; + + tmp = (char *)calloc(1, len + 1); + CHECK_ERROR(tmp == NULL); + ret = snprintf(tmp, len + 1, "%s", dir); + CHECK_ERROR(ret < 0 || (size_t)ret >= (len + 1)); + + /* remove trailing slash */ + if (tmp[len - 1] == '/') tmp[len - 1] = '\0'; + + /* check if path exists and is a directory */ + if (stat(tmp, &sb) == 0) {SYS_ERROR(S_ISDIR(sb.st_mode), tmp); } + + /* recursive mkdir */ + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = 0; + /* test path */ + if (stat(tmp, &sb) != 0) {SYS_ERROR(mkdir(tmp, mode) < 0, tmp);} /* path does not exist - create directory */ + else {SYS_ERROR(!S_ISDIR(sb.st_mode), tmp);} + *p = '/'; + } + } + + /* test path */ + if (stat(tmp, &sb) != 0) {SYS_ERROR(mkdir(tmp, mode) < 0, tmp);} /* path does not exist - create directory */ + else {SYS_ERROR(!S_ISDIR(sb.st_mode), tmp);} + return 0; +} \ No newline at end of file diff --git a/module/controller/utility/utility.h b/module/controller/utility/utility.h index e69de29..150cab3 100644 --- a/module/controller/utility/utility.h +++ b/module/controller/utility/utility.h @@ -0,0 +1,76 @@ + +#ifndef UTLI_H +#define UTLI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define MEM_SIZEOF(T, m) (sizeof(((T *)0)->m)) +#define MEM_INDEX(p, t, m) (t *)((uintptr_t)(p) - ((uintptr_t)(&((t *)0)->m))) +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define PAD_TO_ALIGNMENT(x, b) (((size_t)(x) + ((size_t)(b) - (size_t)1)) & ~((size_t)(b) - (size_t)1)) + +int recursive_mkdir(const char *dir, size_t len, const mode_t mode); + + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define __swap_le64(x) (x) +#define __swap_le32(x) (x) +#define __swap_le16(x) (x) +#define __swap_be64(x) __builtin_bswap64(x) +#define __swap_be32(x) __builtin_bswap32(x) +#define __swap_be16(x) __builtin_bswap16(x) +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define __swap_le64(x) __builtin_bswap64(x) +#define __swap_le32(x) __builtin_bswap32(x) +#define __swap_le16(x) __builtin_bswap16(x) +#define __swap_be64(x) (x) +#define __swap_be32(x) (x) +#define __swap_be16(x) (x) +#else +#error "Unsupported endianness" +#endif + +static inline uint64_t cpu_to_le64(uint64_t val) { return __swap_le64(val); } +static inline uint64_t le64_to_cpu(uint64_t val) { return __swap_le64(val); } +static inline uint32_t cpu_to_le32(uint32_t val) { return __swap_le32(val); } +static inline uint32_t le32_to_cpu(uint32_t val) { return __swap_le32(val); } +static inline uint16_t cpu_to_le16(uint16_t val) { return __swap_le16(val); } +static inline uint16_t le16_to_cpu(uint16_t val) { return __swap_le16(val); } +static inline uint64_t cpu_to_be64(uint64_t val) { return __swap_be64(val); } +static inline uint64_t be64_to_cpu(uint64_t val) { return __swap_be64(val); } +static inline uint32_t cpu_to_be32(uint32_t val) { return __swap_be32(val); } +static inline uint32_t be32_to_cpu(uint32_t val) { return __swap_be32(val); } +static inline uint16_t cpu_to_be16(uint16_t val) { return __swap_be16(val); } +static inline uint16_t be16_to_cpu(uint16_t val) { return __swap_be16(val); } +static inline void cpu_to_le64s(uint64_t *val) { *val = cpu_to_le64(*val); } +static inline void le64_to_cpus(uint64_t *val) { *val = le64_to_cpu(*val); } +static inline void cpu_to_le32s(uint32_t *val) { *val = cpu_to_le32(*val); } +static inline void le32_to_cpus(uint32_t *val) { *val = le32_to_cpu(*val); } +static inline void cpu_to_le16s(uint16_t *val) { *val = cpu_to_le16(*val); } +static inline void le16_to_cpus(uint16_t *val) { *val = le16_to_cpu(*val); } +static inline void cpu_to_be64s(uint64_t *val) { *val = cpu_to_be64(*val); } +static inline void be64_to_cpus(uint64_t *val) { *val = be64_to_cpu(*val); } +static inline void cpu_to_be32s(uint32_t *val) { *val = cpu_to_be32(*val); } +static inline void be32_to_cpus(uint32_t *val) { *val = be32_to_cpu(*val); } +static inline void cpu_to_be16s(uint16_t *val) { *val = cpu_to_be16(*val); } +static inline void be16_to_cpus(uint16_t *val) { *val = be16_to_cpu(*val); } + +#define cpu_to_le64p(val) cpu_to_le64(*(val)) +#define le64_to_cpup(val) le64_to_cpu(*(val)) +#define cpu_to_le32p(val) cpu_to_le32(*(val)) +#define le32_to_cpup(val) le32_to_cpu(*(val)) +#define cpu_to_le16p(val) cpu_to_le16(*(val)) +#define le16_to_cpup(val) le16_to_cpu(*(val)) + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/module/cpc/cpcd/utility/version.h.in b/module/controller/utility/version.h.in similarity index 79% rename from module/cpc/cpcd/utility/version.h.in rename to module/controller/utility/version.h.in index 30092e4..0b069a4 100644 --- a/module/cpc/cpcd/utility/version.h.in +++ b/module/controller/utility/version.h.in @@ -3,8 +3,8 @@ #ifndef VERSION_H #define VERSION_H -#define LIBRARY_API_VERSION @CPC_LIBRARY_API_VERSION@ -#define PROTOCOL_VERSION @CPC_PROTOCOL_VERSION@ +#define LIBRARY_API_VERSION @EZMESH_LIBRARY_API_VERSION@ +#define PROTOCOL_VERSION @EZMESH_PROTOCOL_VERSION@ #define SOURCES_HASH "@SOURCES_HASH@" #define PROJECT_NAME "@PROJECT_NAME@" #define PROJECT_VER "@PROJECT_VERSION@" diff --git a/module/cpc/CMakeLists.txt b/module/cpc/CMakeLists.txt deleted file mode 100644 index 3c0affe..0000000 --- a/module/cpc/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -ext_add_subdirectory(cpcd) -ext_add_subdirectory(cpcd-system) \ No newline at end of file diff --git a/module/cpc/cpcd-system/CMakeLists.txt b/module/cpc/cpcd-system/CMakeLists.txt deleted file mode 100644 index cdfdc7c..0000000 --- a/module/cpc/cpcd-system/CMakeLists.txt +++ /dev/null @@ -1,138 +0,0 @@ -add_executable(cpc-upgrade - src/upgrade/cpc-upgrade.c - src/upgrade/fsm.c) - -target_link_libraries(cpc-upgrade - cpc - util - pthread -) - -add_executable(cpc-zbbackup - src/zbbackup/cpc-zbbackup.c - src/zbbackup/fsm.c - ) - -target_link_libraries(cpc-zbbackup - cpc - util - pthread -) - - -get_target_property(CPC_SOURCE_DIR cpc SOURCE_DIR) -target_include_directories(cpc-upgrade PRIVATE - ${CPC_SOURCE_DIR}/lib - src/upgrade/include) - -target_include_directories(cpc-zbbackup PRIVATE - ${CPC_SOURCE_DIR}/lib - src/zbbackup/include) - -install(TARGETS cpc-upgrade RUNTIME DESTINATION "bin" COMPONENT cpc-upgrade) - -set(DEFAULT_CPC_HCI_BRIDGE_INSTALL_PATH /var/lib/cpc-upgrade) -if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_HCI_BRIDGE_INSTALL_PATH} COMPONENT cpc-upgrade) -else() - install(DIRECTORY DESTINATION ${DEFAULT_CPC_HCI_BRIDGE_INSTALL_PATH} COMPONENT cpc-upgrade) -endif() - -if((${CONFIG_BLUETOOTH}) AND (${CONFIG_BORDER_ROUTER})) - set(MGMT_POSTFIX -all) -elseif(${CONFIG_BLUETOOTH}) - set(MGMT_POSTFIX -bt) -elseif(${CONFIG_BORDER_ROUTER}) - set(MGMT_POSTFIX -br) -endif() - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/config.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/config) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/postinst.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/postinst) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/prerm.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/prerm) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/postrm.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/postrm) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/templates.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/templates) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/conffiles.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/conffiles) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/cpcd.service.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpcd.service) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debconf/services/cpc-mgmt.service.in - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-mgmt.service) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/cpc-mgmt${MGMT_POSTFIX}.in - ${CMAKE_CURRENT_BINARY_DIR}/scripts/cpc-mgmt) - - -set(DEFAULT_CPCD_SERVICE_PATH lib/systemd/system/) -set(DEFAULT_CPCD_SCRIPTS_PATH src/scripts/) -if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPCD_SCRIPTS_PATH} COMPONENT cpc-mgmt) - set(CPCD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_MGMT_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPCD_SCRIPTS_PATH}) -else() - install(DIRECTORY DESTINATION ${DEFAULT_CPCD_SCRIPTS_PATH} COMPONENT cpc-mgmt) - set(CPCD_SERVICE_PATH ${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_MGMT_PATH ${DEFAULT_CPCD_SCRIPTS_PATH}) -endif() - -ext_install( - "FILE" - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpc-mgmt.service - ${CPCD_SERVICE_PATH} - cpcd -) - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/scripts/cpc-mgmt - ${CPC_MGMT_PATH} - cpc-mgmt -) - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/debconf/services/cpcd.service - ${CPCD_SERVICE_PATH} - cpcd -) - -if(CPCD_LOCATION) - # Install configuration file - ext_install( - "FILE" ${CPCD_LOCATION}/etc/cpcd.conf - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} - cpcd) -else() - # Install binaries they come from custom target build_cpcd - - ext_install( - "TARGET_HEADER" cpc - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} - cpcd) - - ext_install( - "TARGET_LIBRARY" cpc - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} - cpcd) - - ext_install( - "TARGET_RUNTIME" cpc - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR} - cpcd) - - ext_install( - "FILE" ${cpcd_SOURCE_DIR}/cpcd.conf - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} - cpcd) - - - ext_install( - "TARGET_HEADER" cpc - ${CPC_MGMT_PATH} - cpc-mgmt - ) -endif() - diff --git a/module/cpc/cpcd-system/debconf/prerm.in b/module/cpc/cpcd-system/debconf/prerm.in deleted file mode 100755 index c514765..0000000 --- a/module/cpc/cpcd-system/debconf/prerm.in +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -if type "systemctl" > /dev/null; then - systemctl stop cpcd.service - systemctl disable cpcd.service -fi diff --git a/module/cpc/cpcd-system/debconf/services/cpcd.service.in b/module/cpc/cpcd-system/debconf/services/cpcd.service.in deleted file mode 100644 index e9683ea..0000000 --- a/module/cpc/cpcd-system/debconf/services/cpcd.service.in +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=CPC Daemon (ver @PROJECT_VER@) - -[Service] -ExecStart=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/cpcd -c ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/cpcd.conf -ExecReload=/bin/kill -HUP $MAINPID -Restart=on-failure -KillMode=process -LimitMEMLOCK=infinity - -[Install] -WantedBy=multi-user.target diff --git a/module/cpc/cpcd-system/debconf/templates.in b/module/cpc/cpcd-system/debconf/templates.in deleted file mode 100755 index 15c9db5..0000000 --- a/module/cpc/cpcd-system/debconf/templates.in +++ /dev/null @@ -1,5 +0,0 @@ -Template: cpcd/serial_port -Type: string -Default: /dev/ttyUSB0 -Description: The serial port where CPC RCP is connected. - (default: /dev/ttyUSB0) diff --git a/module/cpc/cpcd-system/scripts/cpc-mgmt-all.in b/module/cpc/cpcd-system/scripts/cpc-mgmt-all.in deleted file mode 100755 index bd8f165..0000000 --- a/module/cpc/cpcd-system/scripts/cpc-mgmt-all.in +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -die() -{ - echo >&2 " *** ERROR: $*" - exit 1 -} - -have() -{ - command -v "$1" >/dev/null 2>/dev/null -} - -main() -{ - echo >&2 "****************************\nCPCD version: @PROJECT_VER@\n****************************" - sudo sysctl --system - if have systemctl; then - systemctl is-active cpc-bluetooth && sudo systemctl stop cpc-bluetooth - systemctl is-active cpc-otbr && sudo systemctl stop cpc-otbr - systemctl is-active cpcd.service && sudo systemctl stop cpcd.service - systemctl is-active cpcd.service || sudo systemctl start cpcd.service || die 'Failed to start cpcd!' - systemctl is-active cpc-otbr || sudo systemctl start cpc-otbr || die 'Failed to start cpc-otbr!' - systemctl is-active cpc-bluetooth || sudo systemctl start cpc-bluetooth || die 'Failed to start cpc-bluetooth' - elif have service; then - sudo service cpc-bluetooth status && ( sudo service cpc-bluetooth stop || die 'Failed to stop cpc-bluetooth' ) - sudo service cpc-otbr status && ( sudo service cpc-otbr stop || die 'Failed to stop otbr!' ) - sudo service cpcd status && ( sudo service cpcd stop || die 'Failed to stop cpcd!' ) - sudo service cpcd status || sudo service cpcd start || die 'Failed to start cpcd!' - sudo service cpc-otbr status || sudo service cpc-otbr start || die 'Failed to start cpc-otbr!' - sudo service cpc-bluetooth status || sudo service cpc-bluetooth start || die 'Failed to start cpc-bluetooth' - else - die 'Unable to find service manager. Try script/console to start in console mode!' - fi -} - -main diff --git a/module/cpc/cpcd-system/scripts/cpc-mgmt-br.in b/module/cpc/cpcd-system/scripts/cpc-mgmt-br.in deleted file mode 100755 index c12ccc5..0000000 --- a/module/cpc/cpcd-system/scripts/cpc-mgmt-br.in +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -die() -{ - echo >&2 " *** ERROR: $*" - exit 1 -} - -have() -{ - command -v "$1" >/dev/null 2>/dev/null -} - -main() -{ - echo >&2 "****************************\nCPCD version: @PROJECT_VER@\n****************************" - sudo sysctl --system - if have systemctl; then - systemctl is-active cpc-otbr && sudo systemctl stop cpc-otbr - systemctl is-active cpcd.service && sudo systemctl stop cpcd.service - systemctl is-active cpcd.service || sudo systemctl start cpcd.service || die 'Failed to start cpcd!' - systemctl is-active cpc-otbr || sudo systemctl start cpc-otbr || die 'Failed to start cpc-otbr!' - elif have service; then - sudo service cpc-otbr status && ( sudo service cpc-otbr stop || die 'Failed to stop otbr!' ) - sudo service cpcd status && ( sudo service cpcd stop || die 'Failed to stop cpcd!' ) - sudo service cpcd status || sudo service cpcd start || die 'Failed to start cpcd!' - sudo service cpc-otbr status || sudo service cpc-otbr start || die 'Failed to start cpc-otbr!' - else - die 'Unable to find service manager. Try script/console to start in console mode!' - fi -} - -main diff --git a/module/cpc/cpcd-system/scripts/cpc-mgmt-bt.in b/module/cpc/cpcd-system/scripts/cpc-mgmt-bt.in deleted file mode 100755 index 0b33d79..0000000 --- a/module/cpc/cpcd-system/scripts/cpc-mgmt-bt.in +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -die() -{ - echo >&2 " *** ERROR: $*" - exit 1 -} - -have() -{ - command -v "$1" >/dev/null 2>/dev/null -} - -main() -{ - echo >&2 "****************************\nCPCD version: @PROJECT_VER@\n****************************" - sudo sysctl --system - if have systemctl; then - systemctl is-active cpc-bluetooth && sudo systemctl stop cpc-bluetooth - systemctl is-active cpcd.service && sudo systemctl stop cpcd.service - systemctl is-active cpcd.service || sudo systemctl start cpcd.service || die 'Failed to start cpcd!' - systemctl is-active cpc-bluetooth || sudo systemctl start cpc-bluetooth || die 'Failed to start cpc-bluetooth' - elif have service; then - sudo service cpc-bluetooth status && ( sudo service cpc-bluetooth stop || die 'Failed to stop cpc-bluetooth' ) - sudo service cpcd status && ( sudo service cpcd stop || die 'Failed to stop cpcd!' ) - sudo service cpcd status || sudo service cpcd start || die 'Failed to start cpcd!' - sudo service cpc-bluetooth status || sudo service cpc-bluetooth start || die 'Failed to start cpc-bluetooth' - else - die 'Unable to find service manager. Try script/console to start in console mode!' - fi -} - -main diff --git a/module/cpc/cpcd-system/scripts/cpc-mgmt.in b/module/cpc/cpcd-system/scripts/cpc-mgmt.in deleted file mode 100755 index bd8f165..0000000 --- a/module/cpc/cpcd-system/scripts/cpc-mgmt.in +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -die() -{ - echo >&2 " *** ERROR: $*" - exit 1 -} - -have() -{ - command -v "$1" >/dev/null 2>/dev/null -} - -main() -{ - echo >&2 "****************************\nCPCD version: @PROJECT_VER@\n****************************" - sudo sysctl --system - if have systemctl; then - systemctl is-active cpc-bluetooth && sudo systemctl stop cpc-bluetooth - systemctl is-active cpc-otbr && sudo systemctl stop cpc-otbr - systemctl is-active cpcd.service && sudo systemctl stop cpcd.service - systemctl is-active cpcd.service || sudo systemctl start cpcd.service || die 'Failed to start cpcd!' - systemctl is-active cpc-otbr || sudo systemctl start cpc-otbr || die 'Failed to start cpc-otbr!' - systemctl is-active cpc-bluetooth || sudo systemctl start cpc-bluetooth || die 'Failed to start cpc-bluetooth' - elif have service; then - sudo service cpc-bluetooth status && ( sudo service cpc-bluetooth stop || die 'Failed to stop cpc-bluetooth' ) - sudo service cpc-otbr status && ( sudo service cpc-otbr stop || die 'Failed to stop otbr!' ) - sudo service cpcd status && ( sudo service cpcd stop || die 'Failed to stop cpcd!' ) - sudo service cpcd status || sudo service cpcd start || die 'Failed to start cpcd!' - sudo service cpc-otbr status || sudo service cpc-otbr start || die 'Failed to start cpc-otbr!' - sudo service cpc-bluetooth status || sudo service cpc-bluetooth start || die 'Failed to start cpc-bluetooth' - else - die 'Unable to find service manager. Try script/console to start in console mode!' - fi -} - -main diff --git a/module/cpc/cpcd/CMakeLists.txt b/module/cpc/cpcd/CMakeLists.txt deleted file mode 100644 index 8b801b2..0000000 --- a/module/cpc/cpcd/CMakeLists.txt +++ /dev/null @@ -1,130 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(cpcd - VERSION "${CPCD_VER}" - LANGUAGES C) -set(CPC_LIBRARY_API_VERSION "${CPCD_LIB}") -set(CPC_PROTOCOL_VERSION "${CPCD_POTOCOL}") - -# Options -set(TARGET_GROUP release CACHE STRING "Group to build") -option(WARN_AS_ERROR "Treat warnings as errors") - -#set(CPC_CRC_0 1) -if (DEFINED CPC_CRC_0) - message(STATUS "Using CPC_CRC_0") - add_definitions(-DCPC_CRC_0=${CPC_CRC_0}) -endif() - -# Includes -include(cmake/GetGitRevisionDescription.cmake) -include(cmake/TargetStds.cmake) -include(cmake/Warnings.cmake) -include(GNUInstallDirs) - -# Dependencies -find_package(Threads REQUIRED) - -find_path(Linux_INCLUDE_DIR "linux/version.h") - - -set(GIT_SHA1 "Unknown") -set(GIT_REFSPEC "Unknown") -get_git_head_revision(GIT_REFSPEC GIT_SHA1 ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) -add_definitions("-DGIT_SHA1=\"${GIT_SHA1}\"") -add_definitions("-DGIT_REFSPEC=\"${GIT_REFSPEC}\"") - -if(WARN_AS_ERROR) - target_compile_options(_Warnings INTERFACE -Werror) -endif() - -add_library(cpc SHARED) -target_stds(cpc C 99 POSIX 2008) -target_link_libraries(cpc PRIVATE Interface::Warnings) -target_sources(cpc PRIVATE utility/sleep.c) -target_sources(cpc PRIVATE lib/libcpc.c) - -target_include_directories(cpc PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(cpc PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") -set_target_properties(cpc PROPERTIES VERSION "${PROJECT_VERSION}") -set_target_properties(cpc PROPERTIES SOVERSION "${CPC_LIBRARY_API_VERSION}") -set_target_properties(cpc PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/lib/libcpc.h") - -# CPCd Config file path -if(NOT DEFINED CPCD_CONFIG_FILE_PATH) - set(CPCD_CONFIG_FILE_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}/cpcd.conf) -endif() -add_definitions(-DCPCD_CONFIG_FILE_PATH="${CPCD_CONFIG_FILE_PATH}") -message(STATUS "CPCD_CONFIG_FILE_PATH=${CPCD_CONFIG_FILE_PATH}") - -# CPCd minimum reboot time -if(NOT DEFINED CPCD_REBOOT_TIME_MS) - set(CPCD_REBOOT_TIME_MS 2000) -endif() -add_definitions(-DCPCD_REBOOT_TIME_MS=${CPCD_REBOOT_TIME_MS}) -message(STATUS "CPCD_REBOOT_TIME_MS=${CPCD_REBOOT_TIME_MS}") - -# CPC Socket directory -if(NOT DEFINED CPC_SOCKET_DIR) - set(CPC_SOCKET_DIR /dev/shm) -endif() -add_definitions(-DCPC_SOCKET_DIR="${CPC_SOCKET_DIR}") -message(STATUS "CPC_SOCKET_DIR=${CPC_SOCKET_DIR}") - - -# Build CPC Daemon if building for release or debug -if((TARGET_GROUP STREQUAL release) OR - (TARGET_GROUP STREQUAL debug)) - message(STATUS "Building CPC Daemon") - - # CMake<3.11 requires two arguments - add_executable(cpcd main.c) - target_stds(cpcd C 99 POSIX 2008) - target_link_libraries(cpcd PRIVATE Interface::Warnings) - target_include_directories(cpcd PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") - target_include_directories(cpcd PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") - target_include_directories(cpcd PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib") - target_sources(cpcd PRIVATE - primary/primary_cpcd.c - primary/epoll_port/epoll_port.c - primary/cpcd/cpcd.c - primary/cpcd/crc.c - primary/cpcd/hdlc.c - primary/primary/primary.c - primary/system/system.c - primary/system/callbacks.c - hal/hal_uart.c - hal/hal_kill.c - utility/errcode.c - utility/logs.c - utility/config.c - utility/utils.c - utility/slist.c - utility/sleep.c) - - target_include_directories(cpcd PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/autogen") - target_include_directories(cpcd PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") - target_include_directories(cpcd PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib") - target_link_libraries(cpcd PRIVATE Threads::Threads) - - # Hash all files except those in the output folder - get_target_property(CPCD_SOURCES cpcd SOURCES) - foreach(file ${CPCD_SOURCES}) - file(SHA256 "${CMAKE_CURRENT_SOURCE_DIR}/${file}" FILE_HASH) - string(APPEND SOURCES_HASH "${FILE_HASH}") - string(SHA256 SOURCES_HASH "${SOURCES_HASH}") - endforeach() - message(STATUS "Sources hash: ${SOURCES_HASH}") - - install(TARGETS cpc cpcd - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - - install(FILES cpcd.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config) -endif() - -# Configure the version header file -configure_file(utility/version.h.in autogen/version.h) - diff --git a/module/cpc/cpcd/cmake-variants.yaml b/module/cpc/cpcd/cmake-variants.yaml deleted file mode 100644 index 9767d31..0000000 --- a/module/cpc/cpcd/cmake-variants.yaml +++ /dev/null @@ -1,35 +0,0 @@ -TARGET_GROUP: - default: release - choices: - release: - short: Release - settings: - TARGET_GROUP: release - debug: - short: Debug - settings: - TARGET_GROUP: debug - blackbox_test: - short: Blackbox Test - settings: - TARGET_GROUP: blackbox_test - blackbox_test_spurious_reset: - short: Blackbox Test Spurious Reset - settings: - TARGET_GROUP: blackbox_test_spurious_reset - blackbox_test_large_buf: - short: Blackbox Test Large Buf - settings: - TARGET_GROUP: blackbox_test_large_buf - unit_test: - short: Unit Test - settings: - TARGET_GROUP: unit_test - unit_test_with_valgrind: - short: Unit Test With Valgrind - settings: - TARGET_GROUP: unit_test_with_valgrind - target_test: - short: Target Test - settings: - TARGET_GROUP: target_test diff --git a/module/cpc/cpcd/cpcd.conf b/module/cpc/cpcd/cpcd.conf deleted file mode 100644 index ff353fa..0000000 --- a/module/cpc/cpcd/cpcd.conf +++ /dev/null @@ -1,48 +0,0 @@ -# Instance Name -instance_name: cpcd_0 - -# Bus type selection -# Mandatory -# Allowed values : UART or SPI -bus_type: UART - -# UART device file -# Mandatory if uart chosen, ignored if spi chosen -uart_device_file: /dev/ttyUSB0 - -# UART baud rate. -# Optional if uart chosen, ignored if spi chosen. Defaults to 115200 -# Allowed values : standard UART baud rates listed in 'termios.h' -uart_device_baud: 500000 -# uart_device_baud: 2000000 - -# UART flow control. -# Optional if uart chosen, ignored if spi chosen. Defaults to 'true' -# Allowed values are 'true' or 'false' -uart_hardflow: false - - -# Prints tracing information to stdout -# Optional, defaults to 'false' -# Allowed values are 'true' or 'false' -stdout_trace: true - -# Prints tracing information to a file located under traces_folder -# Optional, defaults to 'false' -# Allowed values are 'true' or 'false' -trace_to_file: false - -# Traces folder -# Optional, defaults to '/dev/shm/cpcd-traces' -# Folder mounted on a tmpfs is preferred -traces_folder: /dev/shm/cpcd-traces - -# Enable frame trace -# Optional, defaults to 'false' -# Allowed values are 'true' or 'false' -enable_frame_trace: true - -# Number of open file descriptors. -# Optional, defaults to 2000 -# If the error 'Too many open files' occurs, this is the value to increase. -rlimit_nofile: 2000 \ No newline at end of file diff --git a/module/cpc/cpcd/hal/hal_kill.c b/module/cpc/cpcd/hal/hal_kill.c deleted file mode 100644 index 1b98809..0000000 --- a/module/cpc/cpcd/hal/hal_kill.c +++ /dev/null @@ -1,53 +0,0 @@ - -#define _GNU_SOURCE /* See feature_test_macros(7) */ -#include /* Definition of O_* constants */ -#include -#include - -#include - -#include "hal_kill.h" -#include "utility/logs.h" - -static int kill_eventfd = -1; - -int hal_kill_init(void) -{ - kill_eventfd = eventfd(0, EFD_CLOEXEC); - - ERROR_ON(kill_eventfd == -1); - - return kill_eventfd; -} - -void hal_kill_signal(void) -{ - ssize_t ret; - const uint64_t event_value = 1; //doesn't matter what it is - - if (kill_eventfd == -1) - { - return; - } - - ret = write(kill_eventfd, &event_value, sizeof(event_value)); - ERROR_ON(ret != sizeof(event_value)); -} - -int hal_kill_join(void) -{ - void *join_value; - int ret; - - extern pthread_t hal_thread; - ret = pthread_join(hal_thread, &join_value); - - return ret; -} - -int hal_kill_signal_and_join(void) -{ - hal_kill_signal(); - - return hal_kill_join(); -} diff --git a/module/cpc/cpcd/hal/hal_uart.c b/module/cpc/cpcd/hal/hal_uart.c deleted file mode 100644 index 00a92f9..0000000 --- a/module/cpc/cpcd/hal/hal_uart.c +++ /dev/null @@ -1,524 +0,0 @@ -/** - * @file hal_uart.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-10-30 - * - * - */ -#define _GNU_SOURCE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utility/config.h" -#include "utility/logs.h" -#include "utility/sleep.h" -#include "utility/utils.h" -#include "hal/hal_uart.h" -#include "primary/cpcd/hdlc.h" -#include "primary/cpcd/crc.h" -#include "hal/hal_kill.h" - -//============================================================================= -// Constant Definition -//============================================================================= -//============================================================================= -// Macro Definition -//============================================================================= -#define UART_BUFFER_SIZE 4096 + CPC_HDLC_HEADER_RAW_SIZE -#define MAX_EPOLL_EVENTS 1 -//============================================================================= -// Structure Definition -//============================================================================= -typedef struct notify_private_data -{ - int timer_file_descriptor; -}notify_private_data_t; - - -//============================================================================= -// Global Data Definition -//============================================================================= -static int fd_uart; -static int fd_cpcd; -static int fd_cpcd_notify; -static int fd_stop_drv; -static unsigned int device_baudrate = 0; -static pthread_t rx_drv_thread; -static pthread_t tx_drv_thread; -static pthread_t cleanup_thread; -static const struct -{ - unsigned int val; - int symbolic; -} conversion[] = { - { 9600, B9600 }, - { 115200, B115200 }, - { 500000, B500000 }, - { 2000000, B2000000 }, -}; -//============================================================================= -// Private Function Definition -//============================================================================= -static bool __hdlc_header_validate(uint8_t *header_start) -{ - uint16_t hcs; - - if (header_start[CPC_HDLC_FLAG_POS] != CPC_HDLC_FLAG_VAL) - { - return false; - } - - hcs = hdlc_get_hcs(header_start); - - if (!cpc_check_crc_sw(header_start, CPC_HDLC_HEADER_SIZE, hcs)) - { - TRACE_HAL_INVALID_HEADER_CHECKSUM(); - return false; - } - - return true; -} - -static bool __sync_header(uint8_t *buffer, size_t *buffer_head) -{ - size_t num_header_combination, i; - if (*buffer_head < CPC_HDLC_HEADER_RAW_SIZE) - { - return false; - } - - num_header_combination = *buffer_head - CPC_HDLC_HEADER_RAW_SIZE + 1; - - for (i = 0; i != num_header_combination; i++) - { - if (__hdlc_header_validate(&buffer[i])) - { - if (i != 0) - { - memmove(&buffer[0], &buffer[i], *buffer_head - i); - *buffer_head -= i; - } - return true; - } - } - memmove(&buffer[0], &buffer[num_header_combination], CPC_HDLC_HEADER_RAW_SIZE - 1); - *buffer_head = CPC_HDLC_HEADER_RAW_SIZE - 1; - - return false; -} - -static bool __push_valid_hdlc_frame(uint8_t *buffer, size_t *buffer_head) -{ - uint16_t payload_len; - size_t frame_size, remaining_bytes; - - if (*buffer_head < CPC_HDLC_HEADER_RAW_SIZE) - { - return false; - } - - payload_len = hdlc_get_length(buffer); - - frame_size = payload_len + CPC_HDLC_HEADER_RAW_SIZE; - - if (frame_size > *buffer_head) - { - return false; - } - - write(fd_cpcd, buffer, frame_size); - - remaining_bytes = *buffer_head - frame_size; - memmove(buffer, &buffer[frame_size], remaining_bytes); - *buffer_head = remaining_bytes; - - return true; -} - -/* Append UART new data to the frame delimiter processing buffer */ -static size_t __hal_uart_get_fd_data(uint8_t *buffer, size_t buffer_head, size_t buffer_size) -{ - uint8_t temp_buffer[UART_BUFFER_SIZE]; - - ASSERT_ON(buffer_head >= buffer_size); - - /* Make sure we don't read more data than the supplied buffer can handle */ - const size_t available_space = buffer_size - buffer_head - 1; - - /* Read the uart data into the temp buffer */ - ssize_t read_retval = read(fd_uart, temp_buffer, available_space); - ERROR_ON(read_retval < 0); - - /* copy the data in the main buffer */ - memcpy(&buffer[buffer_head], temp_buffer, (size_t)read_retval); - - return (size_t)read_retval; -} - - -static long __drain_ns(uint32_t bytes_left) -{ - uint64_t nanoseconds; - uint64_t bytes_per_sec = device_baudrate / 8; - - nanoseconds = bytes_left * (uint64_t)1000000000 / bytes_per_sec; - - return (long)(nanoseconds); -} - -static void __hal_uart_proc(void) -{ - int ret; - int length; - static uint8_t __hal_uart_buffer[UART_BUFFER_SIZE]; - ssize_t read_retval, write_retval; - struct timespec txd_timestamp; - - read_retval = read(fd_cpcd, __hal_uart_buffer, sizeof(__hal_uart_buffer)); - - ERROR_SYSCALL_ON(read_retval < 0); - - write_retval = write(fd_uart, __hal_uart_buffer, (size_t)read_retval); - - ERROR_SYSCALL_ON(write_retval < 0); - - ERROR_ON((size_t)write_retval != (size_t)read_retval); - - ret = ioctl(fd_uart, TIOCOUTQ, &length); - ERROR_SYSCALL_ON(ret < 0); - - clock_gettime(CLOCK_MONOTONIC, &txd_timestamp); - - if (txd_timestamp.tv_nsec + __drain_ns((uint32_t)length) > 1000000000) - { - txd_timestamp.tv_sec += (txd_timestamp.tv_nsec + __drain_ns((uint32_t)length)) / 1000000000; - } - txd_timestamp.tv_nsec += __drain_ns((uint32_t)length); - txd_timestamp.tv_nsec %= 1000000000; - - write_retval = write(fd_cpcd_notify, &txd_timestamp, sizeof(txd_timestamp)); - ERROR_SYSCALL_ON(write_retval != sizeof(txd_timestamp)); -} - -static void __hal_uart_proc_fd(void) -{ - static uint8_t __hal_uart_fd_buffer[UART_BUFFER_SIZE]; - static size_t buffer_head = 0; - static enum { EXPECTING_HEADER, EXPECTING_PAYLOAD } state = EXPECTING_HEADER; - - /* Put the read data at the tip of the buffer head and increment it. */ - buffer_head += __hal_uart_get_fd_data(__hal_uart_fd_buffer, buffer_head, sizeof(__hal_uart_fd_buffer)); - - while (1) - { - switch (state) - { - case EXPECTING_HEADER: - /* Synchronize the start of 'buffer' with the start of a valid header with valid checksum. */ - if (__sync_header(__hal_uart_fd_buffer, &buffer_head)) - { - /* We are synchronized on a valid header, start delimiting the data that follows into a frame. */ - state = EXPECTING_PAYLOAD; - } else - { - /* We went through all the data contained in 'buffer' and haven't synchronized on a header. - * Go back to waiting for more data. */ - return; - } - break; - - case EXPECTING_PAYLOAD: - if (__push_valid_hdlc_frame(__hal_uart_fd_buffer, &buffer_head)) - { - /* A frame has been delimited and pushed to the cpcd, go back to synchronizing on the next header */ - state = EXPECTING_HEADER; - } else - { - /* Not yet enough data, go back to waiting. */ - return; - } - break; - default: - break; - } - } -} - -static void *__hal_uart_cleanup_thd(void *param) -{ - (void)param; - - // wait for threads to exit - pthread_join(tx_drv_thread, NULL); - pthread_join(rx_drv_thread, NULL); - - TRACE_HAL("UART thd cancelled"); - - close(fd_uart); - close(fd_cpcd); - close(fd_cpcd_notify); - close(fd_stop_drv); - - pthread_exit(0); - return NULL; -} - -static void *__hal_uart_transmit_thd(void *param) -{ - struct epoll_event ep_event[2] = { { .events = EPOLLIN, .data.fd = fd_cpcd }, { .events = EPOLLIN, .data.fd = fd_stop_drv } }; - bool exit_thread = false; - size_t event_i; - int fd_epoll, event_count, ret, current_event_fd; - - (void)param; - - TRACE_HAL("Transmitter thread start"); - - fd_epoll = epoll_create1(EPOLL_CLOEXEC); - ERROR_SYSCALL_ON(fd_epoll < 0); - - - ret = epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_cpcd, &ep_event[0]); - ERROR_SYSCALL_ON(ret < 0); - - ret = epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_stop_drv, &ep_event[1]); - ERROR_SYSCALL_ON(ret < 0); - - while (!exit_thread) - { - do - { - event_count = epoll_wait(fd_epoll, ep_event, 2, -1); - if (event_count == -1 && errno == EINTR) - { - continue; - } - ERROR_SYSCALL_ON(event_count == -1); - break; - } while (1); - - - for (event_i = 0; event_i != (size_t)event_count; event_i++) - { - current_event_fd = ep_event[event_i].data.fd; - - if (current_event_fd == fd_cpcd) - { - __hal_uart_proc(); - } else if (current_event_fd == fd_stop_drv) - { - exit_thread = true; - } - } - } - - close(fd_epoll); - - return 0; -} - -static void *__hal_uart_receive_thd(void *param) -{ - struct epoll_event ep_event[2] = { { .events = EPOLLIN, .data.fd = fd_uart }, { .events = EPOLLIN, .data.fd = fd_stop_drv } }; - bool exit_thread = false; - int fd_epoll; - int event_count, ret, current_event_fd; - size_t event_i; - - (void)param; - - TRACE_HAL("Receiver thread start"); - - fd_epoll = epoll_create1(EPOLL_CLOEXEC); - ERROR_SYSCALL_ON(fd_epoll < 0); - - ret = epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_uart, &ep_event[0]); - ERROR_SYSCALL_ON(ret < 0); - - ret = epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_stop_drv, &ep_event[1]); - ERROR_SYSCALL_ON(ret < 0); - - while (!exit_thread) - { - do - { - event_count = epoll_wait(fd_epoll, ep_event, 2, -1); - if (event_count == -1 && errno == EINTR) - { - continue; - } - ERROR_SYSCALL_ON(event_count == -1); - break; - } while (1); - - for (event_i = 0; event_i != (size_t)event_count; event_i++) - { - current_event_fd = ep_event[event_i].data.fd; - - if (current_event_fd == fd_uart) - { - __hal_uart_proc_fd(); - } else if (current_event_fd == fd_stop_drv) - { - exit_thread = true; - } - } - } - - close(fd_epoll); - - return 0; -} - -void hal_uart_assert_rts(bool assert) -{ - int ret; - int flag = TIOCM_RTS; - - ERROR_ON(fd_uart < 0); - - if (assert) - { - ret = ioctl(fd_uart, TIOCMBIS, &flag); - } else - { - ret = ioctl(fd_uart, TIOCMBIC, &flag); - } - - ERROR_SYSCALL_ON(ret < 0); -} - -pthread_t hal_uart_init(int *fd_to_cpcd, int *fd_notify_cpcd, const char *device, unsigned int baudrate, bool hardflow) -{ - int fd_sockets[2]; - int fd_sockets_notify[2]; - ssize_t ret; - - fd_uart = hal_uart_open(device, baudrate, hardflow); - - /* Flush the uart IO fifo */ - - tcflush(fd_uart, TCIOFLUSH); - - ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd_sockets); - ERROR_SYSCALL_ON(ret < 0); - - fd_cpcd = fd_sockets[0]; - *fd_to_cpcd = fd_sockets[1]; - - ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd_sockets_notify); - ERROR_SYSCALL_ON(ret < 0); - - fd_cpcd_notify = fd_sockets_notify[0]; - *fd_notify_cpcd = fd_sockets_notify[1]; - - fd_stop_drv = hal_kill_init(); - - /* create transmitter thread */ - ret = pthread_create(&tx_drv_thread, NULL, __hal_uart_transmit_thd, NULL); - ERROR_ON(ret != 0); - - /* create receiver thread */ - ret = pthread_create(&rx_drv_thread, NULL, __hal_uart_receive_thd, NULL); - ERROR_ON(ret != 0); - - /* create cleanup thread */ - ret = pthread_create(&cleanup_thread, NULL, __hal_uart_cleanup_thd, NULL); - ERROR_ON(ret != 0); - - ret = pthread_setname_np(tx_drv_thread, "tx_drv_thread"); - ERROR_ON(ret != 0); - - ret = pthread_setname_np(rx_drv_thread, "rx_drv_thread"); - ERROR_ON(ret != 0); - - TRACE_HAL("Opening uart file %s", device); - - TRACE_HAL("Init done"); - - return cleanup_thread; -} - -void hal_uart_print_overruns(void) -{ - struct serial_icounter_struct counters; - int retval = ioctl(fd_uart, TIOCGICOUNT, &counters); - ERROR_SYSCALL_ON(retval < 0); - TRACE_HAL("Overruns %d,%d", counters.overrun, counters.buf_overrun); -} - -int hal_uart_open(const char *device, unsigned int baudrate, bool hardflow) -{ - struct termios tty; - int sym_baudrate = -1; - int fd; - - fd = open(device, O_RDWR | O_CLOEXEC); - ERROR_SYSCALL_ON(fd < 0); - - ERROR_SYSCALL_ON(tcgetattr(fd, &tty) < 0); - - size_t i; - for (i = 0; i < ARRAY_SIZE(conversion); i++) - { - if (conversion[i].val == baudrate) - { - sym_baudrate = conversion[i].symbolic; - } - } - - if (sym_baudrate < 0) - { - ERROR("invalid baudrate: %d", baudrate); - } - - cfsetispeed(&tty, (speed_t)sym_baudrate); - cfsetospeed(&tty, (speed_t)sym_baudrate); - cfmakeraw(&tty); - /* Nonblocking read. */ - tty.c_cc[VTIME] = 0; - tty.c_cc[VMIN] = 1; - tty.c_iflag &= (unsigned)~(IXON); - tty.c_iflag &= (unsigned)~(IXOFF); - tty.c_iflag &= (unsigned)~(IXANY); - tty.c_cflag &= (unsigned)~(HUPCL); - tty.c_cflag |= CLOCAL; - if (hardflow) - { - tty.c_cflag |= CRTSCTS; - } else - { - tty.c_cflag &= ~CRTSCTS; - } - - ERROR_SYSCALL_ON(tcsetattr(fd, TCSANOW, &tty) < 0); - - /* Flush the content of the UART in case there was stale data */ - { - /* There was once a bug in the kernel requiring a delay before flushing the uart. - * Keep it there for backward compatibility */ - sleep_ms(10); - - tcflush(fd, TCIOFLUSH); - } - - device_baudrate = baudrate; - - return fd; -} \ No newline at end of file diff --git a/module/cpc/cpcd/lib/libcpc.c b/module/cpc/cpcd/lib/libcpc.c deleted file mode 100644 index 61a98a9..0000000 --- a/module/cpc/cpcd/lib/libcpc.c +++ /dev/null @@ -1,1113 +0,0 @@ -/** - * @file cpc.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-11-02 - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libcpc.h" -#include "version.h" -#include "utility/utils.h" -#include "utility/sleep.h" - -//============================================================================= -// Constant Definition -//============================================================================= -#ifndef DEFAULT_INSTANCE_NAME - #define DEFAULT_INSTANCE_NAME "cpcd_0" -#endif - -#define CTRL_SOCKET_TIMEOUT_SEC 2 - -#define DEFAULT_EP_SOCKET_SIZE LIB_CPC_READ_MINIMUM_SIZE -//============================================================================= -// Macro Definition -//============================================================================= -#define INIT_CPC_RET(type) type __cpc_ret = 0 -#define RETURN_CPC_RET return __cpc_ret -#define SET_CPC_RET(error) \ - do { \ - if (__cpc_ret == 0) { \ - __cpc_ret = error; \ - } \ - } while (0) - -//============================================================================= -// Structure Definition -//============================================================================= -typedef struct -{ - int ctrl_sock_fd; - pthread_mutex_t ctrl_sock_fd_lock; - size_t max_write_size; - char *secondary_app_version; - char *instance_name; - bool initialized; -} __cpc_handle_t; - -typedef struct -{ - uint8_t id; - int server_sock_fd; - int sock_fd; - pthread_mutex_t sock_fd_lock; - __cpc_handle_t *lib_handle; -} __cpc_ep_t; - -typedef struct -{ - int endpoint_id; - int sock_fd; - pthread_mutex_t sock_fd_lock; - __cpc_handle_t *lib_handle; -} __cpc_ep_event_handle_t; - -//============================================================================= -// Global Data Definition -//============================================================================= -static cpc_reset_cb_t saved_reset_cb; -//============================================================================= -// Private Function Definition -//============================================================================= -static cpc_reset_cb_t saved_reset_cb; -int cpc_deinit(cpc_handle_t *handle); - -static void SIGUSR1_handler(int signum) -{ - (void)signum; - - if (saved_reset_cb != NULL) - { - saved_reset_cb(); - } -} - -static int cpc_query_exchange(__cpc_handle_t *lib_handle, int fd, cpc_cpcd_exchange_type_t type, uint8_t ep_id, - void *payload, size_t payload_sz) -{ - (void)lib_handle; - - INIT_CPC_RET(int); - cpc_croe_exange_buffer_t *query = NULL; - ssize_t bytes_written = 0; - ssize_t bytes_read = 0; - const size_t query_len = sizeof(cpc_croe_exange_buffer_t) + payload_sz; - - query = calloc_port(query_len); - if (query == NULL) - { - SET_CPC_RET(-ENOMEM); - RETURN_CPC_RET; - } - - query->type = type; - query->endpoint_number = ep_id; - if (payload_sz) - { - memcpy(query->payload, payload, payload_sz); - } - - bytes_written = send(fd, query, query_len, 0); - if (bytes_written < (ssize_t)query_len) - { - if (bytes_written == -1) - { - SET_CPC_RET(-errno); - } else - { - SET_CPC_RET(-EBADE); - } - goto free_query; - } - - bytes_read = recv(fd, query, query_len, 0); - if (bytes_read != (ssize_t)query_len) - { - if (bytes_read == 0) - { - SET_CPC_RET(-ECONNRESET); - } else if (bytes_read == -1) - { - SET_CPC_RET(-errno); - } else - { - SET_CPC_RET(-EBADE); - } - goto free_query; - } - - if (payload_sz) - { - memcpy(payload, query->payload, payload_sz); - } - - free_query: - free(query); - - RETURN_CPC_RET; -} - -static int cpc_query_receive(__cpc_handle_t *lib_handle, int fd, void *payload, size_t payload_sz) -{ - (void)lib_handle; - INIT_CPC_RET(int); - cpc_croe_exange_buffer_t *query = NULL; - ssize_t bytes_read = 0; - const size_t query_len = sizeof(cpc_croe_exange_buffer_t) + payload_sz; - - query = calloc_port(query_len); - if (query == NULL) - { - SET_CPC_RET(-ENOMEM); - RETURN_CPC_RET; - } - - bytes_read = recv(fd, query, query_len, 0); - if (bytes_read != (ssize_t)query_len) - { - if (bytes_read == 0) - { - SET_CPC_RET(-ECONNRESET); - } else if (bytes_read == -1) - { - SET_CPC_RET(-errno); - } else - { - SET_CPC_RET(-EBADE); - } - - goto free_query; - } - - if (payload_sz && payload) - { - memcpy(payload, query->payload, payload_sz); - } - - free_query: - free(query); - - RETURN_CPC_RET; -} - -static int get_max_write(__cpc_handle_t *lib_handle) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - uint32_t max_write_size = 0; - - tmp_ret = cpc_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, - EXCHANGE_MAX_WRITE_SIZE_QUERY, 0, - (void *)&max_write_size, sizeof(max_write_size)); - - if (tmp_ret == 0) - { - lib_handle->max_write_size = (size_t)max_write_size; - } else - { - SET_CPC_RET(tmp_ret); - } - - RETURN_CPC_RET; -} - -static int check_version(__cpc_handle_t *lib_handle) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - char version[PROJECT_MAX_VERSION_SIZE]; - - strncpy(version, PROJECT_VER, PROJECT_MAX_VERSION_SIZE); - - tmp_ret = cpc_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, - EXCHANGE_VERSION_QUERY, 0, - (void *)version, PROJECT_MAX_VERSION_SIZE); - - if (tmp_ret) - { - SET_CPC_RET(tmp_ret); - RETURN_CPC_RET; - } - - if (strncmp(version, PROJECT_VER, PROJECT_MAX_VERSION_SIZE) != 0) - { - SET_CPC_RET(-ELIBBAD); - RETURN_CPC_RET; - } - - RETURN_CPC_RET; -} - - -static int set_pid(__cpc_handle_t *lib_handle) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - bool can_connect = false; - ssize_t bytes_written = 0; - const pid_t pid = getpid(); - const size_t set_pid_query_len = sizeof(cpc_croe_exange_buffer_t) + sizeof(pid_t); - uint8_t buf[set_pid_query_len]; - cpc_croe_exange_buffer_t *set_pid_query = (cpc_croe_exange_buffer_t *)buf; - - set_pid_query->type = EXCHANGE_SET_PID_QUERY; - set_pid_query->endpoint_number = 0; - - memcpy(set_pid_query->payload, &pid, sizeof(pid_t)); - - bytes_written = send(lib_handle->ctrl_sock_fd, set_pid_query, set_pid_query_len, 0); - if (bytes_written < (ssize_t)set_pid_query_len) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - - tmp_ret = cpc_query_receive(lib_handle, lib_handle->ctrl_sock_fd, &can_connect, sizeof(bool)); - if (tmp_ret == 0) - { - if (!can_connect) - { - SET_CPC_RET(-ELIBMAX); - RETURN_CPC_RET; - } - } else - { - SET_CPC_RET(tmp_ret); - RETURN_CPC_RET; - } - - RETURN_CPC_RET; -} - - -int libcpc_init(cpc_handle_t *handle, const char *instance_name, cpc_reset_cb_t reset_cb) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - __cpc_handle_t *lib_handle = NULL; - struct sockaddr_un server_addr = { 0 }; - - if (handle == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - lib_handle = calloc_port(sizeof(__cpc_handle_t)); - if (lib_handle == NULL) - { - SET_CPC_RET(-ENOMEM); - RETURN_CPC_RET; - } - - saved_reset_cb = reset_cb; - - if (instance_name == NULL) - { - /* If the instance name is NULL, use the default name */ - lib_handle->instance_name = strdup(DEFAULT_INSTANCE_NAME); - if (lib_handle->instance_name == NULL) - { - SET_CPC_RET(-errno); - goto free_lib_handle; - } - } else - { - /* Instead, use the one supplied by the user */ - lib_handle->instance_name = strdup(instance_name); - if (lib_handle->instance_name == NULL) - { - SET_CPC_RET(-errno); - goto free_lib_handle; - } - } - - /* Create the control socket path */ - { - int nchars; - const size_t size = sizeof(server_addr.sun_path) - 1; - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sun_family = AF_UNIX; - - nchars = snprintf(server_addr.sun_path, size, "%s/cpcd/%s/ctrl.cpcd.sock", CPC_SOCKET_DIR, lib_handle->instance_name); - - /* Make sure the path fitted entirely in the struct's static buffer */ - if (nchars < 0 || (size_t)nchars >= size) - { - SET_CPC_RET(-ERANGE); - goto free_instance_name; - } - } - - // Check if control socket exists - if (access(server_addr.sun_path, F_OK) != 0) - { - SET_CPC_RET(-errno); - goto free_instance_name; - } - - lib_handle->ctrl_sock_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - if (lib_handle->ctrl_sock_fd < 0) - { - SET_CPC_RET(-errno); - goto free_instance_name; - } - - if (connect(lib_handle->ctrl_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) - { - SET_CPC_RET(-errno); - goto close_ctrl_sock_fd; - } - - // Set ctrl socket timeout - struct timeval timeout; - timeout.tv_sec = CTRL_SOCKET_TIMEOUT_SEC; - timeout.tv_usec = 0; - - if (setsockopt(lib_handle->ctrl_sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - SET_CPC_RET(-errno); - goto close_ctrl_sock_fd; - } - - tmp_ret = check_version(lib_handle); - if (tmp_ret < 0) - { - SET_CPC_RET(tmp_ret); - goto close_ctrl_sock_fd; - } - - tmp_ret = set_pid(lib_handle); - if (tmp_ret < 0) - { - SET_CPC_RET(tmp_ret); - goto close_ctrl_sock_fd; - } - - // Check if reset callback is define - if (reset_cb != NULL) - { - signal(SIGUSR1, SIGUSR1_handler); - } - - // Check if control socket exists - if (access(server_addr.sun_path, F_OK) != 0) - { - SET_CPC_RET(-errno); - goto close_ctrl_sock_fd; - } - - tmp_ret = get_max_write(lib_handle); - if (tmp_ret < 0) - { - SET_CPC_RET(tmp_ret); - goto close_ctrl_sock_fd; - } - - tmp_ret = pthread_mutex_init(&lib_handle->ctrl_sock_fd_lock, NULL); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - goto free_secondary_app_version; - } - - lib_handle->initialized = true; - handle->ptr = (void *)lib_handle; - RETURN_CPC_RET; - - free_secondary_app_version: - free(lib_handle->secondary_app_version); - - close_ctrl_sock_fd: - if (close(lib_handle->ctrl_sock_fd) < 0) - { - SET_CPC_RET(-errno); - } - - free_instance_name: - free(lib_handle->instance_name); - - free_lib_handle: - free(lib_handle); - - RETURN_CPC_RET; -} - -int cpc_deinit(cpc_handle_t *handle) -{ - INIT_CPC_RET(int); - __cpc_handle_t *lib_handle = NULL; - - if (handle->ptr == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - lib_handle = (__cpc_handle_t *)handle->ptr; - - pthread_mutex_destroy(&lib_handle->ctrl_sock_fd_lock); - - free(lib_handle->instance_name); - free(lib_handle->secondary_app_version); - free(lib_handle); - - handle->ptr = NULL; - - RETURN_CPC_RET; -} - -int libcpc_reset(cpc_handle_t *handle) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - __cpc_handle_t *lib_handle = NULL; - - if (handle->ptr == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - lib_handle = (__cpc_handle_t *)handle->ptr; - - __cpc_handle_t *lib_handle_copy = calloc_port(sizeof(__cpc_handle_t)); - if (lib_handle_copy == NULL) - { - SET_CPC_RET(-ENOMEM); - RETURN_CPC_RET; - } - - memcpy(lib_handle_copy, lib_handle, sizeof(__cpc_handle_t)); - lib_handle_copy->instance_name = strdup(lib_handle->instance_name); - if (lib_handle_copy->instance_name == NULL) - { - free(lib_handle_copy); - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - - // De-init the original handle - if (lib_handle_copy->initialized) - { - tmp_ret = cpc_deinit(handle); - if (tmp_ret != 0) - { - // Restore the handle copy on failure - free(lib_handle_copy->instance_name); - lib_handle_copy->instance_name = lib_handle->instance_name; - handle->ptr = (void *)lib_handle_copy; - - SET_CPC_RET(tmp_ret); - RETURN_CPC_RET; - } - } - - // De-init was successful, invalidate copy - lib_handle_copy->initialized = false; - - // Attemps a connection - tmp_ret = libcpc_init(handle, lib_handle_copy->instance_name, saved_reset_cb); - if (tmp_ret != 0) - { - sleep_ms(CPCD_REBOOT_TIME_MS); // Wait for the minimum time it takes for CPCd to reboot - tmp_ret = libcpc_init(handle, lib_handle_copy->instance_name, saved_reset_cb); - if (tmp_ret != 0) - { - // Restore the handle copy on failure - handle->ptr = (void *)lib_handle_copy; - - SET_CPC_RET(tmp_ret); - RETURN_CPC_RET; - } - } - - // On success we can free the lib_handle_copy - free(lib_handle_copy->instance_name); - free(lib_handle_copy); - - RETURN_CPC_RET; -} - -int libcpc_open_ep(cpc_handle_t handle, cpc_ep_t *endpoint, uint8_t id, uint8_t tx_win_size) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - int tmp_ret2 = 0; - bool can_open = false; - __cpc_handle_t *lib_handle = NULL; - __cpc_ep_t *ep = NULL; - struct sockaddr_un ep_addr = { 0 }; - - if (id == CPC_EP_SYSTEM || endpoint == NULL || handle.ptr == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - lib_handle = (__cpc_handle_t *)handle.ptr; - - if (tx_win_size != 1) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - ep_addr.sun_family = AF_UNIX; - - /* Create the endpoint socket path */ - { - int nchars; - const size_t size = sizeof(ep_addr.sun_path) - 1; - - nchars = snprintf(ep_addr.sun_path, size, "%s/cpcd/%s/ep%d.cpcd.sock", CPC_SOCKET_DIR, lib_handle->instance_name, id); - - /* Make sure the path fitted entirely in the struct sockaddr_un's static buffer */ - if (nchars < 0 || (size_t)nchars >= size) - { - SET_CPC_RET(-ERANGE); - RETURN_CPC_RET; - } - } - - ep = calloc_port(sizeof(__cpc_ep_t)); - if (ep == NULL) - { - SET_CPC_RET(-ERANGE); - RETURN_CPC_RET; - } - - ep->id = id; - ep->lib_handle = lib_handle; - - tmp_ret = pthread_mutex_lock(&lib_handle->ctrl_sock_fd_lock); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - goto free_endpoint; - } - - tmp_ret = cpc_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, - EXCHANGE_OPEN_EP_QUERY, id, - (void *)&can_open, sizeof(can_open)); - - if (tmp_ret) - { - SET_CPC_RET(tmp_ret); - } - - tmp_ret2 = pthread_mutex_unlock(&lib_handle->ctrl_sock_fd_lock); - if (tmp_ret2 != 0) - { - SET_CPC_RET(-tmp_ret2); - goto free_endpoint; - } - - if (tmp_ret) - { - goto free_endpoint; - } - - if (can_open == false) - { - SET_CPC_RET(-EAGAIN); - goto free_endpoint; - } - - ep->sock_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - if (ep->sock_fd < 0) - { - SET_CPC_RET(-errno); - goto free_endpoint; - } - - tmp_ret = connect(ep->sock_fd, (struct sockaddr *)&ep_addr, sizeof(ep_addr)); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - goto close_sock_fd; - } - - tmp_ret = cpc_query_receive(lib_handle, ep->sock_fd, (void *)&ep->server_sock_fd, sizeof(ep->server_sock_fd)); - if (tmp_ret) - { - SET_CPC_RET(tmp_ret); - goto close_sock_fd; - } - - int ep_socket_size = DEFAULT_EP_SOCKET_SIZE; - tmp_ret = setsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDBUF, &ep_socket_size, sizeof(int)); - if (tmp_ret != 0) - { - SET_CPC_RET(-errno); - goto close_sock_fd; - } - - tmp_ret = pthread_mutex_init(&ep->sock_fd_lock, NULL); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - goto close_sock_fd; - } - - endpoint->ptr = (void *)ep; - - SET_CPC_RET(ep->sock_fd); - RETURN_CPC_RET; - - close_sock_fd: - if (close(ep->sock_fd) < 0) - { - SET_CPC_RET(-errno); - } - - free_endpoint: - free(ep); - - RETURN_CPC_RET; -} - -int libcpc_close_ep(cpc_ep_t *endpoint) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - __cpc_handle_t *lib_handle = NULL; - __cpc_ep_t *ep = NULL; - - if (endpoint == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - ep = (__cpc_ep_t *)endpoint->ptr; - if (ep == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - lib_handle = ep->lib_handle; - - tmp_ret = pthread_mutex_lock(&lib_handle->ctrl_sock_fd_lock); - if (tmp_ret != 0) - { - goto destroy_mutex; - } - - tmp_ret = cpc_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, - EXCHANGE_CLOSE_EP_QUERY, ep->id, - (void *)&ep->server_sock_fd, sizeof(ep->server_sock_fd)); - - if (close(ep->sock_fd) < 0) - { - goto unlock_mutex; - } - ep->sock_fd = -1; - - tmp_ret = cpc_query_receive(lib_handle, lib_handle->ctrl_sock_fd, NULL, sizeof(int)); - unlock_mutex: - tmp_ret = pthread_mutex_unlock(&lib_handle->ctrl_sock_fd_lock); - - - destroy_mutex: - tmp_ret = pthread_mutex_destroy(&ep->sock_fd_lock); - - free(ep); - endpoint->ptr = NULL; - - RETURN_CPC_RET; -} - -ssize_t libcpc_read_ep(cpc_ep_t endpoint, void *buffer, size_t count, cpc_ep_read_flags_t flags) -{ - INIT_CPC_RET(ssize_t); - int sock_flags = 0; - ssize_t bytes_read = 0; - __cpc_ep_t *ep = NULL; - - if (buffer == NULL || count < LIB_CPC_READ_MINIMUM_SIZE || endpoint.ptr == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - ep = (__cpc_ep_t *)endpoint.ptr; - - - if (flags & CPC_EP_READ_FLAG_NON_BLOCKING) - { - sock_flags |= MSG_DONTWAIT; - } - - bytes_read = recv(ep->sock_fd, buffer, count, sock_flags); - if (bytes_read == 0) - { - SET_CPC_RET(-ECONNRESET); - } else if (bytes_read < 0) - { - SET_CPC_RET(-errno); - } else - { - SET_CPC_RET(bytes_read); - } - - RETURN_CPC_RET; -} - - -ssize_t libcpc_write_ep(cpc_ep_t endpoint, const void *data, size_t data_length, cpc_ep_write_flags_t flags) -{ - INIT_CPC_RET(ssize_t); - int sock_flags = 0; - ssize_t bytes_written = 0; - __cpc_ep_t *ep = NULL; - - if (endpoint.ptr == NULL || data == NULL || data_length == 0) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - ep = (__cpc_ep_t *)endpoint.ptr; - - if (data_length > ep->lib_handle->max_write_size) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - if (flags & CPC_EP_WRITE_FLAG_NON_BLOCKING) - { - sock_flags |= MSG_DONTWAIT; - } - - bytes_written = send(ep->sock_fd, data, data_length, sock_flags); - if (bytes_written == -1) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } else - { - SET_CPC_RET(bytes_written); - } - assert((size_t)bytes_written == data_length); - - RETURN_CPC_RET; -} - -int libcpc_get_ep_state(cpc_handle_t handle, uint8_t id, cpc_ep_state_t *state) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - __cpc_handle_t *lib_handle = NULL; - - if (state == NULL || handle.ptr == NULL || id == CPC_EP_SYSTEM) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - lib_handle = (__cpc_handle_t *)handle.ptr; - - tmp_ret = pthread_mutex_lock(&lib_handle->ctrl_sock_fd_lock); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - RETURN_CPC_RET; - } - - - tmp_ret = cpc_query_exchange(lib_handle, lib_handle->ctrl_sock_fd, - EXCHANGE_EP_STATUS_QUERY, id, - (void *)state, sizeof(cpc_ep_state_t)); - - tmp_ret = pthread_mutex_unlock(&lib_handle->ctrl_sock_fd_lock); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - RETURN_CPC_RET; - } - - RETURN_CPC_RET; -} - -int libcpc_set_ep_option(cpc_ep_t endpoint, cpc_option_t option, const void *optval, size_t optlen) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - __cpc_ep_t *ep = NULL; - - if (option == CPC_OPTION_NONE || endpoint.ptr == NULL || optval == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - ep = (__cpc_ep_t *)endpoint.ptr; - - if (option == CPC_OPTION_RX_TIMEOUT) - { - cpc_timeval_t *useropt = (cpc_timeval_t *)optval; - struct timeval sockopt; - - if (optlen != sizeof(cpc_timeval_t)) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - sockopt.tv_sec = useropt->seconds; - sockopt.tv_usec = useropt->microseconds; - - tmp_ret = setsockopt(ep->sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sockopt, (socklen_t)sizeof(sockopt)); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - } else if (option == CPC_OPTION_TX_TIMEOUT) - { - cpc_timeval_t *useropt = (cpc_timeval_t *)optval; - struct timeval sockopt; - - if (optlen != sizeof(cpc_timeval_t)) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - sockopt.tv_sec = useropt->seconds; - sockopt.tv_usec = useropt->microseconds; - - tmp_ret = setsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDTIMEO, &sockopt, (socklen_t)sizeof(sockopt)); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - } else if (option == CPC_OPTION_BLOCKING) - { - if (optlen != sizeof(bool)) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - tmp_ret = pthread_mutex_lock(&ep->sock_fd_lock); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - RETURN_CPC_RET; - } - - int flags = fcntl(ep->sock_fd, F_GETFL); - if (flags < 0) - { - SET_CPC_RET(-errno); - - tmp_ret = pthread_mutex_unlock(&ep->sock_fd_lock); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - } - - RETURN_CPC_RET; - } - - if (*(bool *)optval == true) - { - flags &= ~O_NONBLOCK; - } else - { - flags |= O_NONBLOCK; - } - - tmp_ret = fcntl(ep->sock_fd, F_SETFL, flags); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - } - - tmp_ret = pthread_mutex_unlock(&ep->sock_fd_lock); - if (tmp_ret != 0) - { - SET_CPC_RET(-tmp_ret); - } - - RETURN_CPC_RET; - } else if (option == CPC_OPTION_SOCKET_SIZE) - { - if (optlen != sizeof(int)) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - if (setsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDBUF, optval, (socklen_t)optlen) != 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - } else - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - RETURN_CPC_RET; -} - -int libcpc_get_ep_option(cpc_ep_t endpoint, cpc_option_t option, void *optval, size_t *optlen) -{ - INIT_CPC_RET(int); - int tmp_ret = 0; - __cpc_ep_t *ep = NULL; - - if (option == CPC_OPTION_NONE || endpoint.ptr == NULL || optval == NULL || optlen == NULL) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - ep = (__cpc_ep_t *)endpoint.ptr; - - if (option == CPC_OPTION_RX_TIMEOUT) - { - cpc_timeval_t *useropt = (cpc_timeval_t *)optval; - struct timeval sockopt; - socklen_t socklen = sizeof(sockopt); - - if (*optlen != sizeof(cpc_timeval_t)) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - tmp_ret = getsockopt(ep->sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sockopt, &socklen); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - - // these values are "usually" of type long, so make sure they - // fit in integers (really, they should). - if (sockopt.tv_sec > INT_MAX || sockopt.tv_usec > INT_MAX) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - useropt->seconds = (int)sockopt.tv_sec; - useropt->microseconds = (int)sockopt.tv_usec; - } else if (option == CPC_OPTION_TX_TIMEOUT) - { - cpc_timeval_t *useropt = (cpc_timeval_t *)optval; - struct timeval sockopt; - socklen_t socklen = sizeof(sockopt); - - if (*optlen != sizeof(cpc_timeval_t)) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - tmp_ret = getsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDTIMEO, &sockopt, &socklen); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - - if (sockopt.tv_sec > INT_MAX || sockopt.tv_usec > INT_MAX) - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - useropt->seconds = (int)sockopt.tv_sec; - useropt->microseconds = (int)sockopt.tv_usec; - } else if (option == CPC_OPTION_BLOCKING) - { - if (*optlen < sizeof(bool)) - { - SET_CPC_RET(-ENOMEM); - RETURN_CPC_RET; - } - - *optlen = sizeof(bool); - - int flags = fcntl(ep->sock_fd, F_GETFL); - if (flags < 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - - if (flags & O_NONBLOCK) - { - *(bool *)optval = false; - } else - { - *(bool *)optval = true; - } - } else if (option == CPC_OPTION_SOCKET_SIZE) - { - socklen_t socklen = (socklen_t)*optlen; - - if (*optlen < sizeof(int)) - { - SET_CPC_RET(-ENOMEM); - RETURN_CPC_RET; - } - - tmp_ret = getsockopt(ep->sock_fd, SOL_SOCKET, SO_SNDBUF, optval, &socklen); - if (tmp_ret < 0) - { - SET_CPC_RET(-errno); - RETURN_CPC_RET; - } - - *optlen = (size_t)socklen; - } else if (option == CPC_OPTION_MAX_WRITE_SIZE) - { - *optlen = sizeof(size_t); - memcpy(optval, &ep->lib_handle->max_write_size, sizeof(ep->lib_handle->max_write_size)); - } else - { - SET_CPC_RET(-EINVAL); - RETURN_CPC_RET; - } - - RETURN_CPC_RET; -} - -const char *libcpc_get_lib_ver(void) -{ - return PROJECT_VER; -} - diff --git a/module/cpc/cpcd/lib/libcpc.h b/module/cpc/cpcd/lib/libcpc.h deleted file mode 100644 index ea07ba0..0000000 --- a/module/cpc/cpcd/lib/libcpc.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef _LIBCPC_H -#define _LIBCPC_H -#include -#include -#include -#if !defined(__linux__) -#error Wrong platform -#endif -#define CPC_ENUM_DECLARE(name) typedef uint8_t name; enum name ## _enum -#define CPC_ENUM_GENERIC_DECLARE(name, type) typedef type name; enum name ## _enum -#ifdef __cplusplus -extern "C" -{ -#endif -#define LIB_CPC_READ_MINIMUM_SIZE 4087 -CPC_ENUM_DECLARE(cpc_ep_state_t) -{ - CPC_EP_STATE_OPEN = 0, - CPC_EP_STATE_CLOSED, - CPC_EP_STATE_CLOSING, - CPC_EP_STATE_ERROR_DEST_UNREACH, - CPC_EP_STATE_ERROR_FAULT -}; -CPC_ENUM_DECLARE(cpc_ep_write_flags_t) -{ - CPC_EP_WRITE_FLAG_NONE = 0, ///< No flag - CPC_EP_WRITE_FLAG_NON_BLOCKING = (1 << 0) ///< Set this transaction as non-blocking -}; -CPC_ENUM_DECLARE(cpc_ep_read_flags_t) -{ - CPC_EP_READ_FLAG_NONE = 0, ///< No flag - CPC_EP_READ_FLAG_NON_BLOCKING = (1 << 0) ///< Set this transaction as non-blocking -}; -CPC_ENUM_DECLARE(cpc_ep_event_flags_t) -{ - CPC_EP_EVENT_FLAG_NONE = 0, ///< No flag - CPC_EP_EVENT_FLAG_NON_BLOCKING = (1 << 0) ///< Set this transaction as non-blocking -}; -CPC_ENUM_DECLARE(cpc_option_t) -{ - CPC_OPTION_NONE = 0, - CPC_OPTION_BLOCKING, - CPC_OPTION_RX_TIMEOUT, - CPC_OPTION_TX_TIMEOUT, - CPC_OPTION_SOCKET_SIZE, - CPC_OPTION_MAX_WRITE_SIZE, -}; -CPC_ENUM_DECLARE(cpc_ep_event_option_t) -{ - CPC_EP_EVENT_OPTION_NONE = 0, - CPC_EP_EVENT_OPTION_BLOCKING, - CPC_EP_EVENT_OPTION_READ_TIMEOUT, -}; -CPC_ENUM_DECLARE(cpc_srv_ep_id_t) -{ - CPC_EP_SYSTEM = 0, - CPC_EP_ZIGBEE = 5, - CPC_EP_OPENTHREAD = 9, - CPC_EP_15_4 = 12, - CPC_EP_CLI = 13, - CPC_EP_BT_RCP = 14 -}; -CPC_ENUM_DECLARE(cpc_user_ep_id_t) -{ - CPC_EP_USER_ID_0 = 90, - CPC_EP_USER_ID_1 = 91, - CPC_EP_USER_ID_2 = 92, - CPC_EP_USER_ID_3 = 93, - CPC_EP_USER_ID_4 = 94, - CPC_EP_USER_ID_5 = 95, - CPC_EP_USER_ID_6 = 96, - CPC_EP_USER_ID_7 = 97, - CPC_EP_USER_ID_8 = 98, - CPC_EP_USER_ID_9 = 99, -}; -CPC_ENUM_DECLARE(cpc_evt_type_t) -{ - CPC_EVT_EP_UNKNOWN = 0, - CPC_EVT_EP_OPENED = 1, - CPC_EVT_EP_CLOSED = 2, - CPC_EVT_EP_CLOSING = 3, - CPC_EVT_EP_ERROR_DESTINATION_UNREACHABLE = 4, - CPC_EVT_EP_ERROR_SECURITY_INCIDENT = 5, - CPC_EVT_EP_ERROR_FAULT = 6, -}; -CPC_ENUM_GENERIC_DECLARE(cpc_cpcd_exchange_type_t, uint8_t) -{ - EXCHANGE_EP_STATUS_QUERY, - EXCHANGE_OPEN_EP_QUERY, - EXCHANGE_MAX_WRITE_SIZE_QUERY, - EXCHANGE_VERSION_QUERY, - EXCHANGE_CLOSE_EP_QUERY, - EXCHANGE_SET_PID_QUERY, -}; -typedef struct -{ - cpc_cpcd_exchange_type_t type; - uint8_t endpoint_number; - uint8_t payload[]; -} cpc_croe_exange_buffer_t; -typedef struct -{ - cpc_evt_type_t type; - uint8_t endpoint_number; - uint32_t payload_length; - uint8_t payload[]; -} cpc_cpcd_event_buffer_t; -typedef struct -{ - void *ptr; -} cpc_handle_t, cpc_ep_t; -typedef struct -{ - int seconds; - int microseconds; -} cpc_timeval_t; -typedef uint8_t cpc_evts_flags_t; -typedef void (*cpc_reset_cb_t) (void); -typedef void (*cpc_ep_state_callback_t) (uint8_t endpoint_id, cpc_ep_state_t endpoint_state); -int libcpc_init(cpc_handle_t *handle, const char *instance_name, cpc_reset_cb_t reset_cb); -int libcpc_reset(cpc_handle_t *handle); -int libcpc_open_ep(cpc_handle_t handle, cpc_ep_t *endpoint, uint8_t id, uint8_t tx_win_size); -int libcpc_close_ep(cpc_ep_t *endpoint); -ssize_t libcpc_read_ep(cpc_ep_t endpoint, void *buffer, size_t count, cpc_ep_read_flags_t flags); -ssize_t libcpc_write_ep(cpc_ep_t endpoint, const void *data, size_t data_length, cpc_ep_write_flags_t flags); -int libcpc_get_ep_state(cpc_handle_t handle, uint8_t id, cpc_ep_state_t *state); -int libcpc_set_ep_option(cpc_ep_t endpoint, cpc_option_t option, const void *optval, size_t optlen); -int libcpc_get_ep_option(cpc_ep_t endpoint, cpc_option_t option, void *optval, size_t *optlen); -const char *libcpc_get_lib_ver(void); -#ifdef __cplusplus -} -#endif -#endif // _LIBCPC_H diff --git a/module/cpc/cpcd/main.c b/module/cpc/cpcd/main.c deleted file mode 100644 index c3608c6..0000000 --- a/module/cpc/cpcd/main.c +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @file main.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-10-27 - * - * @copyright Copyright (c) 2023 - * - */ -#define _GNU_SOURCE - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "version.h" -#include "utility/config.h" -#include "utility/logs.h" -#include "utility/sleep.h" -#include "hal/hal_kill.h" -#include "primary/primary_cpcd.h" -#include "primary/epoll_port/epoll_port.h" - -#include "hal/hal_uart.h" - -//============================================================================= -// Constant Definition -//============================================================================= - -//============================================================================= -// Macro Definition -//============================================================================= - -//============================================================================= -// Structure Definition -//============================================================================= - -//============================================================================= -// Global Data Definition -//============================================================================= -static pthread_t daemon_thread = 0; -pthread_t hal_thread = 0; -pthread_t primary_cpcd_thread = 0; - -static int daemon_crash_eventfd; -static int daemon_graceful_exit_eventfd; -static int daemon_graceful_exit_signalfd; -static int daemon_wait_crash_or_graceful_exit_epoll; - -static int fd_socket_hal_cpcd; -static int fd_socket_hal_cpcd_notify; - -static int exit_status = EXIT_SUCCESS; - -char **argv_g = 0; -int argc_g = 0; - -//============================================================================= -// Private Function Definition -//============================================================================= - -void main_wait_crash_or_graceful_exit(void); - -int main(int argc, char *argv[]) -{ - struct epoll_event event = { .events = EPOLLIN }; - sigset_t mask; - int ret; - - argc_g = argc; - argv_g = argv; - - daemon_thread = pthread_self(); - pthread_setname_np(daemon_thread, "cpcd"); - - sigemptyset(&mask); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGTERM); - sigaddset(&mask, SIGQUIT); - - ret = sigprocmask(SIG_BLOCK, &mask, NULL); - ERROR_ON(ret == -1); - - daemon_wait_crash_or_graceful_exit_epoll = epoll_create1(EPOLL_CLOEXEC); - ERROR_SYSCALL_ON(daemon_wait_crash_or_graceful_exit_epoll < 0); - - daemon_crash_eventfd = eventfd(0, EFD_CLOEXEC); - ERROR_ON(daemon_crash_eventfd == -1); - - ret = epoll_ctl(daemon_wait_crash_or_graceful_exit_epoll, - EPOLL_CTL_ADD, - daemon_crash_eventfd, - &event); - ERROR_SYSCALL_ON(ret < 0); - - daemon_graceful_exit_eventfd = eventfd(0, EFD_CLOEXEC); - ERROR_ON(daemon_graceful_exit_eventfd == -1); - - ret = epoll_ctl(daemon_wait_crash_or_graceful_exit_epoll, - EPOLL_CTL_ADD, - daemon_graceful_exit_eventfd, - &event); - ERROR_SYSCALL_ON(ret < 0); - - daemon_graceful_exit_signalfd = signalfd(-1, &mask, SFD_CLOEXEC); - ERROR_ON(daemon_graceful_exit_signalfd == -1); - - ret = epoll_ctl(daemon_wait_crash_or_graceful_exit_epoll, - EPOLL_CTL_ADD, - daemon_graceful_exit_signalfd, - &event); - ERROR_SYSCALL_ON(ret < 0); - - epoll_port_init(); - - logging_init(); - - PRINT_INFO("[Daemon v%s] [Library v%d] [Protocol v%d]", PROJECT_VER, LIBRARY_API_VERSION, PROTOCOL_VERSION); - PRINT_INFO("Git commit: %s / branch: %s", GIT_SHA1, GIT_REFSPEC); - PRINT_INFO("Sources hash: %s", SOURCES_HASH); - config_init(argc, argv); - - PRINT_INFO("Daemon Starting ... "); - - - // Init HAL - hal_thread = hal_uart_init(&fd_socket_hal_cpcd, - &fd_socket_hal_cpcd_notify, - config.uart_file, config.uart_baudrate, - config.uart_hardflow); - - primary_cpcd_thread = primary_cpcd_init(fd_socket_hal_cpcd, fd_socket_hal_cpcd_notify); - - main_wait_crash_or_graceful_exit(); - - return 0; -} - -static void exit_daemon(void) -{ - hal_kill_signal(); - pthread_join(hal_thread, NULL); - - primary_cpcd_kill_signal(); - pthread_join(primary_cpcd_thread, NULL); - - PRINT_INFO("Daemon exit : status %s", (exit_status == 0) ? "EXIT_SUCCESS" : "EXIT_FAILURE"); - logging_kill(); - - exit(exit_status); -} - -void main_wait_crash_or_graceful_exit(void) -{ - int event_count; - struct epoll_event events; - - do - { - event_count = epoll_wait(daemon_wait_crash_or_graceful_exit_epoll, &events, 1, -1); - } while (errno == EINTR && event_count < 0); - - ERROR_SYSCALL_ON(event_count <= 0); - - exit_daemon(); -} - -void signal_crash(void) -{ - uint64_t event_value; - - exit_status = EXIT_FAILURE; - - sleep_s(1); - - if (pthread_self() == daemon_thread) - { - exit_daemon(); - } else - { - write(daemon_crash_eventfd, &event_value, sizeof(event_value)); - } - - pthread_exit(0); -} \ No newline at end of file diff --git a/module/cpc/cpcd/primary/cpcd/cpcd.c b/module/cpc/cpcd/primary/cpcd/cpcd.c deleted file mode 100644 index b87d7cd..0000000 --- a/module/cpc/cpcd/primary/cpcd/cpcd.c +++ /dev/null @@ -1,1735 +0,0 @@ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utility/config.h" -#include "utility/endian.h" -#include "utility/logs.h" -#include "utility/slist.h" -#include "utility/status.h" -#include "utility/sleep.h" -#include "utility/utils.h" -#include "primary/cpcd/cpcd.h" -#include "primary/primary/primary.h" -#include "primary/epoll_port/epoll_port.h" -#include "primary/system/system.h" -#include "primary/cpcd/cpcd.h" -#include "primary/cpcd/hdlc.h" -#include "primary/cpcd/crc.h" - -#define ABS(a) ((a) < 0 ? -(a) : (a)) -#define X_ENUM_TO_STR(x) #x -#define ENUM_TO_STR(x) X_ENUM_TO_STR(x) - -/******************************************************************************* - *************************** GLOBAL VARIABLES ******************************* - ******************************************************************************/ -cpc_cpcd_dbg_cts_t primary_cpcd_debug_counters; -cpc_cpcd_dbg_cts_t secondary_cpcd_debug_counters; - -/******************************************************************************* - *************************** LOCAL DECLARATIONS ***************************** - ******************************************************************************/ - -/******************************************************************************* - *************************** LOCAL VARIABLES ******************************** - ******************************************************************************/ - -static int hal_sock_fd; -static int hal_sock_notify_fd; -static int stats_timer_fd; -static endpoint_t cpcd_endpoints[EP_MAX_COUNT]; -static slist_node_t *transmit_queue = NULL; -static slist_node_t *pending_on_security_ready_queue = NULL; -static slist_node_t *pending_on_tx_complete = NULL; -/******************************************************************************* - ************************** LOCAL FUNCTIONS ******************************** - ******************************************************************************/ - -static void cpcd_process_rx_hal_notification(epoll_port_private_data_t *event_private_data); -static void cpcd_process_rx_hal(epoll_port_private_data_t *event_private_data); -static void cpcd_process_ep_timeout(epoll_port_private_data_t *event_private_data); - -static void cpcd_process_rx_i_frame(frame_t *rx_frame); -static void cpcd_process_rx_s_frame(frame_t *rx_frame); -static void cpcd_process_rx_u_frame(frame_t *rx_frame); - -/* CPC cpcd functions */ -static bool cpcd_process_tx_queue(void); -static void cpcd_clear_transmit_queue(slist_node_t **head, int endpoint_id); -static void process_ack(endpoint_t *endpoint, uint8_t ack); -static void transmit_ack(endpoint_t *endpoint); -static void re_transmit_frame(endpoint_t *endpoint); -static bool is_seq_valid(uint8_t seq, uint8_t ack); -static endpoint_t *find_endpoint(uint8_t endpoint_number); -static void transmit_reject(endpoint_t *endpoint, uint8_t address, uint8_t ack, reject_reason_t reason); - -/* Functions to operate on linux fd timers */ -static void stop_re_transmit_timer(endpoint_t *endpoint); -static void start_re_transmit_timer(endpoint_t *endpoint, struct timespec offset); - -/* Functions to communicate with the hal and server */ -static void cpcd_push_frame_to_hal(const void *frame, size_t frame_len); -static bool cpcd_pull_frame_from_hal(frame_t **frame_buf, size_t *frame_buf_len); - -static status_t cpcd_push_data_to_server(uint8_t ep_id, const void *data, size_t data_len); - -static void cpcd_fetch_secondary_debug_counters(epoll_port_private_data_t *event_private_data); - -/******************************************************************************* - ************************** IMPLEMENTATION ******************************** - ******************************************************************************/ -cpc_ep_state_t cpcd_state_mapper(uint8_t state) -{ - #define STATE_FREED 6 // State freed, internal to Secondary - - switch (state) - { - case CPC_EP_STATE_OPEN: - case CPC_EP_STATE_CLOSED: - case CPC_EP_STATE_CLOSING: - case CPC_EP_STATE_ERROR_DEST_UNREACH: - case CPC_EP_STATE_ERROR_FAULT: - return state; - case STATE_FREED: - return CPC_EP_STATE_CLOSED; - default: - ASSERT("A new state (%d) has been added to the Secondary that has no equivalent on the daemon.", state); - } -} - -const char *cpcd_stringify_state(cpc_ep_state_t state) -{ - switch (state) - { - case CPC_EP_STATE_OPEN: - return ENUM_TO_STR(CPC_EP_STATE_OPEN); - case CPC_EP_STATE_CLOSED: - return ENUM_TO_STR(CPC_EP_STATE_CLOSED); - case CPC_EP_STATE_CLOSING: - return ENUM_TO_STR(CPC_EP_STATE_CLOSING); - case CPC_EP_STATE_ERROR_DEST_UNREACH: - return ENUM_TO_STR(CPC_EP_STATE_ERROR_DEST_UNREACH); - case CPC_EP_STATE_ERROR_FAULT: - return ENUM_TO_STR(CPC_EP_STATE_ERROR_FAULT); - default: - ASSERT("A new state (%d) has been added to the Secondary that has no equivalent on the daemon.", state); - } -} - -static void on_disconnect_notification(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - (void)property_length; - (void)property_value; - - uint8_t ep_id = PROPERTY_ID_TO_EP_ID(property_id); - ASSERT_ON(cpcd_endpoints[ep_id].state == CPC_EP_STATE_OPEN); - - switch (status) - { - case STATUS_IN_PROGRESS: - case STATUS_OK: - TRACE_CPCD("Disconnection notification received for ep#%d", ep_id); - cpcd_set_endpoint_state(ep_id, CPC_EP_STATE_CLOSED); - break; - - case STATUS_TIMEOUT: - case STATUS_ABORT: - cpcd_set_endpoint_in_error(ep_id, CPC_EP_STATE_ERROR_DEST_UNREACH); - WARN("Failed to receive disconnection notification for ep#%d", ep_id); - break; - default: - ERROR("Unknown status during disconnection notification"); - break; - } -} - -static void cpcd_compute_re_transmit_timeout(endpoint_t *endpoint) -{ - // Implemented using Karn’s algorithm - // Based off of RFC 2988 Computing TCP's Retransmission Timer - static bool first_rtt_measurement = true; - struct timespec current_time; - int64_t current_timestamp_ms; - int64_t previous_timestamp_ms; - long round_trip_time_ms = 0; - long rto = 0; - - const uint8_t k = 4; // This value is recommended by the Karn’s algorithm - - ERROR_ON(endpoint == NULL); - - clock_gettime(CLOCK_MONOTONIC, ¤t_time); - - current_timestamp_ms = (current_time.tv_sec * 1000) + (current_time.tv_nsec / 1000000); - previous_timestamp_ms = (endpoint->last_iframe_sent_timestamp.tv_sec * 1000) + (endpoint->last_iframe_sent_timestamp.tv_nsec / 1000000); - - round_trip_time_ms = (long)(current_timestamp_ms - previous_timestamp_ms); - - if (round_trip_time_ms <= 0) - { - round_trip_time_ms = 1; - } - - ERROR_ON(round_trip_time_ms < 0); - - if (first_rtt_measurement) - { - endpoint->smoothed_rtt = round_trip_time_ms; - endpoint->rtt_variation = round_trip_time_ms / 2; - first_rtt_measurement = false; - } else - { - // RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'| where beta is 0.25 - endpoint->rtt_variation = 3 * (endpoint->rtt_variation / 4) + ABS(endpoint->smoothed_rtt - round_trip_time_ms) / 4; - - //SRTT <- (1 - alpha) * SRTT + alpha * R' where alpha is 0.125 - endpoint->smoothed_rtt = 7 * (endpoint->smoothed_rtt / 8) + round_trip_time_ms / 8; - } - - // Impose a lowerbound on the variation, we don't want the RTO to converge too close to the RTT - if (endpoint->rtt_variation < MIN_RE_TRANSMIT_TIMEOUT_MINIMUM_VARIATION_MS) - { - endpoint->rtt_variation = MIN_RE_TRANSMIT_TIMEOUT_MINIMUM_VARIATION_MS; - } - - rto = endpoint->smoothed_rtt + k * endpoint->rtt_variation; - ERROR_ON(rto <= 0); - - if (rto > MAX_RE_TRANSMIT_TIMEOUT_MS) - { - rto = MAX_RE_TRANSMIT_TIMEOUT_MS; - } else if (rto < MIN_RE_TRANSMIT_TIMEOUT_MS) - { - rto = MIN_RE_TRANSMIT_TIMEOUT_MS; - } - - endpoint->re_transmit_timeout_ms = rto; -} - - -void cpcd_init(int hal_fd, int hal_notify_fd) -{ - hal_sock_fd = hal_fd; - hal_sock_notify_fd = hal_notify_fd; - - /* Init all endpoints */ - size_t i = 0; - for (i = 0; i < EP_MAX_COUNT; i++) - { - cpcd_endpoints[i].id = (uint8_t)i; - cpcd_endpoints[i].state = CPC_EP_STATE_CLOSED; - cpcd_endpoints[i].ack = 0; - cpcd_endpoints[i].configured_tx_win_size = 1; - cpcd_endpoints[i].current_tx_window_space = 1; - cpcd_endpoints[i].re_transmit_timer_private_data = NULL; - cpcd_endpoints[i].on_uframe_data_reception = NULL; - cpcd_endpoints[i].on_iframe_data_reception = NULL; - cpcd_endpoints[i].last_iframe_sent_timestamp = (struct timespec){0 }; - cpcd_endpoints[i].smoothed_rtt = 0; - cpcd_endpoints[i].rtt_variation = 0; - cpcd_endpoints[i].re_transmit_timeout_ms = MAX_RE_TRANSMIT_TIMEOUT_MS; - cpcd_endpoints[i].packet_re_transmit_count = 0; - } - /* Setup epoll */ - { - /* Setup the hal data socket */ - { - static epoll_port_private_data_t private_data; - - private_data.callback = cpcd_process_rx_hal; - private_data.file_descriptor = hal_fd; - private_data.endpoint_number = 0; /* Irrelevant here */ - - epoll_port_register(&private_data); - } - - /* Setup the hal notification socket */ - { - static epoll_port_private_data_t private_data_notification; - - private_data_notification.callback = cpcd_process_rx_hal_notification; - private_data_notification.file_descriptor = hal_notify_fd; - private_data_notification.endpoint_number = 0; /* Irrelevant here */ - - epoll_port_register(&private_data_notification); - } - } - - /* Setup timer to fetch secondary debug counter */ - if (config.stats_interval > 0) - { - stats_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - ERROR_SYSCALL_ON(stats_timer_fd < 0); - - struct itimerspec timeout_time = { .it_interval = { .tv_sec = config.stats_interval, .tv_nsec = 0 }, - .it_value = { .tv_sec = config.stats_interval, .tv_nsec = 0 } }; - - int ret = timerfd_settime(stats_timer_fd, - 0, - &timeout_time, - NULL); - - ERROR_SYSCALL_ON(ret < 0); - - /* Setup epoll */ - { - epoll_port_private_data_t *private_data = (epoll_port_private_data_t *)calloc_port(sizeof(epoll_port_private_data_t)); - ERROR_SYSCALL_ON(private_data == NULL); - - private_data->callback = cpcd_fetch_secondary_debug_counters; - private_data->file_descriptor = stats_timer_fd; - - epoll_port_register(private_data); - } - } - - slist_init(&pending_on_tx_complete); -} - -void cpcd_process_transmit_queue(void) -{ - /* Flush the transmit queue */ - while (transmit_queue != NULL || pending_on_security_ready_queue != NULL) - { - if (!cpcd_process_tx_queue()) - { - break; - } - } -} - -cpc_ep_state_t cpcd_get_endpoint_state(uint8_t ep_id) -{ - ERROR_ON(ep_id == 0); - return cpcd_endpoints[ep_id].state; -} - -void cpcd_set_endpoint_state(uint8_t ep_id, cpc_ep_state_t state) -{ - if (cpcd_endpoints[ep_id].state != state) - { - TRACE_CPCD("Changing ep#%d state from %s to %s", ep_id, cpcd_stringify_state(cpcd_endpoints[ep_id].state), cpcd_stringify_state(state)); - cpcd_endpoints[ep_id].state = state; - primary_on_endpoint_state_change(ep_id, state); - } -} - -bool cpcd_get_endpoint_encryption(uint8_t ep_id) -{ - (void)ep_id; - return false; -} - -static void cpcd_update_secondary_debug_counter(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - - if (status == STATUS_TIMEOUT) - { - WARN("Secondary counters query timed out"); - return; - } else if (status == STATUS_ABORT) - { - WARN("Secondary counters query aborted"); - return; - } - - if (status != STATUS_OK && status != STATUS_IN_PROGRESS) - { - ASSERT(); - } - - if (property_id == PROP_LAST_STATUS) - { - ERROR("Secondary does not handle the DEBUG_COUNTERS property, please update secondary or disable print-stats"); - } - - ERROR_ON(property_id != PROP_cpcd_DEBUG_COUNTERS); - ERROR_ON(property_value == NULL || property_length > sizeof(cpc_cpcd_dbg_cts_t)); - - memcpy(&secondary_cpcd_debug_counters, property_value, property_length); -} - -static void cpcd_fetch_secondary_debug_counters(epoll_port_private_data_t *event_private_data) -{ - int fd_timer = event_private_data->file_descriptor; - - /* Ack the timer */ - { - uint64_t expiration; - ssize_t ret; - - ret = read(fd_timer, &expiration, sizeof(expiration)); - ERROR_ON(ret < 0); - } - - sys_cmd_property_get(cpcd_update_secondary_debug_counter, - PROP_cpcd_DEBUG_COUNTERS, 0, 0, false); -} - -static void cpcd_process_rx_hal_notification(epoll_port_private_data_t *event_private_data) -{ - (void)event_private_data; - uint8_t frame_type; - slist_node_t *node; - transmit_queue_item_t *item; - buffer_handle_t *frame; - - struct timespec tx_complete_timestamp; - - ssize_t ret = recv(hal_sock_notify_fd, &tx_complete_timestamp, sizeof(tx_complete_timestamp), MSG_DONTWAIT); - if (ret == 0) - { - TRACE_CPCD("Driver closed the notification socket"); - int ret_close = close(event_private_data->file_descriptor); - ERROR_SYSCALL_ON(ret_close != 0); - return; - } - ERROR_SYSCALL_ON(ret < 0); - - // Get first queued frame for transmission - node = slist_pop(&pending_on_tx_complete); - item = SLIST_ENTRY(node, transmit_queue_item_t, node); - ERROR_ON(item == NULL); - - frame = item->handle; - frame->pending_tx_complete = false; - frame_type = hdlc_get_frame_type(frame->control); - - switch (frame_type) - { - case CPC_HDLC_FRAME_TYPE_IFRAME: - - if (frame->endpoint->state != CPC_EP_STATE_OPEN) - { - // Now that tx is completed, we can clear any frames still in the re-tx queue - cpcd_clear_transmit_queue(&cpcd_endpoints[frame->endpoint->id].re_transmit_queue, -1); - } else - { - // Remember when we sent this i-frame in order to calculate round trip time - // Only do so if this is not a re_transmit - if (frame->endpoint->packet_re_transmit_count == 0u) - { - frame->endpoint->last_iframe_sent_timestamp = tx_complete_timestamp; - } - - if (frame->endpoint->re_transmit_queue != NULL && frame->acked == false) - { - start_re_transmit_timer(frame->endpoint, tx_complete_timestamp); - } - - if (frame->acked) - { - process_ack(frame->endpoint, frame->pending_ack); - } - } - - break; - - case CPC_HDLC_FRAME_TYPE_UFRAME: - case CPC_HDLC_FRAME_TYPE_SFRAME: - if (frame->data_length != 0) - { - free((void *)frame->data); // Not expecting a reply - } - free(frame->hdlc_header); - free(frame); - break; - - default: - ASSERT(); - break; - } - - free(item); -} - -static void cpcd_process_rx_hal(epoll_port_private_data_t *event_private_data) -{ - (void)event_private_data; - frame_t *rx_frame; - size_t frame_size; - - /* The hal unblocked, read the frame. Frames from the hal are complete */ - if (cpcd_pull_frame_from_hal(&rx_frame, &frame_size) == false) - { - return; - } - - TRACE_cpcd_RXD_FRAME(rx_frame, frame_size); - - /* Validate header checksum */ - { - uint16_t hcs = hdlc_get_hcs(rx_frame->header); - - if (!cpc_check_crc_sw(rx_frame->header, CPC_HDLC_HEADER_SIZE, hcs)) - { - TRACE_cpcd_INVALID_HEADER_CHECKSUM(); - free(rx_frame); - return; - } - } - - uint16_t data_length = hdlc_get_length(rx_frame->header); - uint8_t address = hdlc_get_address(rx_frame->header); - uint8_t control = hdlc_get_control(rx_frame->header); - uint8_t type = hdlc_get_frame_type(control); - uint8_t ack = hdlc_get_ack(control); - - /* Make sure the length from the header matches the length reported by the hal*/ - ASSERT_ON(data_length != frame_size - CPC_HDLC_HEADER_RAW_SIZE); - - endpoint_t *endpoint = find_endpoint(address); - - /* If endpoint is closed , reject the frame and return unless the frame itself is a reject, if so ignore it */ - if (endpoint->state != CPC_EP_STATE_OPEN) - { - if (type != CPC_HDLC_FRAME_TYPE_SFRAME) - { - transmit_reject(NULL, address, 0, HDLC_REJECT_UNREACHABLE_ENDPOINT); - } - free(rx_frame); - return; - } - - /* For data and sframe frames, process the ack right away */ - if (type == CPC_HDLC_FRAME_TYPE_IFRAME || type == CPC_HDLC_FRAME_TYPE_SFRAME) - { - process_ack(endpoint, ack); - } - - switch (type) - { - case CPC_HDLC_FRAME_TYPE_IFRAME: - cpcd_process_rx_i_frame(rx_frame); - break; - case CPC_HDLC_FRAME_TYPE_SFRAME: - cpcd_process_rx_s_frame(rx_frame); - break; - case CPC_HDLC_FRAME_TYPE_UFRAME: - cpcd_process_rx_u_frame(rx_frame); - break; - default: - transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_ERROR); - TRACE_EP_RXD_SFRAME_DROPPED(endpoint); - break; - } - - /* cpcd_pull_frame_from_hal() malloced rx_frame */ - free(rx_frame); -} - -bool cpcd_ep_is_closing(uint8_t ep_id) -{ - return cpcd_endpoints[ep_id].state == CPC_EP_STATE_CLOSING; -} - -void cpcd_process_endpoint_change(uint8_t endpoint_number, cpc_ep_state_t ep_state) -{ - if (ep_state == CPC_EP_STATE_OPEN) - { - if (cpcd_endpoints[endpoint_number].state == CPC_EP_STATE_OPEN) - { - return; // Nothing to do - } - - cpcd_open_endpoint(endpoint_number, 0, 1); - } else - { - cpcd_close_endpoint(endpoint_number, true, false); - } -} - -bool cpcd_ep_is_busy(uint8_t ep_id) -{ - if (cpcd_endpoints[ep_id].holding_list != NULL) - { - return true; - } - return false; -} - -static void cpcd_process_rx_i_frame(frame_t *rx_frame) -{ - endpoint_t *endpoint; - - uint8_t address = hdlc_get_address(rx_frame->header); - - endpoint = &cpcd_endpoints[hdlc_get_address(rx_frame->header)]; - - TRACE_EP_RXD_DATA_FRAME(endpoint); - - if (endpoint->id != 0 && (endpoint->state != CPC_EP_STATE_OPEN || primary_listener_list_empty(endpoint->id))) - { - transmit_reject(endpoint, address, 0, HDLC_REJECT_UNREACHABLE_ENDPOINT); - return; - } - - /* Prevent -2 on a zero length */ - ASSERT_ON(hdlc_get_length(rx_frame->header) < CPC_HDLC_FCS_SIZE); - - uint16_t rx_frame_payload_length = (uint16_t)(hdlc_get_length(rx_frame->header) - CPC_HDLC_FCS_SIZE); - - uint16_t fcs = hdlc_get_fcs(rx_frame->payload, rx_frame_payload_length); - - /* Validate payload checksum. In case it is invalid, NAK the packet. */ - if (!cpc_check_crc_sw(rx_frame->payload, rx_frame_payload_length, fcs)) - { - WARN("rx_frame_payload_length %d, fcs %04X\r\n", rx_frame_payload_length, fcs); - transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_CHECKSUM_MISMATCH); - TRACE_cpcd_INVALID_PAYLOAD_CHECKSUM(); - return; - } - - uint8_t control = hdlc_get_control(rx_frame->header); - uint8_t seq = hdlc_get_seq(control); - - // data received, Push in Rx Queue and send Ack - if (seq == endpoint->ack) - { - // Check if the received message is a final reply for the system endpoint - if (hdlc_is_poll_final(control)) - { - ASSERT_ON(endpoint->id != 0); // Only system endpoint can receive final messages - ASSERT_ON(endpoint->poll_final.on_final == NULL); // Received final, but no callback assigned - endpoint->poll_final.on_final(endpoint->id, (void *)CPC_HDLC_FRAME_TYPE_IFRAME, rx_frame->payload, rx_frame_payload_length); - } else - { - if (endpoint->id == CPC_EP_SYSTEM) - { - // unsolicited i-frame - if (endpoint->on_iframe_data_reception != NULL) - { - endpoint->on_iframe_data_reception(endpoint->id, rx_frame->payload, rx_frame_payload_length); - } - } else - { - status_t status = cpcd_push_data_to_server(endpoint->id, - rx_frame->payload, - rx_frame_payload_length); - if (status == STATUS_FAIL) - { - // can't recover from that, close endpoint - cpcd_close_endpoint(endpoint->id, true, false); - return; - } else if (status == STATUS_WOULD_BLOCK) - { - transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_OUT_OF_MEMORY); - return; - } - } - } - - TRACE_EP_RXD_DATA_FRAME_QUEUED(endpoint); - - // Update endpoint acknowledge number - endpoint->ack++; - endpoint->ack %= 4; - - // Send ack - transmit_ack(endpoint); - } else if (is_seq_valid(seq, endpoint->ack)) - { - // The packet was already received. We must re-send a ACK because the other side missed it the first time - TRACE_EP_RXD_DUPLICATE_DATA_FRAME(endpoint); - transmit_ack(endpoint); - } else - { - transmit_reject(endpoint, address, endpoint->ack, HDLC_REJECT_SEQUENCE_MISMATCH); - return; - } -} - -static void cpcd_process_rx_s_frame(frame_t *rx_frame) -{ - endpoint_t *endpoint; - bool fatal_error = false; - - endpoint = find_endpoint(hdlc_get_address(rx_frame->header)); - - TRACE_EP_RXD_SFRAME_FRAME(endpoint); - - cpc_ep_state_t new_state = endpoint->state; - - uint8_t sframe_function = hdlc_get_sframe_function(hdlc_get_control(rx_frame->header)); - - uint16_t data_length = (hdlc_get_length(rx_frame->header) > 2) ? (uint16_t)(hdlc_get_length(rx_frame->header) - 2) : 0; - - switch (sframe_function) - { - case CPC_HDLC_ACK_SFRAME_FUNCTION: - TRACE_EP_RXD_SFRAME_PROCESSED(endpoint); - // ACK; already processed previously by receive_ack(), so nothing to do - break; - - case CPC_HDLC_REJECT_SFRAME_FUNCTION: - - TRACE_EP_RXD_SFRAME_PROCESSED(endpoint); - ASSERT_ON(data_length != CPC_HDLC_REJECT_PAYLOAD_SIZE); - - switch (*((reject_reason_t *)rx_frame->payload)) - { - case HDLC_REJECT_SEQUENCE_MISMATCH: - // This is not a fatal error when the tx window is > 1 - fatal_error = true; - new_state = CPC_EP_STATE_ERROR_FAULT; - TRACE_EP_RXD_REJECT_SEQ_MISMATCH(endpoint); - WARN("Sequence mismatch on endpoint #%d", endpoint->id); - break; - - case HDLC_REJECT_CHECKSUM_MISMATCH: - if (endpoint->re_transmit_queue != NULL) - { - re_transmit_frame(endpoint); - } - TRACE_EP_RXD_REJECT_CHECKSUM_MISMATCH(endpoint); - WARN("Remote received a packet with an invalid checksum"); - break; - - case HDLC_REJECT_OUT_OF_MEMORY: - TRACE_EP_RXD_REJECT_OUT_OF_MEMORY(endpoint); - break; - - case HDLC_REJECT_UNREACHABLE_ENDPOINT: - fatal_error = true; - new_state = CPC_EP_STATE_ERROR_DEST_UNREACH; - TRACE_EP_RXD_REJECT_DESTINATION_UNREACHABLE(endpoint); - WARN("Unreachable endpoint #%d", endpoint->id); - break; - - case HDLC_REJECT_ERROR: - default: - fatal_error = true; - new_state = CPC_EP_STATE_ERROR_FAULT; - TRACE_EP_RXD_REJECT_FAULT(endpoint); - WARN("Endpoint #%d fault", endpoint->id); - break; - } - break; - - default: - ASSERT("Illegal switch"); - break; - } - - if (fatal_error) - { - WARN("Fatal error %d, endoint #%d is in error.", *((reject_reason_t *)rx_frame->payload), endpoint->id); - cpcd_set_endpoint_in_error(endpoint->id, new_state); - } -} - -static void cpcd_process_rx_u_frame(frame_t *rx_frame) -{ - uint16_t payload_length; - uint8_t type; - endpoint_t *endpoint; - - // Retreive info from header - { - uint8_t address = hdlc_get_address(rx_frame->header); - endpoint = find_endpoint(address); - TRACE_EP_RXD_UFRAME_FRAME(endpoint); - - uint8_t control = hdlc_get_control(rx_frame->header); - type = hdlc_get_uframe_type(control); - - payload_length = hdlc_get_length(rx_frame->header); - - if (payload_length < 2) - { - payload_length = 0; - } else - { - payload_length = (uint16_t)(payload_length - CPC_HDLC_FCS_SIZE); - } - } - - // Sanity checks - { - // Validate the payload checksum - if (payload_length > 0) - { - uint16_t fcs = hdlc_get_fcs(rx_frame->payload, payload_length); - - if (!cpc_check_crc_sw(rx_frame->payload, payload_length, fcs)) - { - TRACE_cpcd_INVALID_PAYLOAD_CHECKSUM(); - TRACE_EP_RXD_UFRAME_DROPPED(endpoint, "Bad payload checksum"); - return; - } - } - - // Make sure U-Frames are enabled on this endpoint - if (!(endpoint->flags & OPEN_EP_FLAG_UFRAME_ENABLE)) - { - TRACE_EP_RXD_UFRAME_DROPPED(endpoint, "U-Frame not enabled on endoint"); - return; - } - - // If its an Information U-Frame, make sure they are enabled - if ((type == CPC_HDLC_CONTROL_UFRAME_TYPE_INFORMATION) - && (endpoint->flags & OPEN_EP_FLAG_UFRAME_INFORMATION_DISABLE)) - { - TRACE_EP_RXD_UFRAME_DROPPED(endpoint, "Information U-Frame not enabled on endpoint"); - return; - } - } - - switch (type) - { - case CPC_HDLC_CONTROL_UFRAME_TYPE_INFORMATION: - if (endpoint->on_uframe_data_reception != NULL) - { - endpoint->on_uframe_data_reception(endpoint->id, rx_frame->payload, payload_length); - } - break; - - case CPC_HDLC_CONTROL_UFRAME_TYPE_POLL_FINAL: - if (endpoint->id != CPC_EP_SYSTEM) - { - ERROR("Received an unnumbered final frame but it was not addressed to the system enpoint"); - } else if (endpoint->poll_final.on_final != NULL) - { - endpoint->poll_final.on_final(endpoint->id, (void *)CPC_HDLC_FRAME_TYPE_UFRAME, rx_frame->payload, payload_length); - } else - { - ASSERT(); - } - break; - - case CPC_HDLC_CONTROL_UFRAME_TYPE_ACKNOWLEDGE: - ASSERT_ON(endpoint->id != CPC_EP_SYSTEM); - sys_on_unnumbered_acknowledgement(); - break; - - default: - TRACE_EP_RXD_UFRAME_DROPPED(endpoint, "U-Frame not enabled on endpoint"); - return; - } - - TRACE_EP_RXD_UFRAME_PROCESSED(endpoint); -} - -void cpcd_write(uint8_t endpoint_number, const void *message, size_t message_len, uint8_t flags) -{ - endpoint_t *endpoint; - buffer_handle_t *buffer_handle; - transmit_queue_item_t *transmit_queue_item; - bool iframe = true; - bool poll = (flags & FLAG_INFORMATION_POLL) ? true : false; - uint8_t type = CPC_HDLC_CONTROL_UFRAME_TYPE_UNKNOWN; - void *payload = NULL; - - ERROR_ON(message_len > UINT16_MAX); - - endpoint = find_endpoint(endpoint_number); - - /* Sanity checks */ - { - /* Make sure the endpoint it opened */ - if (endpoint->state != CPC_EP_STATE_OPEN) - { - WARN("Tried to write on closed endpoint #%d", endpoint_number); - return; - } - - /* if u-frame, make sure they are enabled */ - if ((flags & FLAG_UFRAME_INFORMATION) || (flags & FLAG_UFRAME_RESET_COMMAND) || (flags & FLAG_UFRAME_POLL)) - { - ERROR_ON(!(endpoint->flags & OPEN_EP_FLAG_UFRAME_ENABLE)); - - iframe = false; - - if (flags & FLAG_UFRAME_INFORMATION) - { - type = CPC_HDLC_CONTROL_UFRAME_TYPE_INFORMATION; - } else if (flags & FLAG_UFRAME_RESET_COMMAND) - { - type = CPC_HDLC_CONTROL_UFRAME_TYPE_RESET_SEQ; - } else if ((flags & FLAG_UFRAME_POLL)) - { - type = CPC_HDLC_CONTROL_UFRAME_TYPE_POLL_FINAL; - } - } - /* if I-frame, make sure they are not disabled */ - else - { - ERROR_ON(endpoint->flags & OPEN_EP_FLAG_IFRAME_DISABLE); - } - } - - /* Fill the buffer handle */ - { - buffer_handle = (buffer_handle_t *)calloc_port(sizeof(buffer_handle_t)); - ERROR_SYSCALL_ON(buffer_handle == NULL); - - payload = calloc_port(message_len); - ERROR_SYSCALL_ON(payload == NULL); - memcpy(payload, message, message_len); - - buffer_handle->data = payload; - buffer_handle->data_length = (uint16_t)message_len; - buffer_handle->endpoint = endpoint; - buffer_handle->address = endpoint_number; - - if (iframe) - { - // Set the SEQ number and ACK number in the control byte - buffer_handle->control = hdlc_create_ctrl_data(endpoint->seq, endpoint->ack, poll); - // Update endpoint sequence number - endpoint->seq++; - endpoint->seq %= 4; - TRACE_CPCD("Sequence # is now %d on ep %d", endpoint->seq, endpoint->id); - } else - { - ERROR_ON(type == CPC_HDLC_CONTROL_UFRAME_TYPE_UNKNOWN); - buffer_handle->control = hdlc_create_ctrl_uframe(type); - } - - /* Compute the payload's checksum */ - { - uint16_t fcs = cpc_get_crc_sw(message, (uint16_t)message_len); - - buffer_handle->fcs[0] = (uint8_t)fcs; - buffer_handle->fcs[1] = (uint8_t)(fcs >> 8); - } - } - - transmit_queue_item = (transmit_queue_item_t *)calloc_port(sizeof(transmit_queue_item_t)); - ERROR_SYSCALL_ON(transmit_queue_item == NULL); - - transmit_queue_item->handle = buffer_handle; - - // Deal with transmit window - { - // If U-Frame, skip the window and send immediately - if (iframe == false) - { - slist_push_back(&transmit_queue, &transmit_queue_item->node); - cpcd_process_transmit_queue(); - } else - { - if (endpoint->current_tx_window_space > 0) - { - endpoint->current_tx_window_space--; - - //Put frame in Tx Q so that it can be transmitted by CPC Core later - slist_push_back(&transmit_queue, &transmit_queue_item->node); - cpcd_process_transmit_queue(); - } else - { - //Put frame in endpoint holding list to wait for more space in the transmit window - slist_push_back(&endpoint->holding_list, &transmit_queue_item->node); - } - } - } -} - -void cpcd_open_endpoint(uint8_t endpoint_number, uint8_t flags, uint8_t tx_win_size) -{ - endpoint_t *ep; - cpc_ep_state_t previous_state; - - ERROR_ON(tx_win_size < TRANSMIT_WINDOW_MIN_SIZE); - ERROR_ON(tx_win_size > TRANSMIT_WINDOW_MAX_SIZE); - - ep = &cpcd_endpoints[endpoint_number]; - - /* Check if endpoint was already opened */ - if (ep->state != CPC_EP_STATE_CLOSED) - { - ASSERT("Endpoint already opened"); - return; - } - - /* Keep the previous state to log the transition */ - previous_state = ep->state; - memset(ep, 0x00, sizeof(endpoint_t)); - ep->state = previous_state; - cpcd_set_endpoint_state(endpoint_number, CPC_EP_STATE_OPEN); - - ep->id = endpoint_number; - ep->flags = flags; - ep->configured_tx_win_size = tx_win_size; - ep->current_tx_window_space = ep->configured_tx_win_size; - ep->re_transmit_timeout_ms = MIN_RE_TRANSMIT_TIMEOUT_MS; - - int timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - ERROR_SYSCALL_ON(timer_fd < 0); - - /* Setup epoll */ - { - epoll_port_private_data_t *private_data = (epoll_port_private_data_t *)calloc_port(sizeof(epoll_port_private_data_t)); - ERROR_SYSCALL_ON(private_data == NULL); - - ep->re_transmit_timer_private_data = private_data; - - private_data->callback = cpcd_process_ep_timeout; - private_data->file_descriptor = timer_fd; - private_data->endpoint_number = endpoint_number; - - epoll_port_register(private_data); - } - - slist_init(&ep->re_transmit_queue); - slist_init(&ep->holding_list); - - TRACE_cpcd_OPEN_ENDPOINT(ep->id); - - return; -} - -void cpcd_set_endpoint_in_error(uint8_t endpoint_number, cpc_ep_state_t new_state) -{ - if (endpoint_number == 0) - { - WARN("System endpoint in error, new state: %s. Restarting it.", cpcd_stringify_state(new_state)); - sys_request_sequence_reset(); - } else - { - WARN("Setting ep#%d in error, new state: %s", endpoint_number, cpcd_stringify_state(new_state)); - - primary_close_endpoint(endpoint_number, true); - cpcd_close_endpoint(endpoint_number, false, false); - cpcd_set_endpoint_state(endpoint_number, new_state); - } -} - -void cpcd_reset_endpoint_sequence(uint8_t endpoint_number) -{ - cpcd_endpoints[endpoint_number].seq = 0; - cpcd_endpoints[endpoint_number].ack = 0; -} - -static void cpcd_clear_transmit_queue(slist_node_t **head, int endpoint_id) -{ - slist_node_t *current_node; - slist_node_t *next_node; - bool filter_with_endpoint_id; - uint8_t ep_id; - - if (!*head) - { - return; - } - - if (endpoint_id < 0) - { - filter_with_endpoint_id = false; - } else - { - filter_with_endpoint_id = true; - ep_id = (uint8_t)endpoint_id; - } - - current_node = *head; - - while (current_node) - { - next_node = current_node->node; - - transmit_queue_item_t *item = SLIST_ENTRY(current_node, transmit_queue_item_t, node); - if (!filter_with_endpoint_id - || (filter_with_endpoint_id && item->handle->address == ep_id)) - { - if (item->handle->pending_tx_complete == false) - { - free(item->handle->hdlc_header); - - // free payload if any - if (item->handle->data_length != 0) - { - // free payload - free((void *)item->handle->data); - } - free(item->handle); - - // remove element from list and free it - slist_remove(head, &item->node); - free(item); - } - } - - current_node = next_node; - } -} - -status_t cpcd_close_endpoint(uint8_t endpoint_number, bool notify_secondary, bool force_close) -{ - endpoint_t *ep; - - ep = find_endpoint(endpoint_number); - - ASSERT_ON(ep->state == CPC_EP_STATE_CLOSED); - - TRACE_CPCD("Closing endpoint #%d", endpoint_number); - - stop_re_transmit_timer(ep); - - cpcd_clear_transmit_queue(&ep->re_transmit_queue, -1); - cpcd_clear_transmit_queue(&ep->holding_list, -1); - cpcd_clear_transmit_queue(&transmit_queue, endpoint_number); - cpcd_clear_transmit_queue(&pending_on_security_ready_queue, endpoint_number); - - if (notify_secondary) - { - // State will be set to closed when secondary closes its endpoint - cpcd_set_endpoint_state(ep->id, CPC_EP_STATE_CLOSING); - - // Notify the secondary that the endpoint should get closed - sys_cmd_property_set(on_disconnect_notification, - 5, /* 5 retries */ - 100000, /* 100ms between retries*/ - EP_ID_TO_PROPERTY_STATE(ep->id), - &ep->state, - sizeof(cpc_ep_state_t), - false); - } - - if (ep->re_transmit_timer_private_data != NULL) - { - epoll_port_unregister(ep->re_transmit_timer_private_data); - - close(((epoll_port_private_data_t *)ep->re_transmit_timer_private_data)->file_descriptor); - free(ep->re_transmit_timer_private_data); - - ep->re_transmit_timer_private_data = NULL; - } - - if (force_close) - { - cpcd_set_endpoint_state(ep->id, CPC_EP_STATE_CLOSED); - TRACE_cpcd_CLOSE_ENDPOINT(ep->id); - } - - return STATUS_OK; -} - -void cpcd_set_endpoint_option(uint8_t endpoint_number, - endpoint_option_t option, - void *value) -{ - endpoint_t *ep = &cpcd_endpoints[endpoint_number]; - - ERROR_ON(ep->state != CPC_EP_STATE_OPEN); - - switch (option) - { - case EP_ON_IFRAME_RECEIVE: - ep->on_iframe_data_reception = (on_data_reception_t)value; - break; - case EP_ON_IFRAME_RECEIVE_ARG: - ASSERT("invalid option"); - break; - case EP_ON_UFRAME_RECEIVE: - ep->on_uframe_data_reception = (on_data_reception_t)value; - break; - case EP_ON_UFRAME_RECEIVE_ARG: - ASSERT("invalid option"); - break; - case EP_ON_IFRAME_WRITE_COMPLETED: - ASSERT("invalid option"); - break; - case EP_ON_IFRAME_WRITE_COMPLETED_ARG: - ASSERT("invalid option"); - break; - case EP_ON_UFRAME_WRITE_COMPLETED: - ASSERT("invalid option"); - break; - case EP_ON_UFRAME_WRITE_COMPLETED_ARG: - ASSERT("invalid option"); - break; - case EP_ON_FINAL: - ep->poll_final.on_final = value; - break; - case EP_ON_POLL: - // Can't happen on the primary - ASSERT("invalid option"); - break; - case EP_ON_POLL_ARG: - case EP_ON_FINAL_ARG: - ep->poll_final.on_fnct_arg = value; - break; - default: - ASSERT("invalid option"); - break; - } -} - -static void process_ack(endpoint_t *endpoint, uint8_t ack) -{ - transmit_queue_item_t *item; - slist_node_t *item_node; - buffer_handle_t *frame; - uint8_t control_byte; - uint8_t seq_number; - uint8_t ack_range_min; - uint8_t ack_range_max; - uint8_t frames_count_ack = 0; - - // Return if no frame to acknowledge - if (endpoint->re_transmit_queue == NULL) - { - return; - } - - // Get the sequence number of the first frame in the re-transmission queue - item = SLIST_ENTRY(endpoint->re_transmit_queue, transmit_queue_item_t, node); - frame = item->handle; - - control_byte = hdlc_get_control(frame->hdlc_header); - seq_number = hdlc_get_seq(control_byte); - - // Calculate the acceptable ACK number range - ack_range_min = (uint8_t)(seq_number + 1); - ack_range_min %= 4; - ack_range_max = (uint8_t)(seq_number + endpoint->frames_count_re_transmit_queue); - ack_range_max %= 4; - - // Check that received ACK number is in range - if (ack_range_max >= ack_range_min) - { - if (ack < ack_range_min - || ack > ack_range_max) - { - // Invalid ack number - return; - } - } else - { - if (ack > ack_range_max - && ack < ack_range_min) - { - // Invalid ack number - return; - } - } - - // Find number of frames acknowledged with ACK number - if (ack > seq_number) - { - frames_count_ack = (uint8_t)(ack - seq_number); - } else - { - frames_count_ack = (uint8_t)(4 - seq_number); - frames_count_ack = (uint8_t)(frames_count_ack + ack); - } - - // Stop incoming re-transmit timeout - stop_re_transmit_timer(endpoint); - - // This can happen during a re_transmit, process the ack once the frame is sent - if (frame->pending_tx_complete == true) - { - frame->acked = true; - frame->pending_ack = ack; - return; - } - - // Reset re-transmit counter - endpoint->packet_re_transmit_count = 0u; - - TRACE_CPCD("%d Received ack %d seq number %d", endpoint->id, ack, seq_number); - cpcd_compute_re_transmit_timeout(endpoint); - - // Remove all acknowledged frames in re-transmit queue - for (uint8_t i = 0; i < frames_count_ack; i++) - { - item_node = slist_pop(&endpoint->re_transmit_queue); - ASSERT_ON(item_node == NULL); - - item = SLIST_ENTRY(item_node, transmit_queue_item_t, node); - frame = item->handle; - control_byte = hdlc_get_control(frame->hdlc_header); - - ASSERT_ON(hdlc_get_frame_type(frame->control) != CPC_HDLC_FRAME_TYPE_IFRAME); - -#ifdef USE_ON_WRITE_COMPLETE - on_write_completed(endpoint->id, STATUS_OK); -#endif - - if (endpoint->id == CPC_EP_SYSTEM && hdlc_is_poll_final(control_byte)) - { - sys_cmd_poll_acknowledged(frame->data); - } - - free((void *)frame->data); - free(frame->hdlc_header); - free(frame); - free(item); - - // Update number of frames in re-transmit queue - endpoint->frames_count_re_transmit_queue--; - - // Update transmit window - endpoint->current_tx_window_space++; - - if (endpoint->re_transmit_queue == NULL) - { - break; - } - } - - // Put data frames hold in the endpoint in the tx queue if space in transmit window - while (endpoint->holding_list != NULL && endpoint->current_tx_window_space > 0) - { - slist_node_t *item = slist_pop(&endpoint->holding_list); - slist_push_back(&transmit_queue, item); - endpoint->current_tx_window_space--; - epoll_port_watch_back(endpoint->id); - } - - TRACE_EP_RXD_ACK(endpoint, ack); -} - -static void transmit_ack(endpoint_t *endpoint) -{ - buffer_handle_t *handle; - transmit_queue_item_t *item; - - // Get new frame handler - handle = (buffer_handle_t *)calloc_port(sizeof(buffer_handle_t)); - ERROR_SYSCALL_ON(handle == NULL); - - handle->endpoint = endpoint; - handle->address = endpoint->id; - - // Set ACK number in the sframe control byte - handle->control = hdlc_create_ctrl_sframe(endpoint->ack, 0); - - // Put frame in Tx Q so that it can be transmitted by CPC Core later - item = (transmit_queue_item_t *)calloc_port(sizeof(transmit_queue_item_t)); - ERROR_SYSCALL_ON(item == NULL); - - item->handle = handle; - - slist_push_back(&transmit_queue, &item->node); - TRACE_CPCD("Endpoint #%d sent ACK: %d", endpoint->id, endpoint->ack); - - cpcd_process_transmit_queue(); - - TRACE_EP_TXD_ACK(endpoint); -} - -static void re_transmit_frame(endpoint_t *endpoint) -{ - transmit_queue_item_t *item; - slist_node_t *item_node; - - item_node = slist_pop(&endpoint->re_transmit_queue); - - ASSERT_ON(item_node == NULL); - - item = SLIST_ENTRY(item_node, transmit_queue_item_t, node); - - // Don't re_transmit the frame if it is already being transmitted - if (item->handle->pending_tx_complete == true) - { - slist_push(&endpoint->re_transmit_queue, &item->node); - return; - } - - // Only i-frames support retransmission - ASSERT_ON(hdlc_get_frame_type(item->handle->control) != CPC_HDLC_FRAME_TYPE_IFRAME); - - // Free the previous header buffer. The tx queue process will malloc a new one and fill it. - free(item->handle->hdlc_header); - - endpoint->packet_re_transmit_count++; - endpoint->frames_count_re_transmit_queue--; - - //Put frame in Tx Q so that it can be transmitted by CPC Core later - slist_push(&transmit_queue, &item->node); - - TRACE_EP_RETXD_DATA_FRAME(endpoint); - - return; -} - -static void transmit_reject(endpoint_t *endpoint, - uint8_t address, - uint8_t ack, - reject_reason_t reason) -{ - uint16_t fcs; - buffer_handle_t *handle; - transmit_queue_item_t *item; - - handle = (buffer_handle_t *)calloc_port(sizeof(buffer_handle_t)); - ERROR_ON(handle == NULL); - - handle->address = address; - - // Set the SEQ number and ACK number in the control byte - handle->control = hdlc_create_ctrl_sframe(ack, CPC_HDLC_REJECT_SFRAME_FUNCTION); - - handle->data = calloc_port(sizeof(uint8_t)); - ERROR_SYSCALL_ON(handle->data == NULL); - - // Set in reason - *((uint8_t *)handle->data) = (uint8_t)reason; - handle->data_length = sizeof(uint8_t); - - // Compute payload CRC - fcs = cpc_get_crc_sw(handle->data, 1); - handle->fcs[0] = (uint8_t)fcs; - handle->fcs[1] = (uint8_t)(fcs >> 8); - - // Put frame in Tx Q so that it can be transmitted by CPC Core later - item = (transmit_queue_item_t *)calloc_port(sizeof(transmit_queue_item_t)); - ERROR_SYSCALL_ON(item == NULL); - - item->handle = handle; - - slist_push_back(&transmit_queue, &item->node); - - if (endpoint != NULL) - { - switch (reason) - { - case HDLC_REJECT_CHECKSUM_MISMATCH: - TRACE_EP_TXD_REJECT_CHECKSUM_MISMATCH(endpoint); - WARN("Host received a packet with an invalid checksum on ep %d", endpoint->id); - break; - case HDLC_REJECT_SEQUENCE_MISMATCH: - TRACE_EP_TXD_REJECT_SEQ_MISMATCH(endpoint); - break; - case HDLC_REJECT_OUT_OF_MEMORY: - TRACE_EP_TXD_REJECT_OUT_OF_MEMORY(endpoint); - break; - case HDLC_REJECT_SECURITY_ISSUE: - TRACE_EP_TXD_REJECT_SECURITY_ISSUE(endpoint); - break; - case HDLC_REJECT_UNREACHABLE_ENDPOINT: - TRACE_EP_TXD_REJECT_DESTINATION_UNREACHABLE(endpoint); - break; - case HDLC_REJECT_ERROR: - default: - TRACE_EP_TXD_REJECT_FAULT(endpoint); - break; - } - } else - { - switch (reason) - { - case HDLC_REJECT_UNREACHABLE_ENDPOINT: - TRACE_cpcd_TXD_REJECT_DESTINATION_UNREACHABLE(); - break; - default: - ERROR(); - break; - } - } -} - -static bool cpcd_process_tx_queue(void) -{ - slist_node_t *node; - transmit_queue_item_t *item; - transmit_queue_item_t *tx_complete_item; - buffer_handle_t *frame; - uint16_t total_length; - uint8_t frame_type; - - if (pending_on_security_ready_queue != NULL) - { - TRACE_CPCD("Sending packet that were hold back because security was not ready"); - node = slist_pop(&pending_on_security_ready_queue); - } else - { - // Return if nothing to transmit - if (transmit_queue == NULL) - { - TRACE_CPCD("transmit_queue is empty and cpcd is not ready yet to process hold back packets"); - return false; - } - - // Get first queued frame for transmission - node = slist_pop(&transmit_queue); - } - - item = SLIST_ENTRY(node, transmit_queue_item_t, node); - frame = item->handle; - - frame->hdlc_header = calloc_port(CPC_HDLC_HEADER_RAW_SIZE); - ERROR_SYSCALL_ON(frame->hdlc_header == NULL); - - // Form the HDLC header - total_length = (frame->data_length != 0) ? (uint16_t)(frame->data_length + 2) : 0; - - frame_type = hdlc_get_frame_type(frame->control); - - if (frame_type == CPC_HDLC_FRAME_TYPE_IFRAME) - { - hdlc_set_ctrl_ack(&frame->control, frame->endpoint->ack); - } else if (frame_type == CPC_HDLC_FRAME_TYPE_UFRAME) - { - ASSERT_ON(frame->endpoint->id != CPC_EP_SYSTEM); - } - - hdlc_create_header(frame->hdlc_header, frame->address, total_length, frame->control, true); - - uint16_t encrypted_data_length = frame->data_length; - uint8_t *encrypted_payload = (uint8_t *)frame->data; - - /* Construct and send the frame to the hal */ - { - // total_length takes into account FCS and security tag - size_t frame_length = CPC_HDLC_HEADER_RAW_SIZE + total_length; - - frame_t *frame_buffer = (frame_t *)calloc_port(frame_length); - ERROR_ON(frame_buffer == NULL); - - /* copy the header */ - memcpy(frame_buffer->header, frame->hdlc_header, CPC_HDLC_HEADER_RAW_SIZE); - - /* copy the payload */ - memcpy(frame_buffer->payload, encrypted_payload, encrypted_data_length); - - if (encrypted_data_length != 0) - { - memcpy(&frame_buffer->payload[encrypted_data_length], frame->fcs, sizeof(frame->fcs)); - } - - frame->pending_tx_complete = true; - - tx_complete_item = (transmit_queue_item_t *)malloc(sizeof(transmit_queue_item_t)); - ERROR_SYSCALL_ON(tx_complete_item == NULL); - tx_complete_item->handle = frame; - - slist_push_back(&pending_on_tx_complete, &tx_complete_item->node); - - cpcd_push_frame_to_hal(frame_buffer, frame_length); - - free(frame_buffer); - if (frame->data != encrypted_payload) - { - /* in case a buffer was allocated for allocation, free it */ - free((void *)encrypted_payload); - } - } - - TRACE_EP_FRAME_TRANSMIT_SUBMITTED(frame->endpoint); - - if (frame_type == CPC_HDLC_FRAME_TYPE_IFRAME) - { - // Put frame in in re-transmission queue if it's a I-frame type (with data) - slist_push_back(&frame->endpoint->re_transmit_queue, &item->node); - frame->endpoint->frames_count_re_transmit_queue++; - } else - { - free(item); // Free transmit queue item - } - - return true; -} - -static void re_transmit_timeout(endpoint_t *endpoint) -{ - if (endpoint->packet_re_transmit_count >= CPC_RE_TRANSMIT) - { - WARN("Retransmit limit reached on endpoint #%d", endpoint->id); - cpcd_set_endpoint_in_error(endpoint->id, CPC_EP_STATE_ERROR_DEST_UNREACH); - } else - { - endpoint->re_transmit_timeout_ms *= 2; - if (endpoint->re_transmit_timeout_ms > MAX_RE_TRANSMIT_TIMEOUT_MS) - { - endpoint->re_transmit_timeout_ms = MAX_RE_TRANSMIT_TIMEOUT_MS; - } - - TRACE_CPCD("New RTO calculated on ep %d, after re_transmit timeout: %ldms", endpoint->id, endpoint->re_transmit_timeout_ms); - - re_transmit_frame(endpoint); - } -} - -static bool is_seq_valid(uint8_t seq, uint8_t ack) -{ - bool result = false; - - if (seq == (ack - 1u)) - { - result = true; - } else if (ack == 0u && seq == 3u) - { - result = true; - } - - return result; -} - -static endpoint_t *find_endpoint(uint8_t endpoint_number) -{ - return &cpcd_endpoints[endpoint_number]; -} - -static void stop_re_transmit_timer(endpoint_t *endpoint) -{ - int ret; - epoll_port_private_data_t *fd_timer_private_data; - - /* Passing itimerspec with it_value of 0 stops the timer. */ - const struct itimerspec cancel_time = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, - .it_value = { .tv_sec = 0, .tv_nsec = 0 } }; - - fd_timer_private_data = endpoint->re_transmit_timer_private_data; - - if (fd_timer_private_data == NULL) - { - return; - } - - ret = timerfd_settime(fd_timer_private_data->file_descriptor, - 0, - &cancel_time, - NULL); - - ERROR_SYSCALL_ON(ret < 0); -} - -static double diff_timespec_ms(const struct timespec *final, const struct timespec *initial) -{ - return (double)((final->tv_sec - initial->tv_sec) * 1000) - + (double)(final->tv_nsec - initial->tv_nsec) / 1000000.0; -} - -static void start_re_transmit_timer(endpoint_t *endpoint, struct timespec offset) -{ - int ret; - epoll_port_private_data_t *fd_timer_private_data; - - struct timespec current_timestamp; - clock_gettime(CLOCK_MONOTONIC, ¤t_timestamp); - - long offset_in_ms; - - offset_in_ms = (long)diff_timespec_ms(&offset, ¤t_timestamp); - - fd_timer_private_data = endpoint->re_transmit_timer_private_data; - - if (offset_in_ms < 0) - { - offset_in_ms = 0; - } - - if (endpoint->state != CPC_EP_STATE_OPEN) - { - return; - } - - /* Make sure the timer file descriptor is open*/ - ERROR_ON(fd_timer_private_data == NULL); - ERROR_ON(fd_timer_private_data->file_descriptor < 0); - - struct itimerspec timeout_time = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, - .it_value = { .tv_sec = ((offset_in_ms + endpoint->re_transmit_timeout_ms) / 1000), .tv_nsec = (((offset_in_ms + endpoint->re_transmit_timeout_ms) % 1000) * 1000000) } }; - - ret = timerfd_settime(fd_timer_private_data->file_descriptor, - 0, - &timeout_time, - NULL); - - ERROR_SYSCALL_ON(ret < 0); -} - -static void cpcd_process_ep_timeout(epoll_port_private_data_t *event_private_data) -{ - int fd_timer = event_private_data->file_descriptor; - uint8_t endpoint_number = event_private_data->endpoint_number; - - /* Ack the timer */ - { - uint64_t expiration; - ssize_t ret; - - ret = read(fd_timer, &expiration, sizeof(expiration)); - ERROR_ON(ret < 0); - - /* we missed a timeout*/ - WARN_ON(expiration != 1); - } - - re_transmit_timeout(&cpcd_endpoints[endpoint_number]); -} - -static void cpcd_push_frame_to_hal(const void *frame, size_t frame_len) -{ - TRACE_FRAME("Core : Pushed frame to cpc : ", frame, frame_len); - ssize_t ret = send(hal_sock_fd, frame, frame_len, 0); - - ERROR_SYSCALL_ON(ret < 0); - - ERROR_ON((size_t)ret != frame_len); - - TRACE_cpcd_TXD_TRANSMIT_COMPLETED(); -} - -static bool cpcd_pull_frame_from_hal(frame_t **frame_buf, size_t *frame_buf_len) -{ - size_t datagram_length; - - /* Poll the socket to get the next pending datagram size */ - { - ssize_t retval = recv(hal_sock_fd, NULL, 0, MSG_PEEK | MSG_TRUNC | MSG_DONTWAIT); - ERROR_SYSCALL_ON(retval < 0); - datagram_length = (size_t)retval; - - /* Socket closed */ - if (retval == 0) - { - TRACE_CPCD("Driver closed the data socket"); - int ret_close = close(hal_sock_fd); - ERROR_SYSCALL_ON(ret_close != 0); - return false; - } - - ASSERT_ON(datagram_length == 0); - - /* The length of the frame should be at minimum a header length */ - ASSERT_ON(datagram_length < sizeof(frame_t)); - } - - /* Allocate a buffer of the right size */ - { - *frame_buf = (frame_t *)calloc_port((size_t)datagram_length); - ERROR_SYSCALL_ON(*frame_buf == NULL); - } - - /* Fetch the datagram from the hal socket */ - { - ssize_t ret = recv(hal_sock_fd, *frame_buf, (size_t)datagram_length, 0); - - ERROR_SYSCALL_ON(ret < 0); - - /* The next pending datagram size should be equal to what we just read */ - ERROR_ON((size_t)ret != (size_t)datagram_length); - } - - *frame_buf_len = (size_t)datagram_length; - return true; -} - -static status_t cpcd_push_data_to_server(uint8_t ep_id, const void *data, size_t data_len) -{ - return primary_push_data_to_endpoint(ep_id, data, data_len); -} diff --git a/module/cpc/cpcd/primary/cpcd/cpcd.h b/module/cpc/cpcd/primary/cpcd/cpcd.h deleted file mode 100644 index d69feb8..0000000 --- a/module/cpc/cpcd/primary/cpcd/cpcd.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef CPCD_H -#define CPCD_H -#include -#include "lib/libcpc.h" -#include "hdlc.h" -#include "utility/status.h" -#include "utility/slist.h" -#include "primary/cpcd/cpcd.h" -#define OPEN_EP_FLAG_IFRAME_DISABLE 0x01 << 0 -#define OPEN_EP_FLAG_UFRAME_ENABLE 0x01 << 1 -#define OPEN_EP_FLAG_UFRAME_INFORMATION_DISABLE 0x01 << 2 -#define FLAG_UFRAME_INFORMATION 0x01 << 1 -#define FLAG_UFRAME_POLL 0x01 << 2 -#define FLAG_UFRAME_RESET_COMMAND 0x01 << 3 -#define FLAG_INFORMATION_POLL 0x01 << 4 -// Maximum number of retry while sending a frame -#define CPC_RE_TRANSMIT 10 -#define MAX_RE_TRANSMIT_TIMEOUT_MS 5000 -#define MIN_RE_TRANSMIT_TIMEOUT_MS 50 -#define MIN_RE_TRANSMIT_TIMEOUT_MINIMUM_VARIATION_MS 5 -#define TRANSMIT_WINDOW_MIN_SIZE 1u -#define TRANSMIT_WINDOW_MAX_SIZE 1u -#define VERSION_MAJOR 1u -#define VERSION_MINOR 1u -#define EP_MAX_COUNT 256 -void cpcd_init(int driver_fd, int driver_notify_fd); -void cpcd_open_endpoint(uint8_t endpoit_number, uint8_t flags, uint8_t tx_win_size); -void cpcd_process_transmit_queue(void); -void cpcd_reset_endpoint_sequence(uint8_t endpoint_number); -bool cpcd_ep_is_busy(uint8_t ep_id); -status_t cpcd_close_endpoint(uint8_t endpoint_number, bool notify_secondary, bool force_close); -cpc_ep_state_t cpcd_get_endpoint_state(uint8_t ep_id); -bool cpcd_get_endpoint_encryption(uint8_t ep_id); -void cpcd_set_endpoint_state(uint8_t ep_id, cpc_ep_state_t state); -cpc_ep_state_t cpcd_state_mapper(uint8_t state); -const char *cpcd_stringify_state(cpc_ep_state_t state); -void cpcd_write(uint8_t endpoint_number, const void *message, size_t message_len, uint8_t flags); -CPC_ENUM_DECLARE(endpoint_option_t) -{ - EP_ON_IFRAME_RECEIVE = 0, - EP_ON_IFRAME_RECEIVE_ARG, - EP_ON_UFRAME_RECEIVE, - EP_ON_UFRAME_RECEIVE_ARG, - EP_ON_IFRAME_WRITE_COMPLETED, - EP_ON_IFRAME_WRITE_COMPLETED_ARG, - EP_ON_UFRAME_WRITE_COMPLETED, - EP_ON_UFRAME_WRITE_COMPLETED_ARG, - EP_ON_POLL, - EP_ON_POLL_ARG, - EP_ON_FINAL, - EP_ON_FINAL_ARG, -}; -void cpcd_process_endpoint_change(uint8_t endpoint_number, cpc_ep_state_t ep_state); -bool cpcd_ep_is_closing(uint8_t ep_id); -void cpcd_set_endpoint_in_error(uint8_t endpoint_number, cpc_ep_state_t new_state); -void cpcd_set_endpoint_option(uint8_t endpoint_number, - endpoint_option_t option, - void *value); -// ----------------------------------------------------------------------------- -// Data Types -typedef void (*on_final_t)(uint8_t endpoint_id, void *arg, void *answer, uint32_t answer_lenght); -typedef struct -{ - void *on_fnct_arg; - on_final_t on_final; -} poll_final_t; -typedef void (*on_data_reception_t)(uint8_t endpoint_id, const void *data, size_t data_len); -/* - * Internal state for the endpoints. Will be filled by cpc_register_endpoint() - */ -typedef struct endpoint -{ - uint8_t id; - uint8_t flags; - uint8_t seq; - uint8_t ack; - uint8_t configured_tx_win_size; - uint8_t current_tx_window_space; - uint8_t frames_count_re_transmit_queue; - uint8_t packet_re_transmit_count; - long re_transmit_timeout_ms; - void *re_transmit_timer_private_data; - cpc_ep_state_t state; - slist_node_t *re_transmit_queue; - slist_node_t *holding_list; - on_data_reception_t on_uframe_data_reception; - on_data_reception_t on_iframe_data_reception; - poll_final_t poll_final; - struct timespec last_iframe_sent_timestamp; - long smoothed_rtt; - long rtt_variation; -}endpoint_t; -typedef struct -{ - uint32_t frame_counter; -} security_frame_t; -typedef struct -{ - void *hdlc_header; - const void *data; - uint16_t data_length; - uint8_t fcs[2]; - uint8_t control; - uint8_t address; - endpoint_t *endpoint; - uint8_t pending_ack; - bool acked; - bool pending_tx_complete; -} buffer_handle_t; -typedef struct -{ - slist_node_t node; - buffer_handle_t *handle; -} transmit_queue_item_t; -typedef struct -{ - uint8_t header[CPC_HDLC_HEADER_RAW_SIZE]; - uint8_t payload[]; // last two bytes are little endian 16bits -}frame_t; -#endif diff --git a/module/cpc/cpcd/primary/cpcd/crc.c b/module/cpc/cpcd/primary/cpcd/crc.c deleted file mode 100644 index 49f1920..0000000 --- a/module/cpc/cpcd/primary/cpcd/crc.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "crc.h" - -static uint16_t cpc_compute_crc16(uint8_t new_byte, uint16_t prev_result); - -uint16_t cpc_get_crc_sw(const void *buffer, uint16_t buffer_length) -{ - uint16_t i; - uint16_t crc = 0; - - for (i = 0; i < buffer_length; i++) - { - crc = cpc_compute_crc16((uint8_t)((uint8_t *)buffer)[i], crc); - } - - return crc; -} - -bool cpc_check_crc_sw(const void *buffer, uint16_t buffer_length, uint16_t expected_crc) -{ - uint16_t computed_crc; - - computed_crc = cpc_get_crc_sw(buffer, buffer_length); - - return(computed_crc == expected_crc); -} - -static uint16_t cpc_compute_crc16(uint8_t new_byte, uint16_t prev_result) -{ -#if (CPC_CRC_0 == 1) - prev_result = ((uint16_t)(prev_result >> 8)) | ((uint16_t)(prev_result << 8)); - prev_result ^= new_byte; - prev_result ^= (prev_result & 0xff) >> 4; - prev_result ^= (uint16_t)(((uint16_t)(prev_result << 8)) << 4); - prev_result ^= ((uint8_t)(((uint8_t)(prev_result & 0xff)) << 5)) - | ((uint16_t)((uint16_t)((uint8_t)(((uint8_t)(prev_result & 0xff)) >> 3)) << 8)); -#else - uint8_t bit; - - for (bit = 0; bit < 8; bit++) - { - prev_result ^= (new_byte & 0x01); - prev_result = (prev_result & 0x01) ? (prev_result >> 1) ^ 0x8408 : (prev_result >> 1); - new_byte = new_byte >> 1; - } -#endif - return prev_result; -} diff --git a/module/cpc/cpcd/primary/cpcd/crc.h b/module/cpc/cpcd/primary/cpcd/crc.h deleted file mode 100644 index 9266a29..0000000 --- a/module/cpc/cpcd/primary/cpcd/crc.h +++ /dev/null @@ -1,12 +0,0 @@ - - -#ifndef CRC_H -#define CRC_H - -#include -#include - -uint16_t cpc_get_crc_sw(const void *buffer, uint16_t buffer_length); -bool cpc_check_crc_sw(const void *buffer, uint16_t buffer_length, uint16_t expected_crc); - -#endif //CRC_H diff --git a/module/cpc/cpcd/primary/cpcd/hdlc.c b/module/cpc/cpcd/primary/cpcd/hdlc.c deleted file mode 100644 index 541e694..0000000 --- a/module/cpc/cpcd/primary/cpcd/hdlc.c +++ /dev/null @@ -1,31 +0,0 @@ - - -#include "hdlc.h" -#include "crc.h" - -void hdlc_create_header(uint8_t *header_buf, - uint8_t address, - uint16_t length, - uint8_t control, - bool compute_crc) -{ - uint16_u length_union; - - length_union.uint16 = cpu_to_le16(length); - - header_buf[0] = CPC_HDLC_FLAG_VAL; - header_buf[1] = address; - header_buf[2] = length_union.bytes[0]; - header_buf[3] = length_union.bytes[1]; - header_buf[4] = control; - - if (compute_crc) - { - uint16_u hcs_union; - - hcs_union.uint16 = cpu_to_le16(cpc_get_crc_sw(header_buf, CPC_HDLC_HEADER_SIZE)); - - header_buf[5] = hcs_union.bytes[0]; - header_buf[6] = hcs_union.bytes[1]; - } -} diff --git a/module/cpc/cpcd/primary/cpcd/hdlc.h b/module/cpc/cpcd/primary/cpcd/hdlc.h deleted file mode 100644 index c877a82..0000000 --- a/module/cpc/cpcd/primary/cpcd/hdlc.h +++ /dev/null @@ -1,208 +0,0 @@ - - -#ifndef CPC_HDLC_H -#define CPC_HDLC_H - -#include -#include -#include -#include - -#include "libcpc.h" -#include "utility/endian.h" - -#define CPC_HDLC_FLAG_VAL (0x14) - -#define CPC_HDLC_HEADER_SIZE (5) -#define CPC_HDLC_HEADER_RAW_SIZE (7) -#define CPC_HDLC_FCS_SIZE (2) -#define CPC_HDLC_REJECT_PAYLOAD_SIZE (1) -#define CPC_HDLC_CONTROL_UFRAME_TYPE_MASK (0x37) -#define CPC_HDLC_ACK_SFRAME_FUNCTION (0) -#define CPC_HDLC_REJECT_SFRAME_FUNCTION (1) - - -CPC_ENUM_DECLARE(hdlc_frame_type_t) -{ - CPC_HDLC_FRAME_TYPE_IFRAME = 0, - CPC_HDLC_FRAME_TYPE_SFRAME = 2, - CPC_HDLC_FRAME_TYPE_UFRAME = 3 -}; - -CPC_ENUM_DECLARE(hdlc_frame_pos_t) -{ - CPC_HDLC_FLAG_POS = 0, - CPC_HDLC_ADDRESS_POS = 1, - CPC_HDLC_LENGTH_POS = 2, - CPC_HDLC_CONTROL_POS = 4, - CPC_HDLC_HCS_POS = 5 -}; - -CPC_ENUM_DECLARE(hdlc_frame_shift_t) -{ - CPC_HDLC_CONTROL_UFRAME_TYPE_SHIFT = 0, - CPC_HDLC_CONTROL_P_F_SHIFT = 2, - CPC_HDLC_CONTROL_SEQ_SHIFT = 3, - CPC_HDLC_CONTROL_SFRAME_FNCT_ID_SHIFT = 4, - CPC_HDLC_CONTROL_FRAME_TYPE_SHIFT = 6 -}; - - -CPC_ENUM_DECLARE(hdlc_frame_ctrl_u_t) -{ - CPC_HDLC_CONTROL_UFRAME_TYPE_INFORMATION = 0x00, - CPC_HDLC_CONTROL_UFRAME_TYPE_POLL_FINAL = 0x04, - CPC_HDLC_CONTROL_UFRAME_TYPE_ACKNOWLEDGE = 0x0E, - CPC_HDLC_CONTROL_UFRAME_TYPE_RESET_SEQ = 0x31, - CPC_HDLC_CONTROL_UFRAME_TYPE_UNKNOWN = 0xFF -}; - - -CPC_ENUM_DECLARE(reject_reason_t) -{ - HDLC_REJECT_NO_ERROR = 0, - HDLC_REJECT_CHECKSUM_MISMATCH, - HDLC_REJECT_SEQUENCE_MISMATCH, - HDLC_REJECT_OUT_OF_MEMORY, - HDLC_REJECT_SECURITY_ISSUE, - HDLC_REJECT_UNREACHABLE_ENDPOINT, - HDLC_REJECT_ERROR -}; - -typedef union -{ - uint8_t bytes[2]; - uint16_t uint16; -}uint16_u; - -static inline uint8_t hdlc_get_flag(const uint8_t *header_buf) -{ - return header_buf[CPC_HDLC_FLAG_POS]; -} - -static inline uint8_t hdlc_get_address(const uint8_t *header_buf) -{ - return header_buf[CPC_HDLC_ADDRESS_POS]; -} - -static inline uint16_t hdlc_get_length(const uint8_t *header_buf) -{ - uint16_u u; - - u.bytes[0] = header_buf[CPC_HDLC_LENGTH_POS]; - u.bytes[1] = header_buf[CPC_HDLC_LENGTH_POS + 1]; - - return le16_to_cpu(u.uint16); -} - -static inline uint8_t hdlc_get_control(const uint8_t *header_buf) -{ - return header_buf[CPC_HDLC_CONTROL_POS]; -} - -static inline uint16_t hdlc_get_hcs(const uint8_t *header_buf) -{ - uint16_u u; - - u.bytes[0] = header_buf[CPC_HDLC_HCS_POS]; - u.bytes[1] = header_buf[CPC_HDLC_HCS_POS + 1]; - - return le16_to_cpu(u.uint16); -} - -static inline uint16_t hdlc_get_fcs(const uint8_t *payload_buf, uint16_t payload_length) -{ - uint16_u u; - - u.bytes[0] = payload_buf[payload_length]; - u.bytes[1] = payload_buf[payload_length + 1]; - - return le16_to_cpu(u.uint16); -} - -static inline uint8_t hdlc_get_frame_type(uint8_t control) -{ - uint8_t type = control >> CPC_HDLC_CONTROL_FRAME_TYPE_SHIFT; - - if (type == 1 || type == 0) - { - type = CPC_HDLC_FRAME_TYPE_IFRAME; - } - - return type; -} - -static inline uint8_t hdlc_get_seq(uint8_t control) -{ - return (control >> CPC_HDLC_CONTROL_SEQ_SHIFT) & 0x03; -} - -static inline uint8_t hdlc_get_ack(uint8_t control) -{ - return control & 0x03; -} - -static inline uint8_t hdlc_get_sframe_function(uint8_t control) -{ - return (control >> CPC_HDLC_CONTROL_SFRAME_FNCT_ID_SHIFT) & 0x03; -} - -static inline uint8_t hdlc_get_uframe_type(uint8_t control) -{ - return (control >> CPC_HDLC_CONTROL_UFRAME_TYPE_SHIFT) & CPC_HDLC_CONTROL_UFRAME_TYPE_MASK; -} - -static inline bool hdlc_is_poll_final(uint8_t control) -{ - if (control & (1 << CPC_HDLC_CONTROL_P_F_SHIFT)) - { - return true; - } - return false; -} - -void hdlc_create_header(uint8_t *header_buf, - uint8_t address, - uint16_t length, - uint8_t control, - bool compute_crc); - -static inline uint8_t hdlc_create_ctrl_data(uint8_t seq, uint8_t ack, bool poll_final) -{ - uint8_t control = CPC_HDLC_FRAME_TYPE_IFRAME << CPC_HDLC_CONTROL_FRAME_TYPE_SHIFT; - - control |= (uint8_t)(seq << CPC_HDLC_CONTROL_SEQ_SHIFT); - control |= ack; - control |= (uint8_t)((uint8_t)poll_final << CPC_HDLC_CONTROL_P_F_SHIFT); - - return control; -} - - -static inline uint8_t hdlc_create_ctrl_sframe(uint8_t ack, uint8_t sframe_function) -{ - uint8_t control = CPC_HDLC_FRAME_TYPE_SFRAME << CPC_HDLC_CONTROL_FRAME_TYPE_SHIFT; - - control |= (uint8_t)(sframe_function << CPC_HDLC_CONTROL_SFRAME_FNCT_ID_SHIFT); - control |= ack; - - return control; -} - -static inline uint8_t hdlc_create_ctrl_uframe(uint8_t type) -{ - uint8_t control = CPC_HDLC_FRAME_TYPE_UFRAME << CPC_HDLC_CONTROL_FRAME_TYPE_SHIFT; - - control |= type << CPC_HDLC_CONTROL_UFRAME_TYPE_SHIFT; - - return control; -} - -static inline void hdlc_set_ctrl_ack(uint8_t *control, - uint8_t ack) -{ - *control = (uint8_t)(*control & ~0x03); - *control |= ack; -} - -#endif // CPC_HDLC_H diff --git a/module/cpc/cpcd/primary/epoll_port/epoll_port.c b/module/cpc/cpcd/primary/epoll_port/epoll_port.c deleted file mode 100644 index bc43b23..0000000 --- a/module/cpc/cpcd/primary/epoll_port/epoll_port.c +++ /dev/null @@ -1,130 +0,0 @@ - - -#include "epoll_port.h" -#include "utility/logs.h" -#include "utility/slist.h" -#include "utility/utils.h" -#include "primary/cpcd/cpcd.h" -#include "primary/primary/primary.h" - -#include -#include -#include - -typedef struct -{ - slist_node_t node; - struct epoll_port_private_data *unregistered_epoll_port_private_data; -}unwatched_endpoint_list_item_t; - -/* List to keep track of every connected library instance over the control socket */ -static slist_node_t *unwatched_endpoint_list; - -static int fd_epoll; - -void epoll_port_init(void) -{ - /* Create the epoll set */ - { - fd_epoll = epoll_create1(EPOLL_CLOEXEC); - ERROR_SYSCALL_ON(fd_epoll < 0); - } - - slist_init(&unwatched_endpoint_list); -} - -void epoll_port_register(epoll_port_private_data_t *private_data) -{ - struct epoll_event event = {}; - int ret; - - ERROR_ON(private_data == NULL); - ERROR_ON(private_data->callback == NULL); - ERROR_ON(private_data->file_descriptor < 1); - - event.events = EPOLLIN; /* Level-triggered read() availability */ - event.data.ptr = private_data; - - ret = epoll_ctl(fd_epoll, EPOLL_CTL_ADD, private_data->file_descriptor, &event); - ERROR_SYSCALL_ON(ret < 0); -} - -void epoll_port_unregister(epoll_port_private_data_t *private_data) -{ - int ret; - unwatched_endpoint_list_item_t *item; - - ERROR_ON(private_data == NULL); - ERROR_ON(private_data->callback == NULL); - ERROR_ON(private_data->file_descriptor < 1); - - SLIST_FOR_EACH_ENTRY(unwatched_endpoint_list, - item, - unwatched_endpoint_list_item_t, - node) - { - if (private_data == item->unregistered_epoll_port_private_data) - { - slist_remove(&unwatched_endpoint_list, &item->node); - free(item); - return; - } - } - - ret = epoll_ctl(fd_epoll, EPOLL_CTL_DEL, private_data->file_descriptor, NULL); - - ERROR_SYSCALL_ON(ret < 0); -} - -void epoll_port_unwatch(epoll_port_private_data_t *private_data) -{ - epoll_port_unregister(private_data); - - unwatched_endpoint_list_item_t *item = calloc_port(sizeof(unwatched_endpoint_list_item_t)); - ERROR_ON(item == NULL); - - item->unregistered_epoll_port_private_data = private_data; - - slist_push(&unwatched_endpoint_list, &item->node); -} - -void epoll_port_watch_back(uint8_t endpoint_number) -{ - unwatched_endpoint_list_item_t *item; - - slist_node_t *item_node = unwatched_endpoint_list; - while (1) - { - item = SLIST_ENTRY(item_node, - unwatched_endpoint_list_item_t, - node); - if (item == NULL) - { - break; - } - item_node = item_node->node; - if (endpoint_number == item->unregistered_epoll_port_private_data->endpoint_number) - { - epoll_port_register(item->unregistered_epoll_port_private_data); - slist_remove(&unwatched_endpoint_list, &item->node); - free(item); - } - } -} - -size_t epoll_port_wait_for_event(struct epoll_event events[], size_t max_event_number) -{ - int event_count; - - do - { - event_count = epoll_wait(fd_epoll, events, (int)max_event_number, -1); - } while ((event_count == -1) && (errno == EINTR)); - - ERROR_SYSCALL_ON(event_count < 0); - - /* Timeouts should not occur */ - ERROR_ON(event_count == 0); - - return (size_t)event_count; -} diff --git a/module/cpc/cpcd/primary/epoll_port/epoll_port.h b/module/cpc/cpcd/primary/epoll_port/epoll_port.h deleted file mode 100644 index 1eaa2df..0000000 --- a/module/cpc/cpcd/primary/epoll_port/epoll_port.h +++ /dev/null @@ -1,35 +0,0 @@ - - -#ifndef EPOLL_H -#define EPOLL_H - -#include "stdint.h" -#include - -//forward declaration for interdependency -struct epoll_port_private_data; - -typedef struct epoll_port_private_data epoll_port_private_data_t; - -typedef void (*epoll_port_callback_t)(epoll_port_private_data_t *private_data); - -struct epoll_port_private_data -{ - epoll_port_callback_t callback; - int file_descriptor; - uint8_t endpoint_number; -}; - -void epoll_port_init(void); - -void epoll_port_register(epoll_port_private_data_t *private_data); - -void epoll_port_unregister(epoll_port_private_data_t *private_data); - -void epoll_port_unwatch(epoll_port_private_data_t *private_data); - -void epoll_port_watch_back(uint8_t endpoint_number); - -size_t epoll_port_wait_for_event(struct epoll_event events[], size_t max_event_number); - -#endif //EPOLL_H diff --git a/module/cpc/cpcd/primary/primary/primary.c b/module/cpc/cpcd/primary/primary/primary.c deleted file mode 100644 index c719a9f..0000000 --- a/module/cpc/cpcd/primary/primary/primary.c +++ /dev/null @@ -1,1208 +0,0 @@ -/** - * @file primary.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-10-30 - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utility/errcode.h" -#include "utility/logs.h" -#include "utility/config.h" -#include "utility/utils.h" -#include "utility/slist.h" -#include "primary/primary/primary.h" -#include "primary/primary_cpcd.h" -#include "primary/system/callbacks.h" -#include "primary/system/system.h" -#include "primary/epoll_port/epoll_port.h" -#include "primary/cpcd/cpcd.h" -#include "primary/cpcd/cpcd.h" -#include "libcpc.h" -#include "version.h" -//============================================================================= -// Constant Definition -//============================================================================= -#define PRIMARY_EP_MAX_COUNTS (256) -//============================================================================= -// Macro Definition -//============================================================================= - -//============================================================================= -// Structure Definition -//============================================================================= -typedef struct -{ - slist_node_t node; - uint8_t endpoint_id; - int fd_ctrl_data_socket; -}pd_ce_list_t; - -typedef struct -{ - slist_node_t node; - epoll_port_private_data_t data_socket_epoll_port_data; - pid_t pid; -}ctrl_socket_data_list_t; - -typedef struct -{ - slist_node_t node; - epoll_port_private_data_t event_socket_epoll_port_private_data; -}event_socket_data_list_t; - -typedef struct -{ - slist_node_t node; - epoll_port_private_data_t data_socket_epoll_port_data; -}data_socket_data_list_t; - -typedef struct -{ - slist_node_t node; - int fd_data_socket; - int fd_ctrl_data_socket; -}data_ctrl_data_socket_pair_close_list_item_t; - -typedef struct -{ - uint32_t open_data_connections; - uint32_t open_event_connections; - uint32_t pending_close; - epoll_port_private_data_t event_connection_socket_epoll_port_private_data; - epoll_port_private_data_t connection_socket_epoll_port_private_data; - slist_node_t *event_data_socket_epoll_port_data; - slist_node_t *data_socket_epoll_port_data; - slist_node_t *data_ctrl_data_socket_pair; -}ep_ctrl_context_t; - -//============================================================================= -// Global Data Definition -//============================================================================= -static ep_ctrl_context_t ep_ctx[PRIMARY_EP_MAX_COUNTS]; -static slist_node_t *pending_connections; -static slist_node_t *ctrl_connections; -static int fd_socket_ctrl; - -//============================================================================= -// Private Function Definition -//============================================================================= -static void primary_process_epoll_port_fd_ctrl_connection_socket(epoll_port_private_data_t *private_data); -static void primary_process_epoll_port_fd_ctrl_data_socket(epoll_port_private_data_t *private_data); -static void primary_process_epoll_port_fd_ep_connection_socket(epoll_port_private_data_t *private_data); -static void primary_process_epoll_port_fd_ep_data_socket(epoll_port_private_data_t *private_data); - -static void primary_handle_client_disconnected(uint8_t endpoint_number); -static void primary_handle_client_closed_ep_connection(int fd_data_socket, uint8_t endpoint_number); -static bool primary_handle_client_closed_ep_notify_close(int fd_data_socket, uint8_t endpoint_number); -static void primary_handle_client_closed_ctrl_connection(int fd_data_socket); -static void primary_ep_push_close_socket_pair(int fd_data_socket, int fd_ctrl_data_socket, uint8_t endpoint_number); -static bool primary_ep_find_close_socket_pair(int fd_data_socket, int fd_ctrl_data_socket, uint8_t endpoint_number); -static int primary_pull_data_from_data_socket(int fd_data_socket, uint8_t **buffer_ptr, size_t *buffer_len_ptr); - -//============================================================================= -// Global Function Definition -//============================================================================= -void primary_init(void) -{ - int ret, nchars; - struct sockaddr_un name; - size_t size, i; - static epoll_port_private_data_t private_data; - - fd_socket_ctrl = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - ERROR_SYSCALL_ON(fd_socket_ctrl < 0); - - memset(&name, 0, sizeof(name)); - name.sun_family = AF_UNIX; - - size = (sizeof(name.sun_path) - 1); - nchars = snprintf(name.sun_path, size, "%s/cpcd/%s/ctrl.cpcd.sock", config.socket_folder, config.instance_name); - ERROR_ON(nchars < 0 || (size_t)nchars >= size); - - ret = bind(fd_socket_ctrl, (const struct sockaddr *)&name, sizeof(name)); - ERROR_SYSCALL_ON(ret < 0); - - ret = listen(fd_socket_ctrl, 5); - ERROR_SYSCALL_ON(ret < 0); - - slist_init(&ctrl_connections); - - slist_init(&pending_connections); - - for (i = 1; i != PRIMARY_EP_MAX_COUNTS; i++) - { - ep_ctx[i].open_data_connections = 0; - ep_ctx[i].open_event_connections = 0; - ep_ctx[i].pending_close = 0; - ep_ctx[i].connection_socket_epoll_port_private_data.endpoint_number = (uint8_t)i; - ep_ctx[i].connection_socket_epoll_port_private_data.file_descriptor = -1; - ep_ctx[i].event_connection_socket_epoll_port_private_data.file_descriptor = -1; - slist_init(&ep_ctx[i].data_socket_epoll_port_data); - slist_init(&ep_ctx[i].event_data_socket_epoll_port_data); - slist_init(&ep_ctx[i].data_ctrl_data_socket_pair); - } - - private_data.callback = primary_process_epoll_port_fd_ctrl_connection_socket; - private_data.file_descriptor = fd_socket_ctrl; - private_data.endpoint_number = 0; - epoll_port_register(&private_data); -} - -static void primary_process_epoll_port_fd_ctrl_connection_socket(epoll_port_private_data_t *private_data) -{ - (void)private_data; - int new_data_socket; - int flags; - int ret; - - new_data_socket = accept(fd_socket_ctrl, NULL, NULL); - ERROR_SYSCALL_ON(new_data_socket < 0); - - flags = fcntl(new_data_socket, F_GETFL, NULL); - ERROR_SYSCALL_ON(flags < 0); - ret = fcntl(new_data_socket, F_SETFL, flags | O_NONBLOCK); - ERROR_SYSCALL_ON(ret < 0); - - { - ctrl_socket_data_list_t *new_item; - - /* Allocate resources for this new connection */ - new_item = calloc_port(sizeof *new_item); - new_item->pid = -1; - - /* Register this new data socket to epoll set */ - { - epoll_port_private_data_t *private_data = &new_item->data_socket_epoll_port_data; - - private_data->callback = primary_process_epoll_port_fd_ctrl_data_socket; - private_data->endpoint_number = 0; /* Irrelevent information in the case of ctrl data sockets */ - private_data->file_descriptor = new_data_socket; - - epoll_port_register(private_data); - } - - /* Finally, add this new socket item to the list */ - slist_push(&ctrl_connections, &new_item->node); - } -} - -static void primary_process_epoll_port_fd_ctrl_data_socket(epoll_port_private_data_t *private_data) -{ - int fd_ctrl_data_socket = private_data->file_descriptor; - uint8_t *buffer; - size_t buffer_len; - cpc_croe_exange_buffer_t *interface_buffer; - int ret; - - /* Check if the event is about the client closing the connection */ - { - int length; - - ret = ioctl(fd_ctrl_data_socket, FIONREAD, &length); - ERROR_SYSCALL_ON(ret < 0); - - if (length == 0) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - return; - } - } - - /* Retrieve the payload from the endpoint data connection */ - ret = primary_pull_data_from_data_socket(fd_ctrl_data_socket, &buffer, &buffer_len); - ERROR_ON(ret != 0); - - ERROR_ON(buffer_len < sizeof(cpc_croe_exange_buffer_t)); - interface_buffer = (cpc_croe_exange_buffer_t *)buffer; - - switch (interface_buffer->type) - { - case EXCHANGE_EP_STATUS_QUERY: - /* Client requested an endpoint status */ - { - cpc_ep_state_t ep_state; - TRACE_PRIMARY("Received an endpoint status query"); - - ASSERT_ON(buffer_len != sizeof(cpc_croe_exange_buffer_t) + sizeof(cpc_ep_state_t)); - - ep_state = cpcd_get_endpoint_state(interface_buffer->endpoint_number); - - memcpy(interface_buffer->payload, &ep_state, sizeof(cpc_ep_state_t)); - - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != sizeof(cpc_croe_exange_buffer_t) + sizeof(cpc_ep_state_t)); - } - } - break; - - case EXCHANGE_MAX_WRITE_SIZE_QUERY: - /* Client requested maximum write size */ - { - TRACE_PRIMARY("Received an maximum write size query"); - - ASSERT_ON(buffer_len != sizeof(cpc_croe_exange_buffer_t) + sizeof(uint32_t)); - size_t rx_capability = (size_t)primary_cpcd_get_secondary_rx_capability(); - memcpy(interface_buffer->payload, &rx_capability, sizeof(uint32_t)); - - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != sizeof(cpc_croe_exange_buffer_t) + sizeof(uint32_t)); - } - } - break; - - case EXCHANGE_VERSION_QUERY: - /* Client requested the version of the daemon*/ - { - char *version = (char *)interface_buffer->payload; - bool do_close_client = false; - - ERROR_ON(interface_buffer->payload == NULL); - - TRACE_PRIMARY("Received a version query"); - - if (buffer_len != sizeof(cpc_croe_exange_buffer_t) + sizeof(char) * PROJECT_MAX_VERSION_SIZE) - { - WARN("Client used invalid version buffer_len = %zu", buffer_len); - break; - } - - if (strnlen(version, PROJECT_MAX_VERSION_SIZE) == PROJECT_MAX_VERSION_SIZE) - { - do_close_client = true; - WARN("Client used invalid library version, version string is invalid"); - } else if (strcmp(version, PROJECT_VER) != 0) - { - do_close_client = true; - WARN("Client used invalid library version, (v%s) expected (v%s)", version, PROJECT_VER); - } else - { - PRINT_INFO("New client connection using library v%s", version); - } - - //Reuse the receive buffer to send back the response - strncpy(version, PROJECT_VER, PROJECT_MAX_VERSION_SIZE); - - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - - if ((ret < 0 && errno == EPIPE) || do_close_client) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != sizeof(cpc_croe_exange_buffer_t) + sizeof(char) * PROJECT_MAX_VERSION_SIZE); - } - } - break; - - - case EXCHANGE_OPEN_EP_QUERY: - /* Client requested to open an endpoint socket*/ - { - TRACE_PRIMARY("Received an endpoint open query"); - - ASSERT_ON(buffer_len != sizeof(cpc_croe_exange_buffer_t) + sizeof(bool)); - - /* Add this connection to the pending connections list, we need to check the secondary if the endpoint is open */ - /* This will be done in the primary_process_pending_connections function */ - pd_ce_list_t *pending_connection = calloc_port(sizeof(pd_ce_list_t)); - ERROR_ON(pending_connection == NULL); - - pending_connection->endpoint_id = interface_buffer->endpoint_number; - pending_connection->fd_ctrl_data_socket = fd_ctrl_data_socket; - slist_push_back(&pending_connections, &pending_connection->node); - } - break; - - case EXCHANGE_CLOSE_EP_QUERY: - { - TRACE_PRIMARY("Received a endpoint close query"); - /* Endpoint was closed by secondary */ - if (ep_ctx[interface_buffer->endpoint_number].pending_close > 0) - { - ep_ctx[interface_buffer->endpoint_number].pending_close--; - if (ep_ctx[interface_buffer->endpoint_number].pending_close == 0) - { - cpcd_close_endpoint(interface_buffer->endpoint_number, true, false); - } - - // Ack the close query - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - // And notify the caller - ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - } - } - } else - { - /* Endpoint was already closed by a client (same ctrl data socket, multiple instances of the same endpoint) */ - if (cpcd_get_endpoint_state(interface_buffer->endpoint_number) == CPC_EP_STATE_CLOSED) - { - // Ack the close query - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - // And notify the caller - ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - } - } - } else - { - /* Endpoint is about to be closed by a client */ - int fd_data_socket = *(int *)interface_buffer->payload; - bool fd_data_socket_closed = primary_ep_find_close_socket_pair(fd_data_socket, -1, interface_buffer->endpoint_number); - - if (fd_data_socket_closed) - { - // Socket already closed, ack the close query - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - // And notify now - ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - } - } - } else - { - primary_ep_push_close_socket_pair(fd_data_socket, fd_ctrl_data_socket, interface_buffer->endpoint_number); - - // Ack the close query - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != (sizeof(cpc_croe_exange_buffer_t) + sizeof(int))); - } - } - } - } - } - break; - - case EXCHANGE_SET_PID_QUERY: - { - bool can_connect = true; - ctrl_socket_data_list_t *item; - - // Set the control socket PID - item = container_of(private_data, ctrl_socket_data_list_t, data_socket_epoll_port_data); - item->pid = *(pid_t *)interface_buffer->payload; - - memcpy(interface_buffer->payload, &can_connect, sizeof(bool)); - - ASSERT_ON(buffer_len < sizeof(bool)); - ssize_t ret = send(fd_ctrl_data_socket, interface_buffer, buffer_len, 0); - - if (ret < 0 && errno == EPIPE) - { - primary_handle_client_closed_ctrl_connection(fd_ctrl_data_socket); - } else - { - ERROR_SYSCALL_ON(ret < 0 && errno != EPIPE); - ERROR_ON((size_t)ret != sizeof(cpc_croe_exange_buffer_t) + sizeof(pid_t)); - } - } - break; - default: - break; - } - - free(buffer); -} - -void primary_process_pending_connections(void) -{ - pd_ce_list_t *pending_connection; - pending_connection = SLIST_ENTRY(pending_connections, pd_ce_list_t, node); - - if (pending_connection != NULL) - { - if (cpcd_ep_is_closing(pending_connection->endpoint_id)) - { - TRACE_PRIMARY("Endpoint #%d is currently closing, waiting before opening", pending_connection->endpoint_id); - return; - } - - if (sys_open_ep_step == SYSTEM_OPEN_STEP_IDLE) - { - sys_open_ep_step = SYSTEM_OPEN_STEP_STATE_WAITING; - sys_set_pending_connection(pending_connection->fd_ctrl_data_socket); - sys_cmd_property_get(sys_get_ep_state_pending_cb, - (property_id_t)(PROP_EP_STATE_0 + pending_connection->endpoint_id), - 5, - 100000, - false); - } else if (sys_open_ep_step == SYSTEM_OPEN_STEP_STATE_FETCHED) - { - } else if (sys_open_ep_step == SYSTEM_OPEN_STEP_DONE) - { - sys_open_ep_step = SYSTEM_OPEN_STEP_IDLE; - - sys_set_pending_connection(0); - slist_remove(&pending_connections, &pending_connection->node); - free(pending_connection); - } - } -} -static void primary_process_epoll_port_fd_ep_connection_socket(epoll_port_private_data_t *private_data) -{ - int new_data_socket, flags; - int fd_connection_socket = private_data->file_descriptor; - uint8_t endpoint_number = private_data->endpoint_number; - - /* Sanity checks */ - { - /* We don't deal with system endpoint here*/ - ASSERT_ON(endpoint_number == 0); - - /* Make sure the connection socket exists */ - ASSERT_ON(ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor == -1); - } - - /* Accept the new connection for that endpoint */ - new_data_socket = accept(fd_connection_socket, NULL, NULL); - ERROR_SYSCALL_ON(new_data_socket < 0); - - /* Set socket as non-blocking */ - flags = fcntl(new_data_socket, F_GETFL, NULL); - - if (flags < 0) - { - ERROR("fcntl F_GETFL failed.%s", strerror(errno)); - } - - flags |= O_NONBLOCK; - - if (fcntl(new_data_socket, F_SETFL, flags) < 0) - { - ERROR("fcntl F_SETFL failed.%s", strerror(errno)); - } - - /* Add the new data socket in the list of data sockets for that endpoint */ - { - data_socket_data_list_t *new_item; - - /* Allocate resources for this new connection */ - { - new_item = (data_socket_data_list_t *)calloc_port(sizeof(data_socket_data_list_t)); - ERROR_ON(new_item == NULL); - - slist_push(&ep_ctx[endpoint_number].data_socket_epoll_port_data, &new_item->node); - } - - /* Register this new connection's socket to epoll set */ - { - epoll_port_private_data_t *private_data = &new_item->data_socket_epoll_port_data; - - private_data->callback = primary_process_epoll_port_fd_ep_data_socket; - private_data->endpoint_number = endpoint_number; - private_data->file_descriptor = new_data_socket; - - epoll_port_register(private_data); - } - } - - ep_ctx[endpoint_number].open_data_connections++; - PRINT_INFO("Endpoint socket #%d: Client connected. %d connections", endpoint_number, ep_ctx[endpoint_number].open_data_connections); - - /* Tell the cpcd that this endpoint is open */ - cpcd_process_endpoint_change(endpoint_number, CPC_EP_STATE_OPEN); - TRACE_PRIMARY("Told cpcd to open ep#%u", endpoint_number); - - /* Acknowledge the user so that they can start using the endpoint */ - { - cpc_croe_exange_buffer_t *buffer; - size_t buffer_len = sizeof(cpc_croe_exange_buffer_t) + sizeof(int); - - buffer = calloc_port(buffer_len); - ERROR_SYSCALL_ON(buffer == NULL); - buffer->endpoint_number = endpoint_number; - buffer->type = EXCHANGE_OPEN_EP_QUERY; - *((int *)buffer->payload) = new_data_socket; - ERROR_SYSCALL_ON(send(new_data_socket, buffer, buffer_len, 0) != (ssize_t)buffer_len); - free(buffer); - } -} - -static void primary_process_epoll_port_fd_ep_data_socket(epoll_port_private_data_t *private_data) -{ - uint8_t *buffer; - size_t buffer_len; - int fd_data_socket = private_data->file_descriptor; - uint8_t endpoint_number = private_data->endpoint_number; - int ret; - - if (cpcd_ep_is_busy(endpoint_number)) - { - epoll_port_unwatch(private_data); - return; - } - - /* Check if the event is about the client closing the connection */ - { - int length; - - ret = ioctl(fd_data_socket, FIONREAD, &length); - ERROR_SYSCALL_ON(ret < 0); - - if (length == 0) - { - primary_handle_client_closed_ep_connection(fd_data_socket, endpoint_number); - return; - } - } - ret = primary_pull_data_from_data_socket(fd_data_socket, &buffer, &buffer_len); - if (ret != 0) - { - primary_handle_client_closed_ep_connection(fd_data_socket, endpoint_number); - return; - } - if (cpcd_get_endpoint_state(endpoint_number) == CPC_EP_STATE_OPEN) - { - cpcd_write(endpoint_number, buffer, buffer_len, 0); - free(buffer); - } else - { - free(buffer); - WARN("User tried to push on endpoint %d but it's not open, state is %d", endpoint_number, cpcd_get_endpoint_state(endpoint_number)); - primary_close_endpoint(endpoint_number, false); - } -} - -static void primary_handle_client_disconnected(uint8_t endpoint_number) -{ - ERROR_ON(ep_ctx[endpoint_number].open_data_connections == 0); - - ep_ctx[endpoint_number].open_data_connections--; - PRINT_INFO("Endpoint socket #%d: Client disconnected. %d connections", endpoint_number, ep_ctx[endpoint_number].open_data_connections); - - if (ep_ctx[endpoint_number].open_data_connections == 0) - { - TRACE_PRIMARY("Closing endpoint socket, no more listeners"); - primary_close_endpoint(endpoint_number, false); - - if (ep_ctx[endpoint_number].pending_close == 0) - { - TRACE_PRIMARY("No pending close on the endpoint, closing it"); - cpcd_close_endpoint(endpoint_number, true, false); - } - } -} - -static void primary_handle_client_closed_ep_connection(int fd_data_socket, uint8_t endpoint_number) -{ - data_socket_data_list_t *item; - data_socket_data_list_t *next_item; - - item = SLIST_ENTRY(ep_ctx[endpoint_number].data_socket_epoll_port_data, - data_socket_data_list_t, - node); - - if (item == NULL) - { - ERROR("data connection not found in the linked list of the endpoint"); - } - - while (1) - { - next_item = SLIST_ENTRY((item)->node.node, - data_socket_data_list_t, - node); - if (item->data_socket_epoll_port_data.file_descriptor == fd_data_socket) - { - epoll_port_unregister(&item->data_socket_epoll_port_data); - slist_remove(&ep_ctx[endpoint_number].data_socket_epoll_port_data, &item->node); - primary_handle_client_closed_ep_notify_close(item->data_socket_epoll_port_data.file_descriptor, endpoint_number); - - int ret = shutdown(fd_data_socket, SHUT_RDWR); - ERROR_SYSCALL_ON(ret < 0); - - ret = close(fd_data_socket); - ERROR_SYSCALL_ON(ret < 0); - - primary_handle_client_disconnected(endpoint_number); - - free(item); - } - item = next_item; - if (item == NULL) - { - break; - } - } -} - -static void primary_ep_push_close_socket_pair(int fd_data_socket, int fd_ctrl_data_socket, uint8_t endpoint_number) -{ - data_ctrl_data_socket_pair_close_list_item_t *item; - item = calloc_port(sizeof(data_ctrl_data_socket_pair_close_list_item_t)); - ERROR_SYSCALL_ON(item == NULL); - item->fd_data_socket = fd_data_socket; - item->fd_ctrl_data_socket = fd_ctrl_data_socket; - slist_push(&ep_ctx[endpoint_number].data_ctrl_data_socket_pair, &item->node); -} - -static bool primary_ep_find_close_socket_pair(int fd_data_socket, int fd_ctrl_data_socket, uint8_t endpoint_number) -{ - data_ctrl_data_socket_pair_close_list_item_t *item; - data_ctrl_data_socket_pair_close_list_item_t *next_item; - bool found = false; - - item = SLIST_ENTRY(ep_ctx[endpoint_number].data_ctrl_data_socket_pair, - data_ctrl_data_socket_pair_close_list_item_t, - node); - - while (item) - { - next_item = SLIST_ENTRY((item)->node.node, - data_ctrl_data_socket_pair_close_list_item_t, - node); - - if (item->fd_data_socket == fd_data_socket && item->fd_ctrl_data_socket == fd_ctrl_data_socket) - { - slist_remove(&ep_ctx[endpoint_number].data_ctrl_data_socket_pair, &item->node); - free(item); - found = true; - break; - } - - item = next_item; - } - - return found; -} - -static bool primary_handle_client_closed_ep_notify_close(int fd_data_socket, uint8_t endpoint_number) -{ - data_ctrl_data_socket_pair_close_list_item_t *item; - data_ctrl_data_socket_pair_close_list_item_t *next_item; - bool notified = false; - - item = SLIST_ENTRY(ep_ctx[endpoint_number].data_ctrl_data_socket_pair, - data_ctrl_data_socket_pair_close_list_item_t, - node); - - while (item) - { - next_item = SLIST_ENTRY((item)->node.node, - data_ctrl_data_socket_pair_close_list_item_t, - node); - - if (item->fd_data_socket == fd_data_socket && item->fd_ctrl_data_socket > 0) - { - slist_remove(&ep_ctx[endpoint_number].data_ctrl_data_socket_pair, &item->node); - - if (!notified) - { - ssize_t ret; - uint8_t query_close_buffer[sizeof(cpc_croe_exange_buffer_t) + sizeof(int)]; - const size_t query_close_len = sizeof(cpc_croe_exange_buffer_t) + sizeof(int); - cpc_croe_exange_buffer_t *query_close = (cpc_croe_exange_buffer_t *)query_close_buffer; - - query_close->endpoint_number = endpoint_number; - query_close->type = EXCHANGE_CLOSE_EP_QUERY; - *((int *)query_close->payload) = fd_data_socket; - - ret = send(item->fd_ctrl_data_socket, query_close, query_close_len, 0); - if (ret == (ssize_t)query_close_len) - { - notified = true; - } else - { - if (errno != EPIPE) - { - WARN("ep notify send() failed, errno = %d", errno); - } - } - } - - free(item); - } - - item = next_item; - } - - return notified; -} - -static void primary_handle_client_closed_ctrl_connection(int fd_data_socket) -{ - ctrl_socket_data_list_t *item; - ctrl_socket_data_list_t *next_item; - - item = SLIST_ENTRY(ctrl_connections, - ctrl_socket_data_list_t, - node); - - if (item == NULL) - { - ERROR("ctrl data connection not found in the linked list of the ctrl socket"); - } - - while (1) - { - /* Get the next item */ - next_item = SLIST_ENTRY((item)->node.node, - ctrl_socket_data_list_t, - node); - - if (item->data_socket_epoll_port_data.file_descriptor == fd_data_socket) - { - epoll_port_unregister(&item->data_socket_epoll_port_data); - - slist_remove(&ctrl_connections, &item->node); - int ret = shutdown(fd_data_socket, SHUT_RDWR); - ERROR_SYSCALL_ON(ret < 0); - - ret = close(fd_data_socket); - ERROR_SYSCALL_ON(ret < 0); - - PRINT_INFO("Client disconnected"); - free(item); - } - - item = next_item; - if (item == NULL) - { - break; - } - } -} - - -void primary_set_endpoint_encryption(uint8_t endpoint_id, bool encryption_enabled) -{ - (void)endpoint_id; - (void)encryption_enabled; -} - -void primary_open_endpoint(uint8_t endpoint_number) -{ - struct sockaddr_un name; - int fd_connection_sock; - int ret; - - { - if (ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor != -1) - { - return; - } - ASSERT_ON(endpoint_number == 0); - - ASSERT_ON(ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor != -1); - - ASSERT_ON(ep_ctx[endpoint_number].data_socket_epoll_port_data != NULL); - } - - { - /* Create the connection socket.*/ - fd_connection_sock = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - ERROR_SYSCALL_ON(fd_connection_sock < 0); - - { - memset(&name, 0, sizeof(name)); - - name.sun_family = AF_UNIX; - - { - int nchars; - const size_t size = sizeof(name.sun_path) - 1; - - nchars = snprintf(name.sun_path, size, "%s/cpcd/%s/ep%d.cpcd.sock", config.socket_folder, config.instance_name, endpoint_number); - - ERROR_ON(nchars < 0 || (size_t)nchars >= size); - } - - ret = bind(fd_connection_sock, (const struct sockaddr *)&name, sizeof(name)); - ERROR_SYSCALL_ON(ret < 0); - } - ret = listen(fd_connection_sock, 5); - ERROR_SYSCALL_ON(ret < 0); - } - - { - epoll_port_private_data_t *private_data = &ep_ctx[endpoint_number].connection_socket_epoll_port_private_data; - - private_data->callback = primary_process_epoll_port_fd_ep_connection_socket; - private_data->endpoint_number = endpoint_number; - private_data->file_descriptor = fd_connection_sock; - - epoll_port_register(private_data); - } - - PRINT_INFO("Opened connection socket for ep#%u", endpoint_number); -} - -bool primary_is_endpoint_open(uint8_t endpoint_number) -{ - return ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor == -1 ? false : true; -} - - -void primary_close_endpoint(uint8_t endpoint_number, bool error) -{ - size_t data_sock_i = 0; - int ret; - - /* Sanity check */ - { - ASSERT_ON(endpoint_number == 0); - - if (ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor == -1) - { - return; - } - } - - while (ep_ctx[endpoint_number].data_socket_epoll_port_data != NULL) - { - data_socket_data_list_t *item; - data_sock_i++; - slist_node_t *node = slist_pop(&ep_ctx[endpoint_number].data_socket_epoll_port_data); - - item = SLIST_ENTRY(node, data_socket_data_list_t, node); - - epoll_port_unregister(&item->data_socket_epoll_port_data); - - primary_handle_client_closed_ep_notify_close(item->data_socket_epoll_port_data.file_descriptor, endpoint_number); - - ret = shutdown(item->data_socket_epoll_port_data.file_descriptor, SHUT_RDWR); - ERROR_SYSCALL_ON(ret < 0); - - ret = close(item->data_socket_epoll_port_data.file_descriptor); - ERROR_SYSCALL_ON(ret < 0); - - free(item); - TRACE_PRIMARY("Closed data socket #%u on ep#%u", data_sock_i, endpoint_number); - } - - { - int fd_connection_socket = ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor; - - if (fd_connection_socket > 0) - { - epoll_port_unregister(&ep_ctx[endpoint_number].connection_socket_epoll_port_private_data); - - ret = shutdown(fd_connection_socket, SHUT_RDWR); - ERROR_SYSCALL_ON(ret < 0); - ret = close(fd_connection_socket); - ERROR_SYSCALL_ON(ret < 0); - } - - { - char endpoint_path[SIZEOF_MEMBER(struct sockaddr_un, sun_path)]; - - { - int nchars; - const size_t size = sizeof(endpoint_path); - - nchars = snprintf(endpoint_path, size, "%s/cpcd/%s/ep%d.cpcd.sock", config.socket_folder, config.instance_name, endpoint_number); - - ERROR_ON(nchars < 0 || (size_t)nchars >= size); - } - - ret = unlink(endpoint_path); - ERROR_SYSCALL_ON(ret < 0 && errno != ENOENT); - } - ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor = -1; - - if (error) - { - ep_ctx[endpoint_number].pending_close = ep_ctx[endpoint_number].open_data_connections; - } - ep_ctx[endpoint_number].open_data_connections = 0; - } -} - -status_t primary_push_data_to_endpoint(uint8_t endpoint_number, const uint8_t *data, size_t data_len) -{ - data_socket_data_list_t *item; - int nb_clients = 0; - - { - ASSERT_ON(ep_ctx[endpoint_number].connection_socket_epoll_port_private_data.file_descriptor == -1); - - WARN_ON(ep_ctx[endpoint_number].data_socket_epoll_port_data == NULL); - } - - item = SLIST_ENTRY(ep_ctx[endpoint_number].data_socket_epoll_port_data, - data_socket_data_list_t, - node); - - while (item != NULL) - { - ssize_t wc = send(item->data_socket_epoll_port_data.file_descriptor, - data, - data_len, - MSG_DONTWAIT); - if (wc < 0) - { - TRACE_PRIMARY("send() failed with %s", ERRNO_CODENAME[errno]); - } - - nb_clients++; - - if (wc < 0 && (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EWOULDBLOCK)) - { - WARN("Unresponsive data socket on ep#%d, closing", endpoint_number); - - if (ep_ctx[endpoint_number].open_data_connections == 1 && nb_clients == 1) - { - if (errno == EAGAIN || errno == EWOULDBLOCK) - { - return STATUS_WOULD_BLOCK; - } - } - - epoll_port_unregister(&item->data_socket_epoll_port_data); - - primary_ep_push_close_socket_pair(item->data_socket_epoll_port_data.file_descriptor, -1, endpoint_number); - - int ret = shutdown(item->data_socket_epoll_port_data.file_descriptor, SHUT_RDWR); - ERROR_SYSCALL_ON(ret < 0); - - ret = close(item->data_socket_epoll_port_data.file_descriptor); - ERROR_SYSCALL_ON(ret < 0); - - slist_remove(&ep_ctx[endpoint_number].data_socket_epoll_port_data, &item->node); - free(item); - - ERROR_ON(ep_ctx[endpoint_number].open_data_connections == 0); - - ep_ctx[endpoint_number].open_data_connections--; - PRINT_INFO("Endpoint socket #%d: Client disconnected. %d connections", endpoint_number, ep_ctx[endpoint_number].open_data_connections); - - if (ep_ctx[endpoint_number].open_data_connections == 0) - { - TRACE_PRIMARY("Endpoint was unresponsive, closing endpoint socket, no more listeners"); - primary_close_endpoint(endpoint_number, false); - return STATUS_FAIL; - } - - item = SLIST_ENTRY(ep_ctx[endpoint_number].data_socket_epoll_port_data, - data_socket_data_list_t, - node); - } else - { - ERROR_SYSCALL_ON(wc < 0); - ERROR_ON((size_t)wc != data_len); - - item = SLIST_ENTRY((item)->node.node, - data_socket_data_list_t, - node); - } - } - - return STATUS_OK; -} - -static int primary_pull_data_from_data_socket(int fd_data_socket, uint8_t **buffer_ptr, size_t *buffer_len_ptr) -{ - int datagram_length; - uint8_t *buffer; - ssize_t rc; - int ret; - - { - ret = ioctl(fd_data_socket, FIONREAD, &datagram_length); - - ERROR_SYSCALL_ON(ret < 0); - ASSERT_ON(datagram_length == 0); - } - - { - buffer = (uint8_t *)calloc_port((size_t)PAD_TO_8_BYTES(datagram_length)); - ERROR_ON(buffer == NULL); - } - - { - rc = recv(fd_data_socket, buffer, (size_t)datagram_length, 0); - if (rc < 0) - { - TRACE_PRIMARY("recv() failed with %s", ERRNO_CODENAME[errno]); - } - - if (rc == 0 || (rc < 0 && errno == ECONNRESET)) - { - TRACE_PRIMARY("Client is closed"); - free(buffer); - return -1; - } - ERROR_SYSCALL_ON(rc < 0); - } - - *buffer_ptr = buffer; - *buffer_len_ptr = (size_t)rc; - return 0; -} - -bool primary_listener_list_empty(uint8_t endpoint_number) -{ - return ep_ctx[endpoint_number].open_data_connections == 0; -} - -void primary_notify_connected_libs_of_secondary_reset(void) -{ - ctrl_socket_data_list_t *item; - - SLIST_FOR_EACH_ENTRY(ctrl_connections, - item, - ctrl_socket_data_list_t, - node) - { - if (item->pid != getpid()) - { - if (item->pid > 1) - { - kill(item->pid, SIGUSR1); - } else - { - ASSERT("Connected library's pid it not set"); - } - } - } -} - -static void primary_send_event(int socket_fd, cpc_evt_type_t event_type, uint8_t ep_id, uint8_t *payload, uint32_t payload_length) -{ - cpc_cpcd_event_buffer_t *event = calloc_port(sizeof(cpc_cpcd_event_buffer_t) + payload_length); - ERROR_SYSCALL_ON(event == NULL); - - event->type = event_type; - event->endpoint_number = ep_id; - event->payload_length = payload_length; - - if (payload != NULL && payload_length > 0) - { - memcpy(event->payload, payload, payload_length); - } - - ssize_t ret = send(socket_fd, event, sizeof(cpc_cpcd_event_buffer_t) + payload_length, MSG_DONTWAIT); - - if (ret < 0 && (errno == EPIPE || errno == ECONNRESET || errno == ECONNREFUSED)) - { - } else if (ret < 0 && errno == EWOULDBLOCK) - { - WARN("Client event socket is full, closing the socket.."); - ret = shutdown(socket_fd, SHUT_RDWR); - ERROR_SYSCALL_ON(ret < 0); - } else - { - ASSERT_ON(ret < 0 || (size_t)ret != sizeof(cpc_cpcd_event_buffer_t) + payload_length); - } - - free(event); -} - -static cpc_evt_type_t primary_get_event_type_from_state(cpc_ep_state_t state) -{ - switch (state) - { - case CPC_EP_STATE_OPEN: - return CPC_EVT_EP_OPENED; - case CPC_EP_STATE_CLOSED: - return CPC_EVT_EP_CLOSED; - case CPC_EP_STATE_CLOSING: - return CPC_EVT_EP_CLOSING; - case CPC_EP_STATE_ERROR_DEST_UNREACH: - return CPC_EVT_EP_ERROR_DESTINATION_UNREACHABLE; - case CPC_EP_STATE_ERROR_FAULT: - return CPC_EVT_EP_ERROR_FAULT; - default: - ASSERT("A new state (%d) has been added that has no equivalent event type .", state); - } -} - -static void primary_notify_connected_libs_of_endpoint_state_change(uint8_t ep_id, cpc_ep_state_t new_state) -{ - event_socket_data_list_t *item; - - ASSERT_ON(ep_id == CPC_EP_SYSTEM); - - SLIST_FOR_EACH_ENTRY(ep_ctx[ep_id].event_data_socket_epoll_port_data, item, - event_socket_data_list_t, - node) - { - primary_send_event(item->event_socket_epoll_port_private_data.file_descriptor, - primary_get_event_type_from_state((new_state)), - ep_id, - NULL, - 0); - } -} - -void primary_on_endpoint_state_change(uint8_t ep_id, cpc_ep_state_t state) -{ - if (ep_id != CPC_EP_SYSTEM) - { - primary_notify_connected_libs_of_endpoint_state_change(ep_id, state); - } -} diff --git a/module/cpc/cpcd/primary/primary/primary.h b/module/cpc/cpcd/primary/primary/primary.h deleted file mode 100644 index 764d331..0000000 --- a/module/cpc/cpcd/primary/primary/primary.h +++ /dev/null @@ -1,30 +0,0 @@ - - -#ifndef SERVER_H -#define SERVER_H - -#include -#include - -#include "utility/status.h" -#include "primary/cpcd/cpcd.h" - -void primary_init(void); - -void primary_open_endpoint(uint8_t endpoint_number); -void primary_close_endpoint(uint8_t endpoint_number, bool error); -void primary_set_endpoint_encryption(uint8_t endpoint_id, bool encryption_enabled); - -status_t primary_push_data_to_endpoint(uint8_t endpoint_number, const uint8_t *data, size_t data_len); -void primary_process_pending_connections(void); -bool primary_is_endpoint_open(uint8_t endpoint_number); - -bool primary_listener_list_empty(uint8_t endpoint_number); - -void primary_notify_connected_libs_of_secondary_reset(void); -void primary_on_endpoint_state_change(uint8_t ep_id, cpc_ep_state_t state); - -void primary_push_data_to_cpcd(uint8_t endpoint_number, const void *data, size_t data_len); -void primary_tell_cpcd_to_open_endpoint(uint8_t endpoint_number); - -#endif diff --git a/module/cpc/cpcd/primary/primary_cpcd.c b/module/cpc/cpcd/primary/primary_cpcd.c deleted file mode 100644 index a3ab86a..0000000 --- a/module/cpc/cpcd/primary/primary_cpcd.c +++ /dev/null @@ -1,719 +0,0 @@ -/** - * @file primary_cpcd.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-10-30 - * - * - */ -#define _GNU_SOURCE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utility/config.h" -#include "utility/logs.h" -#include "utility/sleep.h" -#include "utility/utils.h" - -#include "primary_cpcd.h" -#include "primary/epoll_port/epoll_port.h" -#include "primary/primary/primary.h" -#include "primary/cpcd/cpcd.h" -#include "primary/system/system.h" - -#include "hal/hal_kill.h" - -#include "version.h" - -//============================================================================= -// Constant Definition -//============================================================================= - -//============================================================================= -// Macro Definition -//============================================================================= - -//============================================================================= -// Structure Definition -//============================================================================= -#define MAX_EPOLL_EVENTS 1 - -//============================================================================= -// Global Data Definition -//============================================================================= -bool ignore_reset_reason = true; -static char *primary_cpcd_secondary_app_version = NULL; -static uint8_t primary_cpcd_secondary_protocol_version; -static bool set_reset_mode_ack = false; -static bool reset_ack = false; -static bool secondary_cpc_version_received = false; -static bool secondary_app_version_received_or_not_available = false; -static bool secondary_bus_speed_received = false; -static bool failed_to_receive_secondary_bus_speed = false; -static bool reset_reason_received = false; -static bool capabilities_received = false; -static bool rx_capability_received = false; -static bool protocol_version_received = false; -static sys_reboot_mode_t pending_mode; -static int kill_eventfd = -1; -static enum -{ - E_SET_REBOOT_MODE, - E_WAIT_REBOOT_MODE_ACK, - E_WAIT_RESET_ACK, - E_WAIT_RESET_REASON, - E_WAIT_CAPABILITIES, - E_WAIT_RX_CAPABILITY, - E_WAIT_BOOTLOADER_INFO, - E_WAIT_SECONDARY_CPC_VERSION, - E_WAIT_SECONDARY_APP_VERSION, - E_WAIT_PROTOCOL_VERSION, - E_WAIT_SECONDARY_BUS_SPEED, - E_RESET_SEQUENCE_DONE -} reset_sequence_state = E_SET_REBOOT_MODE; - -static uint32_t rx_capability = 0; - -static uint32_t capabilities = 0; - - -//============================================================================= -// Private Function Definition -//============================================================================= -static void __primary_unsolicited_cb(sys_status_t status); -static void *__primary_cpcd_loop(void *param); -static void __primary_reset_proc(void); -static void __primary_cpcd_cleanup(epoll_port_private_data_t *private_data); -static void __primary_set_reset_mode_callback(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status); -static void __reset_cb(sys_command_handle_t *handle, - status_t status, - sys_status_t reset_status); - - -static void __primary_remove_socket_folder(const char *folder) -{ - struct dirent *next_file; - char filepath[SIZEOF_MEMBER(struct sockaddr_un, sun_path)] = {}; - DIR *dir = opendir(folder); - ERROR_SYSCALL_ON(dir == NULL); - - while ((next_file = readdir(dir)) != NULL) - { - strcpy(filepath, folder); - strcat(filepath, "/"); - strcat(filepath, next_file->d_name); - if (strstr(filepath, ".cpcd.sock") != NULL) - { - TRACE_PRIMARY("Removing %s", filepath); - ERROR_SYSCALL_ON(remove(filepath) < 0); - } - } - closedir(dir); -} - -static void *__primary_cpcd_loop(void *param) -{ - (void)param; - size_t event_i; - struct epoll_event events[MAX_EPOLL_EVENTS] = {}; - size_t event_count; - - while (1) - { - __primary_reset_proc(); - cpcd_process_transmit_queue(); - - event_count = epoll_port_wait_for_event(events, MAX_EPOLL_EVENTS); - for (event_i = 0; event_i != (size_t)event_count; event_i++) - { - epoll_port_private_data_t *private_data = (epoll_port_private_data_t *)events[event_i].data.ptr; - private_data->callback(private_data); - } - - primary_process_pending_connections(); - } - - return NULL; -} - -static void __primary_set_reset_mode_callback(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - (void)property_id; - (void)property_value; - - switch (status) - { - case STATUS_IN_PROGRESS: - case STATUS_OK: - - if (property_length != sizeof(sys_status_t)) - { - ERROR("Set reset mode reply length error"); - } - - ASSERT_ON(property_length != sizeof(sys_reboot_mode_t)); - - set_reset_mode_ack = true; - break; - - case STATUS_TIMEOUT: - case STATUS_ABORT: - PRINT_INFO("Failed to connect, secondary seems unresponsive"); - ignore_reset_reason = false; - reset_sequence_state = E_SET_REBOOT_MODE; - break; - default: - ASSERT("Unhandled __primary_set_reset_mode_callback status"); - break; - } -} - -static void __reset_cb(sys_command_handle_t *handle, - status_t status, - sys_status_t reset_status) -{ - (void)handle; - - switch (status) - { - case STATUS_IN_PROGRESS: - case STATUS_OK: - - TRACE_RESET("Reset request response received : %d", reset_status); - - if (reset_status == STATUS_OK) - { - reset_ack = true; - } - break; - - case STATUS_TIMEOUT: - case STATUS_ABORT: - WARN("Failed to reset Secondary"); - ignore_reset_reason = false; // Don't ignore a secondary that resets - reset_sequence_state = E_SET_REBOOT_MODE; - break; - default: - ASSERT("Unhandled __reset_cb status"); - break; - } -} - -static void __primary_unsolicited_cb(sys_status_t status) -{ - int ret; - extern char **argv_g; - - if (ignore_reset_reason) - { - ignore_reset_reason = false; - TRACE_RESET("Ignored reset reason : %u", status); - return; - } - - if (status <= SYS_STATUS_RESET_WATCHDOG && status >= SYS_STATUS_RESET_POWER_ON) - { - TRACE_RESET("Received reset reason : %u", status); - TRACE_RESET("Reset sequence: %u", reset_sequence_state); - - if (reset_sequence_state == E_WAIT_RESET_REASON) - { - reset_reason_received = true; - } else - { - PRINT_INFO("Secondary has reset, reset the daemon."); - - /* Stop driver immediately */ - ret = hal_kill_signal_and_join(); - ERROR_ON(ret != 0); - - primary_notify_connected_libs_of_secondary_reset(); - - for (uint8_t i = 1; i < 255; ++i) - { - primary_close_endpoint(i, false); - } - config_restart_cpcd(argv_g); - } - } -} - -static void __primary_get_capabilities_callback(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - - ERROR_ON(property_id != PROP_CAPABILITIES); - ERROR_ON(status != STATUS_OK && status != STATUS_IN_PROGRESS); - ERROR_ON(property_value == NULL || property_length != sizeof(uint32_t)); - - capabilities = *((uint32_t *)property_value); - - if (capabilities & CPC_CAPABILITIES_PACKED_EP_MASK) - { - TRACE_RESET("Received capability : Packed endpoint"); - } - - if (capabilities & CPC_CAPABILITIES_UART_FLOW_CONTROL_MASK) - { - TRACE_RESET("Received capability : UART flow control"); - } - - capabilities_received = true; -} - -static void __primary_get_rx_capability_callback(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - - ERROR_ON(property_id != PROP_RX_CAPABILITY); - ERROR_ON(status != STATUS_OK && status != STATUS_IN_PROGRESS); - ERROR_ON(property_value == NULL || property_length != sizeof(uint16_t)); - - TRACE_RESET("Received RX capability of %u bytes", *((uint16_t *)property_value)); - rx_capability = *((uint16_t *)property_value); - rx_capability_received = true; -} - -static void __primary_get_secondary_cpc_version_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - - uint32_t version[3]; - memcpy(version, property_value, 3 * sizeof(uint32_t)); - - if ((property_id != PROP_SECONDARY_CPC_VERSION) - || (status != STATUS_OK && status != STATUS_IN_PROGRESS) - || (property_value == NULL || property_length != 3 * sizeof(uint32_t))) - { - ERROR("Cannot get Secondary CPC version (obsolete RCP firmware?)"); - } - - PRINT_INFO("Secondary CPC v%d.%d.%d", version[0], version[1], version[2]); - secondary_cpc_version_received = true; -} - -static void __primary_get_secondary_app_version_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - - if ((status == STATUS_OK || status == STATUS_IN_PROGRESS) && property_id == PROP_SECONDARY_APP_VERSION) - { - ERROR_ON(property_value == NULL); - ERROR_ON(property_length == 0); - - const char *version = (const char *)property_value; - - ASSERT_ON(primary_cpcd_secondary_app_version); - - primary_cpcd_secondary_app_version = calloc_port(property_length); - ERROR_SYSCALL_ON(primary_cpcd_secondary_app_version == NULL); - - strncpy(primary_cpcd_secondary_app_version, version, property_length - 1); - primary_cpcd_secondary_app_version[property_length - 1] = '\0'; - PRINT_INFO("Secondary APP v%s", primary_cpcd_secondary_app_version); - } else - { - WARN("Cannot get Secondary APP version (obsolete RCP firmware?)"); - } - - secondary_app_version_received_or_not_available = true; -} - -static void __primary_get_secondary_bus_speed_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - uint32_t bus_speed = 0; - - if ((status == STATUS_OK || status == STATUS_IN_PROGRESS) && property_id == PROP_BUS_SPEED_VALUE) - { - ERROR_ON(property_value == NULL); - ERROR_ON(property_length != sizeof(uint32_t)); - - memcpy(&bus_speed, property_value, sizeof(uint32_t)); - - PRINT_INFO("Secondary bus speed is %d", bus_speed); - - if (config.bus == UART && bus_speed != config.uart_baudrate) - { - ERROR("Baudrate mismatch (%d) on the daemon versus (%d) on the secondary", - config.uart_baudrate, bus_speed); - } - - secondary_bus_speed_received = true; - } else - { - WARN("Could not obtain the secondary's bus speed"); - failed_to_receive_secondary_bus_speed = true; - } -} - -static void __primary_get_protocol_version_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - - uint8_t *version = (uint8_t *)property_value; - - if ((property_id != PROP_PROTOCOL_VERSION) - || (status != STATUS_OK && status != STATUS_IN_PROGRESS) - || (property_value == NULL || property_length != sizeof(uint8_t))) - { - ERROR("Cannot get Secondary Protocol version (obsolete RCP firmware?)"); - } - - primary_cpcd_secondary_protocol_version = *version; - PRINT_INFO("Secondary Protocol v%d", primary_cpcd_secondary_protocol_version); - - protocol_version_received = true; -} - -static void __primary_capabilities_check(void) -{ - if ((config.bus == UART) && (config.uart_hardflow != (bool)(capabilities & CPC_CAPABILITIES_UART_FLOW_CONTROL_MASK))) - { - ERROR("UART flow control configuration mismatch between CPCd (%s) and Secondary (%s)", - config.uart_hardflow ? "enabled" : "disabled", - (bool)(capabilities & CPC_CAPABILITIES_UART_FLOW_CONTROL_MASK) ? "enabled" : "disabled"); - } -} - -static void __primary_protocol_version_check(void) -{ - if (primary_cpcd_secondary_protocol_version != PROTOCOL_VERSION) - { - ERROR("Secondary Protocol v%d doesn't match CPCd Protocol v%d", - primary_cpcd_secondary_protocol_version, PROTOCOL_VERSION); - } -} - -static void __primary_application_version_check(void) -{ - if (config.application_version_validation && primary_cpcd_secondary_app_version) - { - if (strcmp(primary_cpcd_secondary_app_version, - config.application_version_validation) != 0) - { - ERROR("Secondary APP v%s doesn't match the provided APP v%s", - primary_cpcd_secondary_app_version, config.application_version_validation); - } - } -} - -static void __primary_reset_proc(void) -{ - switch (reset_sequence_state) - { - case E_RESET_SEQUENCE_DONE: - return; - - case E_SET_REBOOT_MODE: - PRINT_INFO("Connecting to Secondary..."); - - /* Send a request to the secondary to set the reboot mode to 'application' */ - { - const sys_reboot_mode_t reboot_mode = REBOOT_APPLICATION; - - pending_mode = reboot_mode; - - sys_cmd_property_set(__primary_set_reset_mode_callback, - 1, - 2000000, - PROP_BOOTLOADER_REBOOT_MODE, - &reboot_mode, - sizeof(reboot_mode), - true); - - reset_sequence_state = E_WAIT_REBOOT_MODE_ACK; - - TRACE_RESET("Reboot mode sent"); - } - break; - - case E_WAIT_REBOOT_MODE_ACK: - - if (set_reset_mode_ack == true) - { - /* Now, request a reset */ - sys_cmd_reboot(__reset_cb, 5, 100000); - - reset_sequence_state = E_WAIT_RESET_ACK; - - /* Set it back to false because it will be used for the bootloader reboot sequence */ - set_reset_mode_ack = false; - - TRACE_RESET("Reboot mode reply received, reset request sent"); - } - break; - - case E_WAIT_RESET_ACK: - - if (reset_ack == true) - { - reset_sequence_state = E_WAIT_RESET_REASON; - - /* Set it back to false because it will be used for the bootloader reboot sequence */ - reset_ack = false; - - TRACE_RESET("Reset request acknowledged"); - } - break; - - case E_WAIT_RESET_REASON: - TRACE_RESET("Waiting for reset reason"); - if (reset_reason_received) - { - TRACE_RESET("Reset reason received"); - reset_sequence_state = E_WAIT_RX_CAPABILITY; - sys_cmd_property_get(__primary_get_rx_capability_callback, - PROP_RX_CAPABILITY, - 5, - 100000, - true); - } - break; - - case E_WAIT_RX_CAPABILITY: - if (rx_capability_received) - { - TRACE_RESET("Get RX capability"); - PRINT_INFO("Connected to Secondary"); - reset_sequence_state = E_WAIT_PROTOCOL_VERSION; - sys_cmd_property_get(__primary_get_protocol_version_cb, - PROP_PROTOCOL_VERSION, - 5, - 100000, - true); - } - break; - - case E_WAIT_PROTOCOL_VERSION: - if (protocol_version_received) - { - TRACE_RESET("Get Protocol version"); - - __primary_protocol_version_check(); - reset_sequence_state = E_WAIT_CAPABILITIES; - sys_cmd_property_get(__primary_get_capabilities_callback, - PROP_CAPABILITIES, - 5, - 100000, - true); - } - break; - - case E_WAIT_CAPABILITIES: - if (capabilities_received) - { - TRACE_RESET("Get Capabilites"); - - __primary_capabilities_check(); - - reset_sequence_state = E_WAIT_SECONDARY_BUS_SPEED; - sys_cmd_property_get(__primary_get_secondary_bus_speed_cb, - PROP_BUS_SPEED_VALUE, - 5, - 100000, - true); - } - break; - - - case E_WAIT_SECONDARY_CPC_VERSION: - if (secondary_cpc_version_received) - { - TRACE_RESET("Get Secondary CPC version"); - - reset_sequence_state = E_WAIT_SECONDARY_APP_VERSION; - - sys_cmd_property_get(__primary_get_secondary_app_version_cb, - PROP_SECONDARY_APP_VERSION, - 5, - 100000, - true); - } - break; - - case E_WAIT_SECONDARY_BUS_SPEED: - if (secondary_bus_speed_received || failed_to_receive_secondary_bus_speed) - { - reset_sequence_state = E_WAIT_SECONDARY_CPC_VERSION; - sys_cmd_property_get(__primary_get_secondary_cpc_version_cb, - PROP_SECONDARY_CPC_VERSION, - 5, - 100000, - true); - } - break; - - case E_WAIT_SECONDARY_APP_VERSION: - if (secondary_app_version_received_or_not_available) - { - if (primary_cpcd_secondary_app_version) - { - TRACE_RESET("Get Secondary APP version"); - } - - if (config.print_secondary_versions_and_exit) - { - sleep_s(2); - exit(EXIT_SUCCESS); - } - __primary_application_version_check(); - - reset_sequence_state = E_RESET_SEQUENCE_DONE; - - primary_init(); - PRINT_INFO("Daemon startup was successful. Waiting for client connections"); - } - break; - - default: - ASSERT("Impossible state"); - break; - } -} - -static void __primary_cpcd_cleanup(epoll_port_private_data_t *private_data) -{ - (void)private_data; - - PRINT_INFO("Server cpcd cleanup"); - - sys_cleanup(); - - pthread_exit(0); -} - -bool primary_cpcd_reset_sequence_in_progress(void) -{ - return reset_sequence_state != E_RESET_SEQUENCE_DONE; -} - - -uint32_t primary_cpcd_get_secondary_rx_capability(void) -{ - ERROR_ON(rx_capability == 0); // Need to go through reset sequence first - return rx_capability; -} - -void primary_cpcd_kill_signal(void) -{ - ssize_t ret; - const uint64_t event_value = 1; //doesn't matter what it is - - if (kill_eventfd == -1) - { - return; - } - - ret = write(kill_eventfd, &event_value, sizeof(event_value)); - ERROR_ON(ret != sizeof(event_value)); -} - -pthread_t primary_cpcd_init(int fd_socket_driver_cpcd, int fd_socket_driver_cpcd_notify) -{ - char *socket_folder = NULL; - struct stat sb = { 0 }; - pthread_t primary_cpcd_thread = { 0 }; - int ret = 0; - - cpcd_init(fd_socket_driver_cpcd, fd_socket_driver_cpcd_notify); - - sys_init(); - - sys_register_unsolicited_prop_last_status_callback(__primary_unsolicited_cb); - - /* Create the string {socket_folder}/cpcd/{instance_name} */ - { - const size_t socket_folder_string_size = strlen(config.socket_folder) + strlen("/cpcd/") + strlen(config.instance_name) + sizeof(char); - socket_folder = (char *)calloc_port(socket_folder_string_size); - ERROR_ON(socket_folder == NULL); - - ret = snprintf(socket_folder, socket_folder_string_size, "%s/cpcd/%s", config.socket_folder, config.instance_name); - ERROR_ON(ret < 0 || (size_t)ret >= socket_folder_string_size); - } - - /* Check if the socket folder exists */ - if (stat(socket_folder, &sb) == 0 && S_ISDIR(sb.st_mode)) - { - TRACE_PRIMARY("Remove socket folder %s", socket_folder); - __primary_remove_socket_folder(socket_folder); - } else - { - TRACE_PRIMARY("Remove socket folder %s", socket_folder); - recursive_mkdir(socket_folder, strlen(socket_folder), S_IRWXU | S_IRWXG | S_ISVTX); - ret = access(socket_folder, W_OK); - ERROR_SYSCALL_ON(ret < 0); - } - - free(socket_folder); - - kill_eventfd = eventfd(0, EFD_CLOEXEC); - ERROR_ON(kill_eventfd == -1); - - static epoll_port_private_data_t private_data; - - private_data.callback = __primary_cpcd_cleanup; - private_data.file_descriptor = kill_eventfd; /* Irrelevant here */ - private_data.endpoint_number = 0; /* Irrelevant here */ - - epoll_port_register(&private_data); - - /* create primary_cpcd thread */ - ret = pthread_create(&primary_cpcd_thread, NULL, __primary_cpcd_loop, NULL); - ERROR_ON(ret != 0); - - ret = pthread_setname_np(primary_cpcd_thread, "primary_cpcd"); - ERROR_ON(ret != 0); - - return primary_cpcd_thread; -} - -char *primary_cpcd_get_secondary_app_version(void) -{ - ASSERT_ON(primary_cpcd_secondary_app_version == NULL); - return primary_cpcd_secondary_app_version; -} diff --git a/module/cpc/cpcd/primary/primary_cpcd.h b/module/cpc/cpcd/primary/primary_cpcd.h deleted file mode 100644 index b6df683..0000000 --- a/module/cpc/cpcd/primary/primary_cpcd.h +++ /dev/null @@ -1,24 +0,0 @@ - - -#ifndef PRIMARY_cpcd_H -#define PRIMARY_cpcd_H - -#define _GNU_SOURCE -#include - -#include -#include - -uint32_t primary_cpcd_get_secondary_rx_capability(void); - -pthread_t primary_cpcd_init(int fd_socket_driver_cpcd, int fd_socket_driver_cpcd_notify); - -void primary_cpcd_kill_signal(void); - -void primary_cpcd_notify_security_ready(void); - -bool primary_cpcd_reset_sequence_in_progress(void); - -char *primary_cpcd_get_secondary_app_version(void); - -#endif //PRIMARY_cpcd_H diff --git a/module/cpc/cpcd/primary/system/callbacks.c b/module/cpc/cpcd/primary/system/callbacks.c deleted file mode 100644 index 043a73e..0000000 --- a/module/cpc/cpcd/primary/system/callbacks.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include - -#include "utility/config.h" -#include "primary/system/callbacks.h" -#include "primary/cpcd/cpcd.h" -#include "primary/primary/primary.h" -#include "utility/logs.h" -#include "lib/libcpc.h" -#include "primary/cpcd/cpcd.h" - -static int fd_ctrl_data_of_pending_open = 0; - -sys_open_step_t sys_open_ep_step = SYSTEM_OPEN_STEP_IDLE; - -bool sys_is_waiting_for_status_reply(void) -{ - return fd_ctrl_data_of_pending_open != 0; -} - -void sys_set_pending_connection(int fd) -{ - fd_ctrl_data_of_pending_open = fd; -} - -void sys_closing_ep_async_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - (void)property_length; - (void)property_value; - - uint8_t ep_id = PROPERTY_ID_TO_EP_ID(property_id); - - switch (status) - { - case STATUS_IN_PROGRESS: - case STATUS_OK: - TRACE_PRIMARY("Acknowledged secondary of asynchronously closing ep#%d", ep_id); - break; - - case STATUS_TIMEOUT: - case STATUS_ABORT: - default: - WARN("Secondary did not receive acknowledge of asynchronously closing ep#%d", ep_id); - break; - } -} - -void sys_closing_ep_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - (void)property_length; - (void)property_value; - - uint8_t ep_id = PROPERTY_ID_TO_EP_ID(property_id); - - switch (status) - { - case STATUS_IN_PROGRESS: - case STATUS_OK: - TRACE_PRIMARY("Acknowledged secondary of closing ep#%d", ep_id); - cpcd_set_endpoint_state(ep_id, CPC_EP_STATE_CLOSED); - break; - - case STATUS_TIMEOUT: - case STATUS_ABORT: - default: - WARN("Secondary did not receive acknowledge of closing ep#%d", ep_id); - break; - } -} - -static void sys_send_open_endpoint_ack(uint8_t endpoint_id, bool can_open) -{ - const size_t buffer_len = sizeof(cpc_croe_exange_buffer_t) + sizeof(bool); - cpc_croe_exange_buffer_t *interface_buffer; - uint8_t buffer[buffer_len]; - - interface_buffer = (cpc_croe_exange_buffer_t *)buffer; - - // populate fields related to the query - interface_buffer->type = EXCHANGE_OPEN_EP_QUERY; - interface_buffer->endpoint_number = endpoint_id; - memcpy(interface_buffer->payload, &can_open, sizeof(bool)); - - ssize_t ret = send(fd_ctrl_data_of_pending_open, interface_buffer, buffer_len, 0); - TRACE_PRIMARY("Replied to endpoint open query on ep#%d", endpoint_id); - - if (ret == -1) - { - WARN("Failed to acknowledge the open request for endpoint #%d. %m", endpoint_id); - } else if ((size_t)ret != buffer_len) - { - ASSERT("Failed to acknowledge the open request for endpoint #%d. Sent %d, Expected %d", - endpoint_id, (int)ret, (int)buffer_len); - } - - sys_open_ep_step = SYSTEM_OPEN_STEP_DONE; -} - -static void sys_finalize_open_endpoint(uint8_t endpoint_id, bool encryption, bool can_open) -{ - if (can_open) - { - primary_set_endpoint_encryption(endpoint_id, encryption); - primary_open_endpoint(endpoint_id); - } - - sys_send_open_endpoint_ack(endpoint_id, can_open); -} - -void sys_get_ep_state_pending_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status) -{ - (void)handle; - bool can_open = false; - bool secondary_reachable = false; - uint8_t endpoint_id; - cpc_ep_state_t remote_endpoint_state; - - switch (status) - { - case STATUS_OK: - ASSERT_ON(property_length != sizeof(cpc_ep_state_t)); - TRACE_PRIMARY("Property-get::PROP_EP_STATE Successful callback"); - remote_endpoint_state = cpcd_state_mapper(*(uint8_t *)property_value); - secondary_reachable = true; - break; - case STATUS_IN_PROGRESS: - ASSERT_ON(property_length != sizeof(cpc_ep_state_t)); - TRACE_PRIMARY("Property-get::PROP_EP_STATE Successful callback after retry(ies)"); - remote_endpoint_state = cpcd_state_mapper(*(uint8_t *)property_value); - secondary_reachable = true; - break; - case STATUS_TIMEOUT: - WARN("Property-get::PROP_EP_STATE timed out"); - break; - case STATUS_ABORT: - WARN("Property-get::PROP_EP_STATE aborted"); - break; - default: - ERROR(); - } - - /* Sanity checks */ - { - /* This callback should be called only when we need to reply to a client pending on an open_endpoint call */ - ASSERT_ON(fd_ctrl_data_of_pending_open == 0); - - /* This function's signature is for all properties get/set. Make sure we - * are dealing with PROP_EP_STATE and with the correct property_length*/ - //ASSERT_ON(property_id < PROP_EP_STATE_1 || property_id > PROP_EP_STATE_255); - - if (secondary_reachable) - { - ASSERT_ON(property_length != 1); - } - } - - endpoint_id = PROPERTY_ID_TO_EP_ID(property_id); - - if (secondary_reachable && (remote_endpoint_state == CPC_EP_STATE_OPEN) - && (cpcd_get_endpoint_state(endpoint_id) == CPC_EP_STATE_CLOSED || cpcd_get_endpoint_state(endpoint_id) == CPC_EP_STATE_OPEN)) - { - can_open = true; - - // endpoint is ready to be opened, the encryption status must now be fetched - } - - if (!can_open && secondary_reachable) - { - TRACE_PRIMARY("Cannot open endpoint #%d. Current state on the secondary is: %s. Current state on daemon is: %s", endpoint_id, cpcd_stringify_state(remote_endpoint_state), cpcd_stringify_state(cpcd_get_endpoint_state(endpoint_id))); - } - - if (!secondary_reachable) - { - WARN("Could not read endpoint state on the secondary"); - } - - if (!can_open) - { - // Send "failed to open" ack to control socket - sys_finalize_open_endpoint(endpoint_id, false, can_open); - } else - { - sys_finalize_open_endpoint(endpoint_id, false, can_open); - } -} -void sys_noop_cmd_cb(sys_command_handle_t *handle, - status_t status) -{ - (void)handle; - - switch (status) - { - case STATUS_OK: - TRACE_PRIMARY("NOOP success"); - break; - case STATUS_IN_PROGRESS: - TRACE_PRIMARY("NOOP success with a least one retry"); - break; - case STATUS_TIMEOUT: - WARN("The noop keep alive timed out, link dead"); - TRACE_PRIMARY("NOOP timed out!"); - break; - case STATUS_ABORT: - WARN("The noop keep alive was aborted"); - TRACE_PRIMARY("NOOP failed!"); - break; - default: - ERROR(); - break; - } -} diff --git a/module/cpc/cpcd/primary/system/callbacks.h b/module/cpc/cpcd/primary/system/callbacks.h deleted file mode 100644 index 4a86a82..0000000 --- a/module/cpc/cpcd/primary/system/callbacks.h +++ /dev/null @@ -1,54 +0,0 @@ - - -#ifndef __CALLBACKS_H__ -#define __CALLBACKS_H__ - -#include "primary/system/system.h" - -#include - -typedef enum -{ - SYSTEM_OPEN_STEP_IDLE, - SYSTEM_OPEN_STEP_STATE_WAITING, - SYSTEM_OPEN_STEP_STATE_FETCHED, - SYSTEM_OPEN_STEP_ENCRYPTION_WAITING, - SYSTEM_OPEN_STEP_ENCRYPTION_FETCHED, - SYSTEM_OPEN_STEP_DONE, -} sys_open_step_t; - -extern sys_open_step_t sys_open_ep_step; - -void sys_set_pending_connection(int fd); -bool sys_is_waiting_for_status_reply(void); - -void sys_closing_ep_async_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status); - -void sys_closing_ep_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status); - -void sys_get_ep_state_pending_cb(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status); - -#if defined(ENABLE_ENCRYPTION) -void property_get_single_endpoint_encryption_state_and_reply_to_pending_open_callback(sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status); -#endif - -void sys_noop_cmd_cb(sys_command_handle_t *handle, - status_t status); - -#endif //__CALLBACKS_H__ diff --git a/module/cpc/cpcd/primary/system/system.c b/module/cpc/cpcd/primary/system/system.c deleted file mode 100644 index 935787c..0000000 --- a/module/cpc/cpcd/primary/system/system.c +++ /dev/null @@ -1,962 +0,0 @@ - - -#include -#include -#include -#include - -#include "primary/cpcd/hdlc.h" -#include "libcpc.h" -#include "system.h" - -#include "utility/logs.h" -#include "utility/utils.h" -#include "primary/system/callbacks.h" -#include "primary/primary/primary.h" -#include "primary/cpcd/cpcd.h" -#include "primary/primary_cpcd.h" -#include "utility/utils.h" - - -#define UFRAME_ACK_TIMEOUT_SECONDS 2 -#define SIZEOF_SYSTEM_COMMAND(command) (sizeof(sys_cmd_t) + command->length) -#define EP_CLOSE_RETRIES 5 -#define EP_CLOSE_RETRY_TIMEOUT 100000 - -static slist_node_t *pending_commands; -static slist_node_t *commands; -static slist_node_t *retries; -static slist_node_t *commands_in_error; - -static bool received_remote_sequence_numbers_reset_ack = true; - -extern bool ignore_reset_reason; - -typedef struct -{ - slist_node_t node; - sys_unsolicited_status_callback_t callback; -}last_status_callback_list_t; - -static slist_node_t *prop_last_status_callbacks; - -static void on_iframe_unsolicited(uint8_t endpoint_id, const void *data, size_t data_len); -static void on_uframe_receive(uint8_t endpoint_id, const void *data, size_t data_len); -static void on_reply(uint8_t endpoint_id, void *arg, void *answer, uint32_t answer_lenght); -static void on_timer_expired(epoll_port_private_data_t *private_data); -static void write_command(sys_command_handle_t *command_handle); - -static void sys_cmd_abort(sys_command_handle_t *command_handle, status_t error); - -static void sys_open_endpoint(void) -{ - cpcd_open_endpoint(CPC_EP_SYSTEM, OPEN_EP_FLAG_UFRAME_ENABLE, 1); - - cpcd_set_endpoint_option(CPC_EP_SYSTEM, EP_ON_FINAL, on_reply); - - cpcd_set_endpoint_option(CPC_EP_SYSTEM, EP_ON_UFRAME_RECEIVE, on_uframe_receive); - - cpcd_set_endpoint_option(CPC_EP_SYSTEM, EP_ON_IFRAME_RECEIVE, on_iframe_unsolicited); -} - -static void sys_init_command_handle(sys_command_handle_t *command_handle, - void *on_final, - uint8_t retry_count, - uint32_t retry_timeout_us, - bool is_uframe) -{ - static uint8_t next_command_seq = 0; - - ASSERT_ON(command_handle == NULL); - ASSERT_ON(on_final == NULL); - command_handle->acked = false; - command_handle->error_status = STATUS_OK; - - command_handle->on_final = on_final; - command_handle->retry_count = retry_count; - command_handle->retry_timeout_us = retry_timeout_us; - command_handle->command_seq = next_command_seq++; - command_handle->is_uframe = is_uframe; -} - -static void sys_cmd_abort(sys_command_handle_t *command_handle, status_t error) -{ - // Stop the re_transmit timer - if (command_handle->re_transmit_timer_private_data.file_descriptor != 0) - { - if (command_handle->is_uframe || command_handle->acked == true) - { - epoll_port_unregister(&command_handle->re_transmit_timer_private_data); - } - close(command_handle->re_transmit_timer_private_data.file_descriptor); - command_handle->re_transmit_timer_private_data.file_descriptor = 0; - } - - command_handle->error_status = error; //This will be propagated when calling the callbacks - - switch (command_handle->command->command_id) - { - case CMD_SYSTEM_NOOP: - ((sys_noop_cmd_cb_t)command_handle->on_final)(command_handle, command_handle->error_status); - break; - - case CMD_SYSTEM_RESET: - ((sys_reset_cmd_callback_t)command_handle->on_final)(command_handle, command_handle->error_status, SYS_STATUS_FAILURE); - break; - - case CMD_SYSTEM_PROP_VALUE_GET: - case CMD_SYSTEM_PROP_VALUE_SET: - { - sys_property_cmd_t *tx_property_command = (sys_property_cmd_t *)command_handle->command->payload; - - ((sys_property_get_set_cmd_callback_t)command_handle->on_final)(command_handle, - tx_property_command->property_id, - NULL, - 0, - command_handle->error_status); - } - break; - - case CMD_SYSTEM_PROP_VALUE_IS: //fall through - default: - ASSERT("Invalid command_id"); - break; - } - - // Invalidate the command id, now that it is aborted - command_handle->command->command_id = CMD_SYSTEM_INVALID; -} - -/***************************************************************************//** -* Handle the case where the system command timed out -*******************************************************************************/ -static void sys_cmd_timed_out(const void *frame_data) -{ - sys_command_handle_t *command_handle; - sys_cmd_t *timed_out_command; - - ERROR_ON(frame_data == NULL); - - timed_out_command = (sys_cmd_t *)frame_data; - - /* Go through the list of pending requests to find the one for which this reply applies */ - SLIST_FOR_EACH_ENTRY(commands, command_handle, sys_command_handle_t, node_commands) - { - if (command_handle->command_seq == timed_out_command->command_seq) - { - break; - } - } - - if (command_handle == NULL || command_handle->command_seq != timed_out_command->command_seq) - { - ASSERT("A command timed out but it could not be found in the submitted commands list. SEQ#%d", timed_out_command->command_seq); - } - - // We won't need this command anymore. It needs to be resubmitted. - slist_remove(&commands, &command_handle->node_commands); - - TRACE_SYSTEM("Command ID #%u SEQ #%u timeout", command_handle->command->command_id, command_handle->command->command_seq); - - sys_cmd_abort(command_handle, STATUS_TIMEOUT); - - /* Free the command handle and its buffer */ - - free(command_handle->command); - free(command_handle); -} - -void sys_cmd_poll_acknowledged(const void *frame_data) -{ - int timer_fd, ret; - sys_command_handle_t *command_handle; - ERROR_ON(frame_data == NULL); - sys_cmd_t *acked_command = (sys_cmd_t *)frame_data; - - // Go through the command list to figure out which command just got acknowledged - SLIST_FOR_EACH_ENTRY(commands, command_handle, sys_command_handle_t, node_commands) - { - if (command_handle->command_seq == acked_command->command_seq) - { - TRACE_SYSTEM("Secondary acknowledged command_id #%d command_seq #%d", command_handle->command->command_id, command_handle->command_seq); - const struct itimerspec timeout = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, - .it_value = { .tv_sec = (long int)command_handle->retry_timeout_us / 1000000, .tv_nsec = ((long int)command_handle->retry_timeout_us * 1000) % 1000000000 } }; - - /* Setup timeout timer.*/ - if (command_handle->error_status == STATUS_OK) - { - timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - - ERROR_SYSCALL_ON(timer_fd < 0); - - ret = timerfd_settime(timer_fd, 0, &timeout, NULL); - ERROR_SYSCALL_ON(ret < 0); - - /* Setup the timer in the primary_cpcd epoll set */ - command_handle->re_transmit_timer_private_data.endpoint_number = CPC_EP_SYSTEM; //Irrelevant in this scenario - command_handle->re_transmit_timer_private_data.file_descriptor = timer_fd; - command_handle->re_transmit_timer_private_data.callback = on_timer_expired; - - epoll_port_register(&command_handle->re_transmit_timer_private_data); - } else if (command_handle->error_status == STATUS_IN_PROGRESS) - { - // Simply restart the timer - ret = timerfd_settime(command_handle->re_transmit_timer_private_data.file_descriptor, 0, &timeout, NULL); - ERROR_SYSCALL_ON(ret < 0); - } else - { - WARN("Received ACK on a command that timed out or is processed.. ignoring"); - } - - command_handle->acked = true; - - return; // Found the associated command - } - } - - WARN("Received a system poll ack for which no pending poll is registered"); -} - -void sys_cmd_noop(sys_noop_cmd_cb_t on_noop_reply, - uint8_t retry_count_max, - uint32_t retry_timeout_us) -{ - sys_command_handle_t *command_handle; - - /* Malloc the command handle and the command buffer */ - { - command_handle = calloc_port(sizeof(sys_command_handle_t)); - ERROR_ON(command_handle == NULL); - - command_handle->command = calloc_port(sizeof(sys_cmd_t)); //noop had nothing in the 'payload field' - ERROR_ON(command_handle->command == NULL); - } - - sys_init_command_handle(command_handle, (void *)on_noop_reply, retry_count_max, - retry_timeout_us, false); - - /* Fill the system endpoint command buffer */ - { - sys_cmd_t *tx_command = command_handle->command; - - tx_command->command_id = CMD_SYSTEM_NOOP; - tx_command->command_seq = command_handle->command_seq; - tx_command->length = 0; - } - - write_command(command_handle); - - TRACE_SYSTEM("NOOP (id #%u) sent", CMD_SYSTEM_NOOP); -} - -void sys_cmd_reboot(sys_reset_cmd_callback_t on_reset_reply, - uint8_t retry_count_max, - uint32_t retry_timeout_us) -{ - sys_command_handle_t *command_handle; - - /* Malloc the command handle and the command buffer */ - { - command_handle = calloc_port(sizeof(sys_command_handle_t)); - ERROR_ON(command_handle == NULL); - - command_handle->command = calloc_port(sizeof(sys_cmd_t)); - ERROR_ON(command_handle->command == NULL); - } - - sys_init_command_handle(command_handle, (void *)on_reset_reply, retry_count_max, - retry_timeout_us, true); - - /* Fill the system endpoint command buffer */ - { - sys_cmd_t *tx_command = command_handle->command; - - tx_command->command_id = CMD_SYSTEM_RESET; - tx_command->command_seq = command_handle->command_seq; - tx_command->length = 0; - } - - write_command(command_handle); - - TRACE_SYSTEM("reset (id #%u) sent", CMD_SYSTEM_RESET); -} - -bool sys_received_unnumbered_acknowledgement(void) -{ - return received_remote_sequence_numbers_reset_ack; -} - -void sys_on_unnumbered_acknowledgement(void) -{ - slist_node_t *item; - sys_command_handle_t *command_handle; - - TRACE_SYSTEM("Received sequence numbers reset acknowledgement"); - received_remote_sequence_numbers_reset_ack = true; - - // Send any pending commands - item = slist_pop(&pending_commands); - while (item != NULL) - { - command_handle = SLIST_ENTRY(item, sys_command_handle_t, node_commands); - write_command(command_handle); - item = slist_pop(&pending_commands); - } -} - -static void on_unnumbered_acknowledgement_timeout(epoll_port_private_data_t *private_data) -{ - slist_node_t *item; - int timer_fd = private_data->file_descriptor; - sys_command_handle_t *command_handle = container_of(private_data, - sys_command_handle_t, - re_transmit_timer_private_data); - - if (sys_received_unnumbered_acknowledgement()) - { - // Unnumbered ack was processed, stop the timeout timer - if (command_handle->re_transmit_timer_private_data.file_descriptor != 0) - { - epoll_port_unregister(&command_handle->re_transmit_timer_private_data); - close(command_handle->re_transmit_timer_private_data.file_descriptor); - command_handle->re_transmit_timer_private_data.file_descriptor = 0; - } - return; - } - - TRACE_SYSTEM("Remote is unresponsive, retrying..."); - - /* Ack the timer */ - { - uint64_t expiration; - ssize_t retval; - - retval = read(timer_fd, &expiration, sizeof(expiration)); - - ERROR_SYSCALL_ON(retval < 0); - - ERROR_ON(retval != sizeof(expiration)); - - WARN_ON(expiration != 1); /* we missed a timeout*/ - } - - /* Drop any pending commands to prevent accumulation*/ - item = slist_pop(&pending_commands); - while (item != NULL) - { - command_handle = SLIST_ENTRY(item, sys_command_handle_t, node_commands); - - if (command_handle->command->command_id != CMD_SYSTEM_INVALID) - { - sys_cmd_abort(command_handle, STATUS_ABORT); - } - free(command_handle->command); - free(command_handle); - item = slist_pop(&pending_commands); - } - - cpcd_write(CPC_EP_SYSTEM, NULL, 0, FLAG_UFRAME_RESET_COMMAND); -} - -void sys_request_sequence_reset(void) -{ - int timer_fd, ret; - sys_command_handle_t *command_handle; - - sys_reset_sys_endpoint(); - - TRACE_SYSTEM("Requesting reset of sequence numbers on the remote"); - cpcd_write(CPC_EP_SYSTEM, NULL, 0, FLAG_UFRAME_RESET_COMMAND); - - // Push the command right away - cpcd_process_transmit_queue(); - - // Register a timeout timer in case we don't receive an unnumbered acknowledgement - const struct itimerspec timeout = { .it_interval = { .tv_sec = UFRAME_ACK_TIMEOUT_SECONDS, .tv_nsec = 0 }, - .it_value = { .tv_sec = UFRAME_ACK_TIMEOUT_SECONDS, .tv_nsec = 0 } }; - - timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - - ERROR_SYSCALL_ON(timer_fd < 0); - - ret = timerfd_settime(timer_fd, 0, &timeout, NULL); - ERROR_SYSCALL_ON(ret < 0); - - command_handle = calloc_port(sizeof(sys_command_handle_t)); - ERROR_ON(command_handle == NULL); - - /* Setup the timer in the primary_cpcd epoll set */ - command_handle->re_transmit_timer_private_data.file_descriptor = timer_fd; - command_handle->re_transmit_timer_private_data.callback = on_unnumbered_acknowledgement_timeout; - - epoll_port_register(&command_handle->re_transmit_timer_private_data); - - ret = timerfd_settime(command_handle->re_transmit_timer_private_data.file_descriptor, 0, &timeout, NULL); - ERROR_SYSCALL_ON(ret < 0); - - received_remote_sequence_numbers_reset_ack = false; -} - -void sys_reset_sys_endpoint(void) -{ - slist_node_t *item; - sys_command_handle_t *command_handle; - - // Abort any pending commands - item = slist_pop(&commands); - while (item != NULL) - { - command_handle = SLIST_ENTRY(item, sys_command_handle_t, node_commands); - - if (command_handle->command->command_id != CMD_SYSTEM_INVALID) - { - WARN("Dropping system command id #%d seq#%d", command_handle->command->command_id, command_handle->command_seq); - sys_cmd_abort(command_handle, STATUS_ABORT); - } - - // Command payload will be freed once we close the endpoint - free(command_handle->command); - free(command_handle); - item = slist_pop(&commands); - } - - // Close the system endpoint - cpcd_close_endpoint(CPC_EP_SYSTEM, false, true); - - // Re-open the system endpoint - sys_open_endpoint(); -} -void sys_cmd_property_get(sys_property_get_set_cmd_callback_t on_property_get_reply, - property_id_t property_id, - uint8_t retry_count_max, - uint32_t retry_timeout_us, - bool is_uframe) -{ - sys_command_handle_t *command_handle; - - /* Malloc the command handle and the command buffer */ - { - const size_t property_get_buffer_size = sizeof(sys_cmd_t) + sizeof(property_id_t); - - command_handle = calloc_port(sizeof(sys_command_handle_t)); - ERROR_ON(command_handle == NULL); - command_handle->command = calloc_port(PAD_TO_8_BYTES(property_get_buffer_size)); //property-get has the property id as payload - ERROR_ON(command_handle->command == NULL); - } - - sys_init_command_handle(command_handle, (void *)on_property_get_reply, retry_count_max, - retry_timeout_us, is_uframe); - - /* Fill the system endpoint command buffer */ - { - sys_cmd_t *tx_command = command_handle->command; - sys_property_cmd_t *tx_property_command = (sys_property_cmd_t *)tx_command->payload; - - tx_command->command_id = CMD_SYSTEM_PROP_VALUE_GET; - tx_command->command_seq = command_handle->command_seq; - tx_property_command->property_id = cpu_to_le32(property_id); - tx_command->length = sizeof(property_id_t); - } - - write_command(command_handle); - - TRACE_SYSTEM("property-get (id #%u) sent with property #%u", CMD_SYSTEM_PROP_VALUE_GET, property_id); -} - -/***************************************************************************//** - * Send a property-set query - ******************************************************************************/ -void sys_cmd_property_set(sys_property_get_set_cmd_callback_t on_property_set_reply, - uint8_t retry_count_max, - uint32_t retry_timeout_us, - property_id_t property_id, - const void *value, - size_t value_length, - bool is_uframe) -{ - sys_command_handle_t *command_handle; - - ASSERT_ON(on_property_set_reply == NULL); - - { - const size_t property_get_buffer_size = sizeof(sys_cmd_t) + sizeof(property_id_t) + value_length; - - command_handle = calloc_port(sizeof(sys_command_handle_t)); - ERROR_ON(command_handle == NULL); - command_handle->command = calloc_port(PAD_TO_8_BYTES(property_get_buffer_size)); //property-get has the property id as payload - ERROR_ON(command_handle->command == NULL); - } - - sys_init_command_handle(command_handle, (void *)on_property_set_reply, - retry_count_max, retry_timeout_us, is_uframe); - - /* Fill the system endpoint command buffer */ - { - sys_cmd_t *tx_command = command_handle->command; - sys_property_cmd_t *tx_property_command = (sys_property_cmd_t *)tx_command->payload;; - - tx_command->command_id = CMD_SYSTEM_PROP_VALUE_SET; - tx_command->command_seq = command_handle->command_seq; - tx_property_command->property_id = cpu_to_le32(property_id); - - { - switch (value_length) - { - case 0: - ERROR("Can't send a property-set request with value of length 0"); - break; - - case 1: - memcpy(tx_property_command->payload, value, value_length); - break; - - case 2: - { - uint16_t le16 = cpu_to_le16p((uint16_t *)value); - memcpy(tx_property_command->payload, &le16, 2); - } - break; - - case 4: - { - uint32_t le32 = cpu_to_le32p((uint32_t *)value); - memcpy(tx_property_command->payload, &le32, 4); - } - break; - - case 8: - { - uint64_t le64 = cpu_to_le64p((uint64_t *)value); - memcpy(tx_property_command->payload, &le64, 8); - } - break; - - default: - memcpy(tx_property_command->payload, value, value_length); - break; - } - } - - tx_command->length = (uint8_t)(sizeof(property_id_t) + value_length); - } - - write_command(command_handle); - - TRACE_SYSTEM("property-set (id #%u) sent with property #%u", CMD_SYSTEM_PROP_VALUE_SET, property_id); -} - -static void on_final_noop(sys_command_handle_t *command_handle, - sys_cmd_t *reply) -{ - (void)reply; - - TRACE_SYSTEM("on_final_noop()"); - - ((sys_noop_cmd_cb_t)command_handle->on_final)(command_handle, - command_handle->error_status); -} - -/***************************************************************************//** - * Handle reset from SECONDARY: - * This functions is called when a reset command is received from the SECONDARY. - * The SECONDARY will send back a reset in response to the one sent by the PRIMARY. - ******************************************************************************/ -static void on_final_reset(sys_command_handle_t *command_handle, - sys_cmd_t *reply) -{ - TRACE_SYSTEM("on_final_reset()"); - - ignore_reset_reason = false; - - // Deal with endianness of the returned status since its a 32bit value. - sys_status_t reset_status_le = *((sys_status_t *)(reply->payload)); - sys_status_t reset_status_cpu = le32_to_cpu(reset_status_le); - - ((sys_reset_cmd_callback_t)command_handle->on_final)(command_handle, - command_handle->error_status, - reset_status_cpu); -} - -/***************************************************************************//** - * Handle property-is from SECONDARY: - * This functions is called when a property-is command is received from the SECONDARY. - * The SECONDARY emits a property-is in response to a property-get/set. - ******************************************************************************/ -static void on_final_property_is(sys_command_handle_t *command_handle, - sys_cmd_t *reply, - bool is_uframe) -{ - sys_property_cmd_t *property_cmd = (sys_property_cmd_t *)reply->payload; - sys_property_get_set_cmd_callback_t callback = (sys_property_get_set_cmd_callback_t)command_handle->on_final; - - // Make sure only certain properties are allowed as u-frame (non-encrypted) - if (is_uframe) - { - if (property_cmd->property_id != PROP_RX_CAPABILITY - && property_cmd->property_id != PROP_CAPABILITIES - && property_cmd->property_id != PROP_BUS_SPEED_VALUE - && property_cmd->property_id != PROP_PROTOCOL_VERSION - && property_cmd->property_id != PROP_SECONDARY_CPC_VERSION - && property_cmd->property_id != PROP_SECONDARY_APP_VERSION - && property_cmd->property_id != PROP_BOOTLOADER_REBOOT_MODE) - { - ERROR("Received on_final property_is %x as a u-frame", property_cmd->property_id); - } - } - - /* Deal with endianness of the returned property-id since its a 32bit value. */ - property_id_t property_id_le = property_cmd->property_id; - property_id_t property_id_cpu = le32_to_cpu(property_id_le); - - size_t value_length = reply->length - sizeof(sys_property_cmd_t); - - callback(command_handle, - property_id_cpu, - property_cmd->payload, - value_length, - command_handle->error_status); -} - -/***************************************************************************//** - * This function is called by CPC cpcd poll reply (final) is received - ******************************************************************************/ -static void on_reply(uint8_t endpoint_id, - void *arg, - void *answer, - uint32_t answer_lenght) -{ - sys_command_handle_t *command_handle; - sys_cmd_t *reply = (sys_cmd_t *)answer; - size_t frame_type = (size_t)arg; - - (void)answer_lenght; - - ASSERT_ON(endpoint_id != 0); - ERROR_ON(reply->length != answer_lenght - sizeof(sys_cmd_t)); - - /* Go through the list of pending requests to find the one for which this reply applies */ - SLIST_FOR_EACH_ENTRY(commands, command_handle, sys_command_handle_t, node_commands) - { - if (command_handle->command_seq == reply->command_seq) - { - TRACE_SYSTEM("Processing command seq#%d of type %d", reply->command_seq, frame_type); - - /* Stop and close the retransmit timer */ - if (frame_type == CPC_HDLC_FRAME_TYPE_UFRAME - || (frame_type == CPC_HDLC_FRAME_TYPE_IFRAME && command_handle->acked == true)) - { - ASSERT_ON(command_handle->re_transmit_timer_private_data.file_descriptor <= 0); - epoll_port_unregister(&command_handle->re_transmit_timer_private_data); - close(command_handle->re_transmit_timer_private_data.file_descriptor); - command_handle->re_transmit_timer_private_data.file_descriptor = 0; - } - - /* Call the appropriate callback */ - if (frame_type == CPC_HDLC_FRAME_TYPE_UFRAME) - { - ASSERT_ON(command_handle->is_uframe == false); - switch (reply->command_id) - { - case CMD_SYSTEM_RESET: - on_final_reset(command_handle, reply); - break; - case CMD_SYSTEM_PROP_VALUE_IS: - on_final_property_is(command_handle, reply, true); - break; - default: - ERROR("system endpoint command id not recognized for u-frame"); - break; - } - } else if (frame_type == CPC_HDLC_FRAME_TYPE_IFRAME) - { - ASSERT_ON(command_handle->is_uframe == true); - switch (reply->command_id) - { - case CMD_SYSTEM_NOOP: - on_final_noop(command_handle, reply); - break; - - case CMD_SYSTEM_PROP_VALUE_IS: - on_final_property_is(command_handle, reply, false); - break; - - case CMD_SYSTEM_PROP_VALUE_GET: - case CMD_SYSTEM_PROP_VALUE_SET: - ERROR("its the primary who sends those"); - break; - - default: - ERROR("system endpoint command id not recognized for i-frame"); - break; - } - } else - { - ERROR("Invalid frame_type"); - } - - /* Cleanup this command now that it's been serviced */ - slist_remove(&commands, &command_handle->node_commands); - free(command_handle->command); - free(command_handle); - - return; - } - } - - WARN("Received a system final for which no pending poll is registered"); -} - -static void on_uframe_receive(uint8_t endpoint_id, const void *data, size_t data_len) -{ - ERROR_ON(endpoint_id != CPC_EP_SYSTEM); - - TRACE_SYSTEM("Unsolicited uframe received"); - - sys_cmd_t *reply = (sys_cmd_t *)data; - - ERROR_ON(reply->length != data_len - sizeof(sys_cmd_t)); - - if (reply->command_id == CMD_SYSTEM_PROP_VALUE_IS) - { - sys_property_cmd_t *property = (sys_property_cmd_t *)reply->payload; - - if (property->property_id == PROP_LAST_STATUS) - { - last_status_callback_list_t *item; - - SLIST_FOR_EACH_ENTRY(prop_last_status_callbacks, item, last_status_callback_list_t, node) - { - sys_status_t *status = (sys_status_t *)property->payload; - - item->callback(*status); - } - } - } -} - -static void on_iframe_unsolicited(uint8_t endpoint_id, const void *data, size_t data_len) -{ - ERROR_ON(endpoint_id != CPC_EP_SYSTEM); - - TRACE_SYSTEM("Unsolicited i-frame received"); - - if (primary_cpcd_reset_sequence_in_progress()) - { - TRACE_SYSTEM("Cannot process unsolicited i-frame during reset sequence, ignoring"); - return; - } - - sys_cmd_t *reply = (sys_cmd_t *)data; - - ERROR_ON(reply->length != data_len - sizeof(sys_cmd_t)); - - if (reply->command_id == CMD_SYSTEM_PROP_VALUE_IS) - { - sys_property_cmd_t *property = (sys_property_cmd_t *)reply->payload; - - if (property->property_id >= PROP_EP_STATE_0 && property->property_id < PROP_EP_STATES) - { - uint8_t closed_endpoint_id = PROPERTY_ID_TO_EP_ID(property->property_id); - cpc_ep_state_t endpoint_state = cpcd_state_mapper(*(uint8_t *)property->payload); - - if (endpoint_state == CPC_EP_STATE_CLOSING) - { - TRACE_SYSTEM("Secondary closed the endpoint #%d", closed_endpoint_id); - // The secondary notified us this endpoint will be closed - if (!primary_listener_list_empty(closed_endpoint_id) && cpcd_get_endpoint_state(closed_endpoint_id) == CPC_EP_STATE_OPEN) - { - // There are still clients connected to the endpoint - // We set this endpoint in error so clients are aware - cpcd_set_endpoint_in_error(closed_endpoint_id, CPC_EP_STATE_ERROR_DEST_UNREACH); - // And we acknowledge this notification - sys_cmd_property_set(sys_closing_ep_async_cb, - EP_CLOSE_RETRIES, - EP_CLOSE_RETRY_TIMEOUT, - property->property_id, - &endpoint_state, - sizeof(cpc_ep_state_t), - false); - } else - { - // We acknowledge this notification and close the endpoint in the callback - sys_cmd_property_set(sys_closing_ep_cb, - EP_CLOSE_RETRIES, - EP_CLOSE_RETRY_TIMEOUT, - property->property_id, - &endpoint_state, - sizeof(cpc_ep_state_t), - false); - } - } else - { - ERROR("Invalid property id"); - } - } - } -} - -/***************************************************************************//** - * System endpoint timer expire callback - ******************************************************************************/ -static void on_timer_expired(epoll_port_private_data_t *private_data) -{ - int timer_fd = private_data->file_descriptor; - sys_command_handle_t *command_handle = container_of(private_data, - sys_command_handle_t, - re_transmit_timer_private_data); - - TRACE_SYSTEM("Command ID #%u SEQ #%u timer expired", command_handle->command->command_id, command_handle->command->command_seq); - - /* Ack the timer */ - { - uint64_t expiration; - ssize_t retval; - - retval = read(timer_fd, &expiration, sizeof(expiration)); - - ERROR_SYSCALL_ON(retval < 0); - - ERROR_ON(retval != sizeof(expiration)); - - WARN_ON(expiration != 1); /* we missed a timeout*/ - } - - if (!command_handle->retry_forever) - { - command_handle->retry_count--; - } - - if (command_handle->retry_count > 0 || command_handle->retry_forever) - { - slist_remove(&commands, &command_handle->node_commands); - - command_handle->error_status = STATUS_IN_PROGRESS; //at least one timer retry occurred - - write_command(command_handle); - - if (command_handle->retry_forever) - { - TRACE_SYSTEM("Command ID #%u SEQ #%u retried", command_handle->command->command_id, command_handle->command->command_seq); - } else - { - TRACE_SYSTEM("Command ID #%u SEQ #%u. %u retry left", command_handle->command->command_id, command_handle->command->command_seq, command_handle->retry_count); - } - } else - { - sys_cmd_timed_out(command_handle->command); - } -} - -/***************************************************************************//** - * Write command on endpoint - ******************************************************************************/ -static void write_command(sys_command_handle_t *command_handle) -{ - int timer_fd; - uint8_t flags = FLAG_INFORMATION_POLL; - - if (command_handle->retry_count == 0) - { - command_handle->retry_forever = true; - } else - { - command_handle->retry_forever = false; - } - - if (command_handle->is_uframe) - { - flags = FLAG_UFRAME_POLL; - } - -#if !defined(UNIT_TESTING) - // Can't send iframe commands on the system endpoint until the sequence numbers are reset - if (!command_handle->is_uframe) - { - if (!sys_received_unnumbered_acknowledgement()) - { - slist_push_back(&pending_commands, &command_handle->node_commands); - return; - } - } -#endif - - slist_push_back(&commands, &command_handle->node_commands); - - command_handle->acked = false; - - cpcd_write(CPC_EP_SYSTEM, - (void *)command_handle->command, - SIZEOF_SYSTEM_COMMAND(command_handle->command), - flags); - - TRACE_SYSTEM("Submitted command_id #%d command_seq #%d", command_handle->command->command_id, command_handle->command_seq); - - if (command_handle->is_uframe) - { - /* Setup timeout timer.*/ - { - const struct itimerspec timeout = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, - .it_value = { .tv_sec = (long int)command_handle->retry_timeout_us / 1000000, .tv_nsec = ((long int)command_handle->retry_timeout_us * 1000) % 1000000000 } }; - - timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - - ERROR_SYSCALL_ON(timer_fd < 0); - - int ret = timerfd_settime(timer_fd, - 0, - &timeout, - NULL); - - ERROR_SYSCALL_ON(ret < 0); - } - - /* Setup the timer in the primary_cpcd epoll set */ - { - command_handle->re_transmit_timer_private_data.endpoint_number = CPC_EP_SYSTEM; - command_handle->re_transmit_timer_private_data.file_descriptor = timer_fd; - command_handle->re_transmit_timer_private_data.callback = on_timer_expired; - - epoll_port_register(&command_handle->re_transmit_timer_private_data); - } - } -} - -void sys_cleanup(void) -{ - slist_node_t *item; - last_status_callback_list_t *callback_list_item; - - TRACE_RESET("Server cpcd cleanup"); - - item = slist_pop(&prop_last_status_callbacks); - while (item != NULL) - { - callback_list_item = SLIST_ENTRY(item, last_status_callback_list_t, node); - free(callback_list_item); - item = slist_pop(&pending_commands); - } - - // Close the system endpoint - cpcd_close_endpoint(CPC_EP_SYSTEM, false, true); -} - -void sys_init(void) -{ - slist_init(&commands); - slist_init(&retries); - slist_init(&pending_commands); - slist_init(&commands_in_error); - slist_init(&prop_last_status_callbacks); - - sys_open_endpoint(); -} - -void sys_register_unsolicited_prop_last_status_callback(sys_unsolicited_status_callback_t callback) -{ - last_status_callback_list_t *item = calloc_port(sizeof(last_status_callback_list_t)); - ERROR_ON(item == NULL); - - item->callback = callback; - - slist_push_back(&prop_last_status_callbacks, &item->node); -} \ No newline at end of file diff --git a/module/cpc/cpcd/primary/system/system.h b/module/cpc/cpcd/primary/system/system.h deleted file mode 100644 index 52b15aa..0000000 --- a/module/cpc/cpcd/primary/system/system.h +++ /dev/null @@ -1,188 +0,0 @@ - - -#ifndef __SYSTEM_H__ -#define __SYSTEM_H__ - -#include "primary/epoll_port/epoll_port.h" -#include "utility/slist.h" -#include "libcpc.h" -#include "utility/status.h" - -#include -#include - -#define CPC_CPC_EP_SYSTEM 0 - -CPC_ENUM_DECLARE(sys_cmd_id_t) -{ - CMD_SYSTEM_NOOP = 0x00, - CMD_SYSTEM_RESET = 0x01, - CMD_SYSTEM_PROP_VALUE_GET = 0x02, - CMD_SYSTEM_PROP_VALUE_SET = 0x03, - CMD_SYSTEM_PROP_VALUE_IS = 0x06, - CMD_SYSTEM_INVALID = 0xFF, -}; - -CPC_ENUM_GENERIC_DECLARE(property_id_t, uint32_t) -{ - PROP_LAST_STATUS = 0x00, - PROP_PROTOCOL_VERSION = 0x01, - PROP_CAPABILITIES = 0x02, - PROP_SECONDARY_CPC_VERSION = 0x03, - PROP_SECONDARY_APP_VERSION = 0x04, - PROP_RX_CAPABILITY = 0x20, - PROP_FC_VALIDATION_VALUE = 0x30, - PROP_BUS_SPEED_VALUE = 0x40, - - PROP_BOOTLOADER_REBOOT_MODE = 0x202, - - PROP_cpcd_DEBUG_COUNTERS = 0x400, - PROP_UFRAME_PROCESSING = 0x500, - - PROP_EP_STATE_0 = 0x1000, - - PROP_EP_STATES = 0x1100, -}; - -#define EP_ID_TO_PROPERTY_ID(property, ep_id) ((property_id_t)((property) | ((ep_id) & 0x000000FF))) - -#define PROPERTY_ID_TO_EP_ID(property_id) ((uint8_t)(property_id & 0x000000FF)) - -#define EP_ID_TO_PROPERTY_STATE(ep_id) EP_ID_TO_PROPERTY_ID(PROP_EP_STATE_0, ep_id) - -#define EP_ID_TO_PROPERTY_ENCRYPTION(ep_id) EP_ID_TO_PROPERTY_ID(PROP_EP_ENCRYPTION, ep_id) - - -#define AGGREGATED_STATE_LOW(agg) ((cpc_ep_state_t)(agg & 0x0F)) -#define AGGREGATED_STATE_HIGH(agg) ((cpc_ep_state_t)(agg >> 4)) - -#define GET_EP_STATE_FROM_STATES(payload, ep_id) \ - ((ep_id % 2 == 0) ? AGGREGATED_STATE_LOW(((uint8_t *)payload)[ep_id / 2]) \ - : AGGREGATED_STATE_HIGH(((uint8_t *)payload)[ep_id / 2])) - -CPC_ENUM_GENERIC_DECLARE(sys_status_t, uint32_t) -{ - SYS_STATUS_OK = 0, - SYS_STATUS_FAILURE = 1, - SYS_STATUS_UNIMPLEMENTED = 2, - SYS_STATUS_INVALID_ARGUMENT = 3, - SYS_STATUS_INVALID_STATE = 4, - SYS_STATUS_INVALID_COMMAND = 5, - SYS_STATUS_INVALID_INTERFACE = 6, - SYS_STATUS_INTERNAL_ERROR = 7, - SYS_STATUS_PARSE_ERROR = 9, - SYS_STATUS_IN_PROGRESS = 10, - SYS_STATUS_NOMEM = 11, - SYS_STATUS_BUSY = 12, - SYS_STATUS_PROP_NOT_FOUND = 13, - SYS_STATUS_PACKET_DROPPED = 14, - SYS_STATUS_EMPTY = 15, - SYS_STATUS_CMD_TOO_BIG = 16, - SYS_STATUS_ALREADY = 19, - SYS_STATUS_ITEM_NOT_FOUND = 20, - SYS_STATUS_INVALID_COMMAND_FOR_PROP = 21, - - SYS_STATUS_RESET_POWER_ON = 112, - SYS_STATUS_RESET_EXTERNAL = 113, - SYS_STATUS_RESET_SOFTWARE = 114, - SYS_STATUS_RESET_FAULT = 115, - SYS_STATUS_RESET_CRASH = 116, - SYS_STATUS_RESET_ASSERT = 117, - SYS_STATUS_RESET_OTHER = 118, - SYS_STATUS_RESET_UNKNOWN = 119, - SYS_STATUS_RESET_WATCHDOG = 120, -}; - - -CPC_ENUM_GENERIC_DECLARE(sys_reboot_mode_t, uint32_t) -{ - REBOOT_APPLICATION = 0, - REBOOT_BOOTLOADER = 1 -}; - -#define CPC_CAPABILITIES_PACKED_EP_MASK (1 << 1) -#define CPC_CAPABILITIES_UART_FLOW_CONTROL_MASK (1 << 3) - - -typedef struct -{ - sys_cmd_id_t command_id; ///< Identifier of the command. - uint8_t command_seq; ///< Command sequence number - uint16_t length; ///< Length of the payload in bytes. - uint8_t payload[]; ///< Command payload. -}sys_cmd_t; - -typedef struct -{ - property_id_t property_id; ///< Identifier of the property. - uint8_t payload[]; ///< Property value. -}sys_property_cmd_t; - -typedef struct -{ - slist_node_t node_commands; - sys_cmd_t *command; // has to be malloc'ed - void *on_final; - uint8_t retry_count; - bool retry_forever; - bool is_uframe; - uint32_t retry_timeout_us; - status_t error_status; - uint8_t command_seq; - bool acked; - epoll_port_private_data_t re_transmit_timer_private_data; //for epoll for timerfd -} sys_command_handle_t; - -void sys_init(void); - - -typedef void (*sys_unsolicited_status_callback_t) (sys_status_t status); - -typedef void (*sys_noop_cmd_cb_t) (sys_command_handle_t *handle, status_t status); - - -typedef void (*sys_reset_cmd_callback_t) (sys_command_handle_t *handle, status_t command_status, sys_status_t reset_status); - -typedef void (*sys_property_get_set_cmd_callback_t) (sys_command_handle_t *handle, - property_id_t property_id, - void *property_value, - size_t property_length, - status_t status); -void sys_cmd_noop(sys_noop_cmd_cb_t on_noop_reply, - uint8_t retry_count_max, - uint32_t retry_timeout_us); - - -void sys_cmd_reboot(sys_reset_cmd_callback_t on_reset_reply, - uint8_t retry_count_max, - uint32_t retry_timeout_us); - -void sys_cmd_property_get(sys_property_get_set_cmd_callback_t on_property_get_reply, - property_id_t property_id, - uint8_t retry_count_max, - uint32_t retry_timeout_us, - bool is_uframe); - -void sys_cmd_property_set(sys_property_get_set_cmd_callback_t on_property_set_reply, - uint8_t retry_count_max, - uint32_t retry_timeout_us, - property_id_t property_id, - const void *value, - size_t value_length, - bool is_uframe); - -void sys_register_unsolicited_prop_last_status_callback(sys_unsolicited_status_callback_t); - -void sys_reset_sys_endpoint(void); - -void sys_request_sequence_reset(void); - -void sys_cmd_poll_acknowledged(const void *data); - -bool sys_received_unnumbered_acknowledgement(void); - -void sys_on_unnumbered_acknowledgement(void); - -void sys_cleanup(void); - -#endif diff --git a/module/cpc/cpcd/utility/config.c b/module/cpc/cpcd/utility/config.c deleted file mode 100644 index fd34dc2..0000000 --- a/module/cpc/cpcd/utility/config.c +++ /dev/null @@ -1,635 +0,0 @@ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sleep.h" -#include "config.h" -#include "logs.h" -#include "version.h" -#include "utils.h" - -/******************************************************************************* - ********************** DATA TYPES ****************************************** - ******************************************************************************/ -typedef struct -{ - char *val; - char *name; - bool has_arg; -} argv_exclude_t; - -/******************************************************************************* - ********************** GLOBAL CONFIGURATION VALUES ************************* - ******************************************************************************/ -config_t config = -{ - .file_path = CPCD_CONFIG_FILE_PATH, - .instance_name = DEFAULT_INSTANCE_NAME, - - .socket_folder = CPC_SOCKET_DIR, - .stdout_tracing = false, - .file_tracing = true, - .lttng_tracing = false, - .enable_frame_trace = false, - .traces_folder = "/dev/shm/cpcd-traces", - .bus = UNCHOSEN, - // UART config - .uart_baudrate = 115200, - .uart_hardflow = false, - .uart_file = NULL, - .application_version_validation = NULL, - .print_secondary_versions_and_exit = false, - .use_noop_keep_alive = false, - .reset_sequence = true, - .uart_validation_test_option = NULL, - .stats_interval = 0, - .rlimit_nofile = 2000, -}; - -/******************************************************************************* - ************************** LOCAL PROTOTYPES ******************************** - ******************************************************************************/ - -static void config_print_version(FILE *stream, int exit_code); - -static void config_print_help(FILE *stream, int exit_code); - -static void config_parse_cli_arg(int argc, char *argv[]); - -static void config_set_rlimit_nofile(void); - -static void config_validate_configuration(void); - -static void config_parse_config_file(void); - - -/******************************************************************************* - **************************** IMPLEMENTATION ******************************** - ******************************************************************************/ -static const char *config_bool_to_str(bool value) -{ - return value ? "true" : "false"; -} - -static const char *config_to_str(const char *value) -{ - return value ? value : ""; -} - -static const char *config_bus_to_str(bus_t value) -{ - switch (value) - { - case UART: - return "UART"; - case SPI: - return "SPI"; - case UNCHOSEN: - return "UNCHOSEN"; - default: - ERROR("bus_t value not supported (%d)", value); - } -} - -#define CONFIG_PREFIX_LEN(variable) (strlen(#variable) + 1) - -#define CONFIG_PRINT_STR(value) \ - do { \ - PRINT_INFO("%s = %s", &(#value)[print_offset], config_to_str(value)); \ - run_time_total_size += (uint32_t)sizeof(value); \ - } while (0) - -#define CONFIG_PRINT_BOOL_TO_STR(value) \ - do { \ - PRINT_INFO("%s = %s", &(#value)[print_offset], config_bool_to_str(value)); \ - run_time_total_size += (uint32_t)sizeof(value); \ - } while (0) - -#define CONFIG_PRINT_OPERATION_MODE_TO_STR(value) \ - do { \ - PRINT_INFO("%s = %s", &(#value)[print_offset], config_operation_mode_to_str(value)); \ - run_time_total_size += (uint32_t)sizeof(value); \ - } while (0) - -#define CONFIG_PRINT_BUS_TO_STR(value) \ - do { \ - PRINT_INFO("%s = %s", &(#value)[print_offset], config_bus_to_str(value)); \ - run_time_total_size += (uint32_t)sizeof(value); \ - } while (0) - -#define CONFIG_PRINT_DEC(value) \ - do { \ - PRINT_INFO("%s = %d", &(#value)[print_offset], value); \ - run_time_total_size += (uint32_t)sizeof(value); \ - } while (0) - -static void config_print(void) -{ - PRINT_INFO("Reading configuration"); - - size_t print_offset = CONFIG_PREFIX_LEN(config); - - uint32_t compile_time_total_size = (uint32_t)sizeof(config_t); - uint32_t run_time_total_size = 0; - - CONFIG_PRINT_STR(config.file_path); - - CONFIG_PRINT_STR(config.instance_name); - - CONFIG_PRINT_STR(config.socket_folder); - - CONFIG_PRINT_BOOL_TO_STR(config.stdout_tracing); - CONFIG_PRINT_BOOL_TO_STR(config.file_tracing); - CONFIG_PRINT_BOOL_TO_STR(config.lttng_tracing); - CONFIG_PRINT_BOOL_TO_STR(config.enable_frame_trace); - CONFIG_PRINT_STR(config.traces_folder); - - CONFIG_PRINT_BUS_TO_STR(config.bus); - - CONFIG_PRINT_DEC(config.uart_baudrate); - CONFIG_PRINT_BOOL_TO_STR(config.uart_hardflow); - CONFIG_PRINT_STR(config.uart_file); - - - CONFIG_PRINT_BOOL_TO_STR(config.application_version_validation); - - CONFIG_PRINT_BOOL_TO_STR(config.print_secondary_versions_and_exit); - - CONFIG_PRINT_BOOL_TO_STR(config.use_noop_keep_alive); - - CONFIG_PRINT_BOOL_TO_STR(config.reset_sequence); - - CONFIG_PRINT_STR(config.uart_validation_test_option); - - CONFIG_PRINT_DEC(config.stats_interval); - - CONFIG_PRINT_DEC(config.rlimit_nofile); - - if (run_time_total_size != compile_time_total_size) - { - ERROR("A new config was added to config_t but it was not printed. run_time_total_size (%d) != compile_time_total_size (%d)", run_time_total_size, compile_time_total_size); - } -} - -static void print_cli_args(int argc, char *argv[]) -{ - char *cli_args; - size_t cli_args_size = 0; - - for (int i = 0; i < argc; i++) - { - if (argv[i]) - { - cli_args_size += strlen(argv[i]) + strlen(" ") + 1; - } - } - - cli_args = calloc_port(cli_args_size); - ERROR_SYSCALL_ON(cli_args == NULL); - - for (int i = 0; i < argc; i++) - { - if (argv[i]) - { - strcat(cli_args, argv[i]); - strcat(cli_args, " "); - } - } - - PRINT_INFO("%s", cli_args); - free(cli_args); -} - -#define ARGV_OPT_CONF "conf" -#define ARGV_OPT_HELP "help" -#define ARGV_OPT_VERSION "version" -#define ARGV_OPT_SECONDARY_VERSIONS "secondary-versions" -#define ARGV_OPT_APP_VERSION "app-version" - -const struct option argv_opt_list[] = -{ - { ARGV_OPT_CONF, required_argument, 0, 'c' }, - { ARGV_OPT_HELP, no_argument, 0, 'h' }, - { ARGV_OPT_VERSION, no_argument, 0, 'v' }, - { ARGV_OPT_SECONDARY_VERSIONS, no_argument, 0, 'p' }, - { ARGV_OPT_APP_VERSION, required_argument, 0, 'a' }, - { 0, 0, 0, 0 } -}; - -static void config_parse_cli_arg(int argc, char *argv[]) -{ - int opt; - - PRINT_INFO("Reading cli arguments"); - - print_cli_args(argc, argv); - - while (1) - { - opt = getopt_long(argc, argv, "c:hpv:a:", argv_opt_list, NULL); - - if (opt == -1) - { - break; - } - - switch (opt) - { - case 'c': - config.file_path = optarg; - break; - case 'h': - config_print_help(stdout, 0); - break; - case 'v': - config_print_version(stdout, 0); - break; - case 'a': - config.application_version_validation = optarg; - break; - case 'p': - config.print_secondary_versions_and_exit = true; - break; - case '?': - default: - config_print_help(stderr, 1); - break; - } - } -} - -void config_restart_cpcd(char **argv) -{ - PRINT_INFO("Restarting CPCd..."); - sleep_s(1); // Wait for logs to be flushed - execv("/proc/self/exe", argv); -} - - -static inline bool is_nul(char c) -{ - return c == '\0'; -} - -static inline bool is_white_space(char c) -{ - return c == ' ' || c == '\t'; -} - -static inline bool is_line_break(char c) -{ - return c == '\n' || c == '\r'; -} - -static inline bool is_comment(char c) -{ - return c == '#'; -} - -static int32_t non_leading_whitespaces_index(const char *str) -{ - int32_t i = 0; - while (!is_nul(str[i])) - { - if (!is_white_space(str[i])) - { - break; - } - ++i; - } - return i; -} - -static bool is_comment_or_newline(const char *line) -{ - char c = line[non_leading_whitespaces_index(line)]; - return is_nul(c) || is_line_break(c) || is_comment(c); -} - -static void config_parse_config_file(void) -{ - FILE *config_file = NULL; - char name[128] = { 0 }; - char val[128] = { 0 }; - char line[256] = { 0 }; - char *endptr = NULL; - int tmp_config_file_tracing = 0; - - config_file = fopen(config.file_path, "r"); - - if (config_file == NULL) - { - ERROR("Could not open the configuration file under: %s, please install the configuration file there or provide a valid path with --conf\n", config.file_path); - } - - /* Iterate through every line of the file*/ - while (fgets(line, sizeof(line), config_file) != NULL) - { - if (is_comment_or_newline(line)) - { - continue; - } - - /* Extract name=value pair */ - if (sscanf(line, "%127[^: ]: %127[^\r\n #]%*c", name, val) != 2) - { - ERROR("Config file line \"%s\" doesn't respect syntax. Expecting YAML format (key: value). Please refer to the provided cpcd.conf", line); - } - - if (0 == strcmp(name, "instance_name")) - { - config.instance_name = strdup(val); - ERROR_ON(config.instance_name == NULL); - } else if (0 == strcmp(name, "bus_type")) - { - if (0 == strcmp(val, "UART")) - { - config.bus = UART; - } else if (0 == strcmp(val, "SPI")) - { - config.bus = SPI; - } else - { - ERROR("Config file error : bad bus_type value\n"); - } - } else if (0 == strcmp(name, "uart_device_file")) - { - config.uart_file = strdup(val); - ERROR_ON(config.uart_file == NULL); - } else if (0 == strcmp(name, "uart_device_baud")) - { - config.uart_baudrate = (unsigned int)strtoul(val, &endptr, 10); - if (*endptr != '\0') - { - ERROR("Bad config line \"%s\"", line); - } - } else if (0 == strcmp(name, "uart_hardflow")) - { - if (0 == strcmp(val, "true")) - { - config.uart_hardflow = true; - } else if (0 == strcmp(val, "false")) - { - config.uart_hardflow = false; - } else - { - ERROR("Config file error : bad UART_HARDFLOW value"); - } - } else if (0 == strcmp(name, "noop_keep_alive")) - { - if (0 == strcmp(val, "true")) - { - config.use_noop_keep_alive = true; - } else if (0 == strcmp(val, "false")) - { - config.use_noop_keep_alive = false; - } else - { - ERROR("Config file error : bad noop_keep_alive value"); - } - } else if (0 == strcmp(name, "stdout_trace")) - { - if (0 == strcmp(val, "true")) - { - config.stdout_tracing = true; - } else if (0 == strcmp(val, "false")) - { - config.stdout_tracing = false; - } else - { - ERROR("Config file error : bad stdout_trace value"); - } - } else if (0 == strcmp(name, "trace_to_file")) - { - if (0 == strcmp(val, "true")) - { - tmp_config_file_tracing = true; - } else if (0 == strcmp(val, "false")) - { - tmp_config_file_tracing = false; - } else - { - ERROR("Config file error : bad trace_to_file value"); - } - } else if (0 == strcmp(name, "enable_frame_trace")) - { - if (0 == strcmp(val, "true")) - { - config.enable_frame_trace = true; - } else if (0 == strcmp(val, "false")) - { - config.enable_frame_trace = false; - } else - { - ERROR("Config file error : bad enable_frame_trace value"); - } - } else if (0 == strcmp(name, "reset_sequence")) - { - if (0 == strcmp(val, "true")) - { - config.reset_sequence = true; - } else if (0 == strcmp(val, "false")) - { - config.reset_sequence = false; - } else - { - ERROR("Config file error : bad reset_sequence value"); - } - } else if (0 == strcmp(name, "traces_folder")) - { - config.traces_folder = strdup(val); - ERROR_ON(config.traces_folder == NULL); - } else if (0 == strcmp(name, "rlimit_nofile")) - { - config.rlimit_nofile = strtoul(val, &endptr, 10); - if (*endptr != '\0') - { - ERROR("Config file error : bad rlimit_nofile value"); - } - } - } - - config.file_tracing = tmp_config_file_tracing; - - fclose(config_file); -} - -static void prevent_device_collision(const char *const device_name) -{ - int tmp_fd = open(device_name, O_RDWR | O_CLOEXEC); - - /* Try to apply a cooperative exclusive file lock on the device file. Don't block */ - int ret = flock(tmp_fd, LOCK_EX | LOCK_NB); - - if (ret == 0) - { - /* The device file is free to use, leave this file descriptor open - * to preserve the lock. */ - } else if (errno == EWOULDBLOCK) - { - ERROR("The device \"%s\" is locked by another cpcd instance", device_name); - } else - { - ERROR_SYSCALL_ON(0); - } -} - -static void prevent_instance_collision(const char *const instance_name) -{ - struct sockaddr_un name; - int ctrl_sock_fd; - - /* Create datagram socket for control */ - ctrl_sock_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - ERROR_SYSCALL_ON(ctrl_sock_fd < 0); - - /* Clear struct for portability */ - memset(&name, 0, sizeof(name)); - - name.sun_family = AF_UNIX; - - /* Create the control socket path */ - { - int nchars; - const size_t size = sizeof(name.sun_path) - sizeof('\0'); - - nchars = snprintf(name.sun_path, size, "%s/cpcd/%s/ctrl.cpcd.sock", config.socket_folder, instance_name); - - /* Make sure the path fitted entirely */ - ERROR_ON(nchars < 0 || (size_t)nchars >= size); - } - - /* Try to connect to the socket in order to see if we collide with another daemon */ - { - int ret; - - ret = connect(ctrl_sock_fd, (const struct sockaddr *)&name, sizeof(name)); - - (void)close(ctrl_sock_fd); - - if (ret == 0) - { - ERROR("Another daemon instance is already running with the same instance name : %s.", name.sun_path); - } else - { - /* good to go */ - } - } -} - -static void config_validate_configuration(void) -{ - /* Validate bus configuration */ - { - if (config.bus == UART) - { - if (config.uart_file == NULL) - { - ERROR("UART device file missing"); - } - - prevent_device_collision(config.uart_file); - } else - { - ERROR("Invalid bus configuration."); - } - } - - prevent_instance_collision(config.instance_name); - - if (config.file_tracing) - { - init_file_logging(); - } - - if (config.stats_interval > 0) - { - init_stats_logging(); - } -} - -static void config_set_rlimit_nofile(void) -{ - struct rlimit limit; - int ret; - - /* Make sure RLIMIT_NOFILE (number of concurrent opened file descriptor) - * is at least rlimit_nofile */ - - ret = getrlimit(RLIMIT_NOFILE, &limit); - ERROR_SYSCALL_ON(ret < 0); - - if (limit.rlim_cur < config.rlimit_nofile) - { - if (config.rlimit_nofile > limit.rlim_max) - { - ERROR("The OS doesn't support our requested RLIMIT_NOFILE value"); - } - - limit.rlim_cur = config.rlimit_nofile; - - ret = setrlimit(RLIMIT_NOFILE, &limit); - ERROR_SYSCALL_ON(ret < 0); - } -} - -static void config_print_version(FILE *stream, int exit_code) -{ -#ifndef GIT_SHA1 -#define GIT_SHA1 "missing SHA1" -#endif - -#ifndef GIT_REFSPEC -#define GIT_REFSPEC "missing refspec" -#endif - - fprintf(stream, "%s\n", PROJECT_VER); - fprintf(stream, "GIT commit: %s\n", GIT_SHA1); - fprintf(stream, "GIT branch: %s\n", GIT_REFSPEC); - fprintf(stream, "Sources hash: %s\n", SOURCES_HASH); - exit(exit_code); -} - -static void config_print_help(FILE *stream, int exit_code) -{ - fprintf(stream, "Start CPC daemon\n"); - fprintf(stream, "\n"); - fprintf(stream, "Usage:\n"); - fprintf(stream, " cpcd -h/--help : prints this message.\n"); - fprintf(stream, " cpcd -c/--conf : manually specify the config file.\n"); - fprintf(stream, " cpcd -v/--version : get the version of the daemon and exit.\n"); - fprintf(stream, " cpcd -p/--secondary-versions : get all secondary versions (protocol, cpc, app) and exit.\n"); - fprintf(stream, " cpcd -a/--app-version : specify the application version to match.\n"); - exit(exit_code); -} - -void config_init(int argc, char *argv[]) -{ - config_parse_cli_arg(argc, argv); - - config_parse_config_file(); - - config_validate_configuration(); - - config_set_rlimit_nofile(); - - config_print(); -} diff --git a/module/cpc/cpcd/utility/config.h b/module/cpc/cpcd/utility/config.h deleted file mode 100644 index 5274953..0000000 --- a/module/cpc/cpcd/utility/config.h +++ /dev/null @@ -1,61 +0,0 @@ - - -#ifndef CONFIG_H -#define CONFIG_H - -#include -#include - -#ifndef DEFAULT_INSTANCE_NAME - #define DEFAULT_INSTANCE_NAME "cpcd_0" -#endif - -typedef enum -{ - UART, - SPI, - UNCHOSEN -}bus_t; - -typedef struct __attribute__((packed)) -{ - const char *file_path; - const char *instance_name; - - const char *const socket_folder; - - bool stdout_tracing; - bool file_tracing; - - int lttng_tracing; - bool enable_frame_trace; - const char *traces_folder; - - bus_t bus; - - unsigned int uart_baudrate; - bool uart_hardflow; - const char *uart_file; - - const char *application_version_validation; - - bool print_secondary_versions_and_exit; - - bool use_noop_keep_alive; - - bool reset_sequence; - - const char *uart_validation_test_option; - - long stats_interval; - - rlim_t rlimit_nofile; -} config_t; - -extern config_t config; - -void config_init(int argc, char *argv[]); -void config_restart_cpcd(char **argv); -void config_restart_cpcd_without_fw_update_args(void); - -#endif //CONFIG_H diff --git a/module/cpc/cpcd/utility/endian.h b/module/cpc/cpcd/utility/endian.h deleted file mode 100644 index 216a2b6..0000000 --- a/module/cpc/cpcd/utility/endian.h +++ /dev/null @@ -1,153 +0,0 @@ - - -#ifndef ENDIANESS_H -#define ENDIANESS_H - -#include - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define __swap_le64(x) (x) -#define __swap_le32(x) (x) -#define __swap_le16(x) (x) -#define __swap_be64(x) __builtin_bswap64(x) -#define __swap_be32(x) __builtin_bswap32(x) -#define __swap_be16(x) __builtin_bswap16(x) -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define __swap_le64(x) __builtin_bswap64(x) -#define __swap_le32(x) __builtin_bswap32(x) -#define __swap_le16(x) __builtin_bswap16(x) -#define __swap_be64(x) (x) -#define __swap_be32(x) (x) -#define __swap_be16(x) (x) -#else -#error "Unsupported endianness" -#endif - -static inline uint64_t cpu_to_le64(uint64_t val) -{ - return __swap_le64(val); -} - -static inline uint64_t le64_to_cpu(uint64_t val) -{ - return __swap_le64(val); -} - -static inline uint32_t cpu_to_le32(uint32_t val) -{ - return __swap_le32(val); -} - -static inline uint32_t le32_to_cpu(uint32_t val) -{ - return __swap_le32(val); -} - -static inline uint16_t cpu_to_le16(uint16_t val) -{ - return __swap_le16(val); -} - -static inline uint16_t le16_to_cpu(uint16_t val) -{ - return __swap_le16(val); -} - -static inline uint64_t cpu_to_be64(uint64_t val) -{ - return __swap_be64(val); -} - -static inline uint64_t be64_to_cpu(uint64_t val) -{ - return __swap_be64(val); -} - -static inline uint32_t cpu_to_be32(uint32_t val) -{ - return __swap_be32(val); -} - -static inline uint32_t be32_to_cpu(uint32_t val) -{ - return __swap_be32(val); -} - -static inline uint16_t cpu_to_be16(uint16_t val) -{ - return __swap_be16(val); -} - -static inline uint16_t be16_to_cpu(uint16_t val) -{ - return __swap_be16(val); -} - -static inline void cpu_to_le64s(uint64_t *val) -{ - *val = cpu_to_le64(*val); -} - -static inline void le64_to_cpus(uint64_t *val) -{ - *val = le64_to_cpu(*val); -} - -static inline void cpu_to_le32s(uint32_t *val) -{ - *val = cpu_to_le32(*val); -} - -static inline void le32_to_cpus(uint32_t *val) -{ - *val = le32_to_cpu(*val); -} - -static inline void cpu_to_le16s(uint16_t *val) -{ - *val = cpu_to_le16(*val); -} - -static inline void le16_to_cpus(uint16_t *val) -{ - *val = le16_to_cpu(*val); -} - -static inline void cpu_to_be64s(uint64_t *val) -{ - *val = cpu_to_be64(*val); -} - -static inline void be64_to_cpus(uint64_t *val) -{ - *val = be64_to_cpu(*val); -} - -static inline void cpu_to_be32s(uint32_t *val) -{ - *val = cpu_to_be32(*val); -} - -static inline void be32_to_cpus(uint32_t *val) -{ - *val = be32_to_cpu(*val); -} - -static inline void cpu_to_be16s(uint16_t *val) -{ - *val = cpu_to_be16(*val); -} - -static inline void be16_to_cpus(uint16_t *val) -{ - *val = be16_to_cpu(*val); -} - -#define cpu_to_le64p(val) cpu_to_le64(*(val)) -#define le64_to_cpup(val) le64_to_cpu(*(val)) -#define cpu_to_le32p(val) cpu_to_le32(*(val)) -#define le32_to_cpup(val) le32_to_cpu(*(val)) -#define cpu_to_le16p(val) cpu_to_le16(*(val)) -#define le16_to_cpup(val) le16_to_cpu(*(val)) - -#endif diff --git a/module/cpc/cpcd/utility/errcode.c b/module/cpc/cpcd/utility/errcode.c deleted file mode 100644 index 28bd70f..0000000 --- a/module/cpc/cpcd/utility/errcode.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "errcode.h" - -/* #include NULL */ - -const char *const ERRNO_CODENAME[] = { - "", /* or NULL, */ - "EPERM", - "ENOENT", - "ESRCH", - "EINTR", - "EIO", - "ENXIO", - "E2BIG", - "ENOEXEC", - "EBADF", - "ECHILD", - "EAGAIN", - "ENOMEM", - "EACCES", - "EFAULT", - "ENOTBLK", - "EBUSY", - "EEXIST", - "EXDEV", - "ENODEV", - "ENOTDIR", - "EISDIR", - "EINVAL", - "ENFILE", - "EMFILE", - "ENOTTY", - "ETXTBSY", - "EFBIG", - "ENOSPC", - "ESPIPE", - "EROFS", - "EMLINK", - "EPIPE", - "EDOM", - "ERANGE", - "EDEADLK", - "ENAMETOOLONG", - "ENOLCK", - "ENOSYS", - "ENOTEMPTY", - "ELOOP", - "EWOULDBLOCK", - "ENOMSG", - "EIDRM", - "ECHRNG", - "EL2NSYNC", - "EL3HLT", - "EL3RST", - "ELNRNG", - "EUNATCH", - "ENOCSI", - "EL2HLT", - "EBADE", - "EBADR", - "EXFULL", - "ENOANO", - "EBADRQC", - "EBADSLT", - "EDEADLOCK", - "EBFONT", - "ENOSTR", - "ENODATA", - "ETIME", - "ENOSR", - "ENONET", - "ENOPKG", - "EREMOTE", - "ENOLINK", - "EADV", - "ESRMNT", - "ECOMM", - "EPROTO", - "EMULTIHOP", - "EDOTDOT", - "EBADMSG", - "EOVERFLOW", - "ENOTUNIQ", - "EBADFD", - "EREMCHG", - "ELIBACC", - "ELIBBAD", - "ELIBSCN", - "ELIBMAX", - "ELIBEXEC", - "EILSEQ", - "ERESTART", - "ESTRPIPE", - "EUSERS", - "ENOTSOCK", - "EDESTADDRREQ", - "EMSGSIZE", - "EPROTOTYPE", - "ENOPROTOOPT", - "EPROTONOSUPPORT", - "ESOCKTNOSUPPORT", - "EOPNOTSUPP", - "EPFNOSUPPORT", - "EAFNOSUPPORT", - "EADDRINUSE", - "EADDRNOTAVAIL", - "ENETDOWN", - "ENETUNREACH", - "ENETRESET", - "ECONNABORTED", - "ECONNRESET", - "ENOBUFS", - "EISCONN", - "ENOTCONN", - "ESHUTDOWN", - "ETOOMANYREFS", - "ETIMEDOUT", - "ECONNREFUSED", - "EHOSTDOWN", - "EHOSTUNREACH", - "EALREADY", - "EINPROGRESS", - "ESTALE", - "EUCLEAN", - "ENOTNAM", - "ENAVAIL", - "EISNAM", - "EREMOTEIO", - "EDQUOT", - "ENOMEDIUM", - "EMEDIUMTYPE", - "ECANCELED", - "ENOKEY", - "EKEYEXPIRED", - "EKEYREVOKED", - "EKEYREJECTED", - "EOWNERDEAD", - "ENOTRECOVERABLE", - "ERFKILL", - "EHWPOISON", -}; - -const uint16_t ERRNO_CODENAME_SIZE = sizeof ERRNO_CODENAME / sizeof *ERRNO_CODENAME; diff --git a/module/cpc/cpcd/utility/errcode.h b/module/cpc/cpcd/utility/errcode.h deleted file mode 100644 index 0cfe904..0000000 --- a/module/cpc/cpcd/utility/errcode.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef ERRNO_CODENAME_H -#define ERRNO_CODENAME_H - -#include - -/* Pointers in the array are constants, data pointed too */ -extern const char *const ERRNO_CODENAME[]; -extern const uint16_t ERRNO_CODENAME_SIZE; - -#endif /* ERRNO_CODENAME_H */ diff --git a/module/cpc/cpcd/utility/logs.c b/module/cpc/cpcd/utility/logs.c deleted file mode 100644 index 4a77ab4..0000000 --- a/module/cpc/cpcd/utility/logs.c +++ /dev/null @@ -1,701 +0,0 @@ - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utility/logs.h" -#include "primary/epoll_port/epoll_port.h" -#include "config.h" -#include "utils.h" - -static union -{ - uint16_t hex; - char nibble[2]; -} hex_str; - -#define NO_LOGGING_ERROR_ON(cond) \ - do { \ - if (cond) { \ - fprintf(stderr, "NO LOGGER FATAL on '%s' in function '%s' in file %s at line #%d\n",#cond, __func__, __FILE__, __LINE__); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - -#define NO_LOGGING_ERROR_SYSCALL_ON(cond) \ - do { \ - if (cond) { \ - fprintf(stderr, "NO LOGGER FATAL SYSCALL on '%s' in function '%s' in file %s at line #%d : %m\n",#cond, __func__, __FILE__, __LINE__); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - -static void write_until_success_or_error(int fd, uint8_t *buff, size_t size) -{ - ssize_t ret; - size_t written = 0; - size_t remaining = size; - - do - { - ret = write(fd, &buff[written], remaining); - NO_LOGGING_ERROR_SYSCALL_ON(ret < 0); - remaining -= (size_t)ret; - written += (size_t)ret; - } while (remaining != 0); -} - -#define ASYNC_LOGGER_PAGE_SIZE 4096 -#define ASYNC_LOGGER_PAGE_COUNT 7 -#define ASYNC_LOGGER_BUFFER_DEPTH (ASYNC_LOGGER_PAGE_SIZE * ASYNC_LOGGER_PAGE_COUNT) -#define ASYNC_LOGGER_TIMEOUT_MS 100 -#define ASYNC_LOGGER_DONT_TRIGG_UNLESS_THIS_CHUNK_SIZE ASYNC_LOGGER_PAGE_SIZE - -static volatile bool gracefully_exit = false; - -static int stats_timer_fd; - -static const char lut[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - -typedef struct -{ - FILE *file; - int fd; - uint8_t *buffer; - volatile size_t buffer_size; - volatile size_t buffer_head; - volatile size_t buffer_tail; - volatile size_t buffer_count; - size_t highwater_mark; - size_t lost_logs; - pthread_cond_t condition; - pthread_mutex_t mutex; - struct timespec timeout; - const char *name; -} async_logger_t; - -static async_logger_t file_logger; -static async_logger_t stdout_logger; - -static pthread_t file_logger_thread; -static pthread_t stdout_logger_thread; - -static epoll_port_private_data_t *logging_private_data; - -static void *async_logger_thread_func(void *param); - -static void async_logger_init(async_logger_t *logger, int file_descriptor, const char *name) -{ - int ret; - - NO_LOGGING_ERROR_ON(logger == NULL); - - logger->fd = file_descriptor; - logger->buffer_size = ASYNC_LOGGER_BUFFER_DEPTH; - logger->buffer_head = 0; - logger->buffer_tail = 0; - logger->buffer_count = 0; - logger->highwater_mark = 0; - logger->lost_logs = 0; - logger->name = name; - - ret = pthread_cond_init(&logger->condition, NULL); - NO_LOGGING_ERROR_ON(ret != 0); - - ret = pthread_mutex_init(&logger->mutex, NULL); - NO_LOGGING_ERROR_ON(ret != 0); - - logger->buffer = calloc_port(logger->buffer_size); - NO_LOGGING_ERROR_ON(logger->buffer == NULL); - - /* Lock the buffer in RAM since it's a long buffer and we will use it often to prevent - * page faults. */ - ret = mlock(logger->buffer, - logger->buffer_size); - NO_LOGGING_ERROR_SYSCALL_ON(ret != 0); - - logger->timeout.tv_sec = ASYNC_LOGGER_TIMEOUT_MS / 1000; - logger->timeout.tv_nsec = (ASYNC_LOGGER_TIMEOUT_MS % 1000) * 1000000; -} - -static void stdout_logging_init(void) -{ - int ret; - - async_logger_init(&stdout_logger, STDOUT_FILENO, "stdout"); - - ret = pthread_create(&stdout_logger_thread, - NULL, - async_logger_thread_func, - &stdout_logger); - NO_LOGGING_ERROR_ON(ret != 0); - - pthread_setname_np(stdout_logger_thread, "stdout_logger"); -} - -static void file_logging_init(void) -{ - int ret; - struct statfs statfs_buf; - - ret = mkdir(config.traces_folder, 0700); - NO_LOGGING_ERROR_SYSCALL_ON(ret < 0 && errno != EEXIST); - - ret = statfs(config.traces_folder, &statfs_buf); - NO_LOGGING_ERROR_SYSCALL_ON(ret < 0); - if (statfs_buf.f_type != TMPFS_MAGIC) - { - WARN("Traces folder %s is not mounted on a tmpfs", config.traces_folder); - } - - ret = access(config.traces_folder, W_OK); - NO_LOGGING_ERROR_SYSCALL_ON(ret < 0); - - /* Build file string and open file */ - { - time_t t = time(NULL); - struct tm tm = *localtime(&t); - char buf[512]; - int nchars; - - nchars = snprintf(buf, - sizeof(buf), - "%s/trace-%d-%02d-%02d_%02d-%02d-%02d.log", - config.traces_folder, - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - tm.tm_sec); - - /* Make sure the path fitted entirely in the struct's static buffer */ - NO_LOGGING_ERROR_SYSCALL_ON(nchars < 0 || (size_t)nchars >= sizeof(buf)); - - file_logger.file = fopen(buf, "w+"); - NO_LOGGING_ERROR_SYSCALL_ON(file_logger.file == NULL); - - PRINT_INFO("Logging to file enabled in file %s.", buf); - } - - file_logger.fd = fileno(file_logger.file); - - ret = pthread_create(&file_logger_thread, - NULL, - async_logger_thread_func, - &file_logger); - NO_LOGGING_ERROR_ON(ret != 0); - - pthread_setname_np(file_logger_thread, "file_logger"); -} - -static void async_logger_write(async_logger_t *logger, void *data, size_t length) -{ - bool do_signal = false; - size_t count_cpy; - - pthread_mutex_lock(&logger->mutex); - { - if (logger->buffer_size - logger->buffer_count < length) - { - /* Overflowing traces are discarded */ - fprintf(stderr, "WARNING : %s logger buffer full, lost log.\n", logger->name); - logger->lost_logs++; - } else - { - size_t remaining = logger->buffer_size - logger->buffer_head; - - if (remaining >= length) - { - memcpy(&logger->buffer[logger->buffer_head], data, length); - logger->buffer_head += length; - } else /* Split write at buffer boundary */ - { - memcpy(&logger->buffer[logger->buffer_head], data, remaining); - memcpy(&logger->buffer[0], data + remaining, length - remaining); - logger->buffer_head = length - remaining; - } - - logger->buffer_count += length; - - /* Register the high water mark */ - if (logger->buffer_count > logger->highwater_mark) - { - logger->highwater_mark = logger->buffer_count; - } - - do_signal = true; - count_cpy = logger->buffer_count; - } - } - pthread_mutex_unlock(&logger->mutex); - - if (do_signal == true) - { - if (count_cpy >= ASYNC_LOGGER_DONT_TRIGG_UNLESS_THIS_CHUNK_SIZE) - { - pthread_cond_signal(&logger->condition); - } - } -} - -static void *async_logger_thread_func(void *param) -{ - async_logger_t *logger = (async_logger_t *)param; - size_t chunk_size; - ssize_t ret; - - while (1) - { - pthread_mutex_lock(&logger->mutex); - { - while (logger->buffer_count < ASYNC_LOGGER_DONT_TRIGG_UNLESS_THIS_CHUNK_SIZE && gracefully_exit == false) - { - struct timespec max_wait; - - clock_gettime(CLOCK_REALTIME, &max_wait); - - max_wait.tv_sec++; - - ret = pthread_cond_timedwait(&logger->condition, - &logger->mutex, - &max_wait); - ERROR_ON(ret != 0 && ret != ETIMEDOUT); - - if (ret == ETIMEDOUT) - { - break; - } - } - - /* We will write as much data as we have on hand */ - chunk_size = logger->buffer_count; - } /* Unlock the mutex to allow other threads to continue to write data. */ - pthread_mutex_unlock(&logger->mutex); - - if (chunk_size == 0) - { - if (gracefully_exit == true) - { - /* Graceful exit requested and no data, kill this thread right away. */ - char buf[256]; - int ret; - ret = snprintf(buf, - sizeof(buf), - "Logger buffer size = %zu, highwater mark = %zu : %.2f%%. Lost logs : %zu\n", - logger->buffer_size, - logger->highwater_mark, - 100.0f * ((float)logger->highwater_mark / (float)logger->buffer_size), - logger->lost_logs); - /* Dont check for 'ret' overflow, we know 256 bytes was sufficient. */ - (void)write(logger->fd, buf, (size_t)ret); - fsync(logger->fd); - if (logger->fd != STDOUT_FILENO) - { - ret = fclose(logger->file); - ERROR_ON(ret != 0); - } - free(logger->buffer); - pthread_exit(NULL); - } else - { - continue; - } - } - - size_t remaining = logger->buffer_size - logger->buffer_tail; - - { - if (remaining >= chunk_size) - { - write_until_success_or_error(logger->fd, - &logger->buffer[logger->buffer_tail], - chunk_size); - } else /* Split write at the buffer boundary */ - { - write_until_success_or_error(logger->fd, - &logger->buffer[logger->buffer_tail], - remaining); - - write_until_success_or_error(logger->fd, - &logger->buffer[0], - chunk_size - remaining); - } - } - - pthread_mutex_lock(&logger->mutex); - { - if (remaining >= chunk_size) - { - logger->buffer_tail += chunk_size; - } else - { - logger->buffer_tail = chunk_size - remaining; - } - - logger->buffer_count -= chunk_size; - } - pthread_mutex_unlock(&logger->mutex); - } - - return NULL; -} - -static void stdio_log(void *data, size_t length) -{ - async_logger_write(&stdout_logger, data, length); -} - -static void file_log(void *data, size_t length) -{ - async_logger_write(&file_logger, data, length); -} - -void logging_init(void) -{ - stdout_logging_init(); - - async_logger_init(&file_logger, - -1, /* No file descriptor for the moment */ - "file"); -} - -static void logging_print_stats(epoll_port_private_data_t *event_private_data) -{ - int fd_timer = event_private_data->file_descriptor; - - /* Ack the timer */ - { - uint64_t expiration; - ssize_t ret; - - ret = read(fd_timer, &expiration, sizeof(expiration)); - ERROR_ON(ret < 0); - } - - TRACE("Host cpcd debug counters:" - "\nendpoint_opened %u" - "\nendpoint_closed %u" - "\nrxd_frame %u" - "\ntxd_reject_destination_unreachable %u" - "\ntxd_completed %u" - "\nretxd_data_frame %u" - "\ninvalid_header_checksum %u" - "\ninvalid_payload_checksum %u\n", - primary_cpcd_debug_counters.endpoint_opened, - primary_cpcd_debug_counters.endpoint_closed, - primary_cpcd_debug_counters.rxd_frame, - primary_cpcd_debug_counters.txd_reject_destination_unreachable, - primary_cpcd_debug_counters.txd_completed, - primary_cpcd_debug_counters.retxd_data_frame, - primary_cpcd_debug_counters.invalid_header_checksum, - primary_cpcd_debug_counters.invalid_payload_checksum); - - TRACE("RCP cpcd debug counters" - "\nendpoint_opened %u" - "\nendpoint_closed %u" - "\nrxd_frame %u" - "\ntxd_reject_destination_unreachable %u" - "\ntxd_completed %u" - "\nretxd_data_frame %u" - "\ndriver_packet_dropped %u" - "\ninvalid_header_checksum %u" - "\ninvalid_payload_checksum %u\n", - secondary_cpcd_debug_counters.endpoint_opened, - secondary_cpcd_debug_counters.endpoint_closed, - secondary_cpcd_debug_counters.rxd_frame, - secondary_cpcd_debug_counters.txd_reject_destination_unreachable, - secondary_cpcd_debug_counters.txd_completed, - secondary_cpcd_debug_counters.retxd_data_frame, - secondary_cpcd_debug_counters.invalid_header_checksum, - secondary_cpcd_debug_counters.invalid_payload_checksum); -} - -void init_stats_logging(void) -{ - /* Setup timer */ - stats_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - ERROR_SYSCALL_ON(stats_timer_fd < 0); - - struct itimerspec timeout_time = { .it_interval = { .tv_sec = config.stats_interval, .tv_nsec = 0 }, - .it_value = { .tv_sec = config.stats_interval, .tv_nsec = 0 } }; - - int ret = timerfd_settime(stats_timer_fd, - 0, - &timeout_time, - NULL); - - ERROR_SYSCALL_ON(ret < 0); - - /* Setup epoll */ - { - logging_private_data = (epoll_port_private_data_t *)calloc_port(sizeof(epoll_port_private_data_t)); - ERROR_ON(logging_private_data == NULL); - - logging_private_data->callback = logging_print_stats; - logging_private_data->file_descriptor = stats_timer_fd; - - epoll_port_register(logging_private_data); - } -} - -void init_file_logging() -{ - file_logging_init(); -} - -void logging_kill(void) -{ - /* Note we don't cancel the threads, we let them finish */ - - gracefully_exit = true; - - pthread_cond_signal(&stdout_logger.condition); - pthread_join(stdout_logger_thread, NULL); - - if (config.file_tracing) - { - pthread_cond_signal(&file_logger.condition); - pthread_join(file_logger_thread, NULL); - } - - free(logging_private_data); -} - -static size_t get_time_string(char *time_string, size_t time_string_size) -{ - long ms; - time_t s; - struct timespec spec; - struct tm *tm_info; - size_t nchar; - int ret = clock_gettime(CLOCK_REALTIME, &spec); - - s = spec.tv_sec; - - ms = spec.tv_nsec / 1000000; - if (ms > 999) - { - s++; - ms = 0; - } - - if (ret != ((time_t)-1)) - { - tm_info = localtime(&s); - nchar = strftime(time_string, time_string_size, "%H:%M:%S", tm_info); - nchar += (size_t)snprintf(&time_string[nchar], time_string_size - nchar, ":%03ld", ms); - } else - { - nchar = (size_t)snprintf(time_string, time_string_size, "time error"); - } - - return nchar; -} - -void trace(const bool force_stdout, const char *string, ...) -{ - char log_string[512]; - size_t log_string_length = 0; - - if (!config.file_tracing && !config.stdout_tracing && !force_stdout) - { - return; - } - - /* Append the time stamp */ - { - log_string[log_string_length++] = '['; - log_string_length += get_time_string(&log_string[log_string_length], sizeof(log_string) - log_string_length); - log_string[log_string_length++] = ']'; - log_string[log_string_length++] = ' '; - } - - /* Append formated text */ - { - va_list vl; - - va_start(vl, string); - { - size_t size = sizeof(log_string) - log_string_length; - - int nchar = vsnprintf(&log_string[log_string_length], size, string, vl); - - NO_LOGGING_ERROR_ON(nchar < 0); - - if ((size_t)nchar >= size) - { - fprintf(stderr, "Truncated log message"); - /* The string was truncated, terminate it properly*/ - log_string[sizeof(log_string) - 1] = '\n'; - log_string_length = sizeof(log_string); - } else - { - log_string_length += (size_t)nchar; - } - } - va_end(vl); - } - - if (config.stdout_tracing || force_stdout) - { - stdio_log(log_string, log_string_length); - } - if (config.file_tracing) - { - file_log(log_string, log_string_length); - } -} - -void trace_no_timestamp(const char *string, ...) -{ - char log_string[512]; - size_t log_string_length = 0; - - if (!config.file_tracing && !config.stdout_tracing) - { - return; - } - - /* Append formated text */ - { - va_list vl; - - va_start(vl, string); - { - size_t size = sizeof(log_string) - log_string_length; - - int nchar = vsnprintf(&log_string[log_string_length], size, string, vl); - - NO_LOGGING_ERROR_ON(nchar < 0); - - if ((size_t)nchar >= size) - { - fprintf(stderr, "Truncated log message"); - /* The string was truncated, terminate it properly*/ - log_string[sizeof(log_string) - 1] = '\n'; - log_string_length = sizeof(log_string); - } else - { - log_string_length += (size_t)nchar; - } - } - va_end(vl); - } - - if (config.stdout_tracing) - { - stdio_log(log_string, log_string_length); - } - if (config.file_tracing) - { - file_log(log_string, log_string_length); - } -} - -static uint16_t byte_to_hex(uint8_t byte) -{ - uint8_t low = byte & 0x0F; - uint8_t high = byte >> 4; - - hex_str.nibble[0] = lut[high]; - hex_str.nibble[1] = lut[low]; - - return hex_str.hex; -} - -void trace_frame(const char *string, const void *buffer, size_t len) -{ - char log_string[4096]; /* Arbitrary size. Large buffer frames will most likely overflow. */ - size_t log_string_length = 0; - uint8_t *frame = (uint8_t *)buffer; - - if ((!config.file_tracing && !config.stdout_tracing) || config.enable_frame_trace == false) - { - return; - } - - /* Append the time stamp */ - { - log_string[log_string_length++] = '['; - - log_string_length += get_time_string(&log_string[log_string_length], sizeof(log_string) - log_string_length); - - log_string[log_string_length++] = ']'; - log_string[log_string_length++] = ' '; - } - - /* Append string up to buffer */ - for (size_t i = 0; string[i] != '\0'; i++) - { - log_string[log_string_length++] = string[i]; - - /* Edge case where the string itself can fill the whole buffer.. */ - if (log_string_length == sizeof(log_string)) - { - /* Flush the buffer */ - if (config.stdout_tracing) - { - stdio_log(log_string, log_string_length); - } - if (config.file_tracing) - { - file_log(log_string, log_string_length); - } - - /* Start at the beginning */ - log_string_length = 0; - } - } - - /* Append hex data */ - for (size_t i = 0; i != len; i++) - { - if (log_string_length >= sizeof(log_string) - sizeof("xx:")) - { - /* Flush the buffer */ - if (config.stdout_tracing) - { - stdio_log(log_string, log_string_length); - } - if (config.file_tracing) - { - file_log(log_string, log_string_length); - } - - /* Start at the beginning */ - log_string_length = 0; - } - - *(uint16_t *)(&log_string[log_string_length]) = byte_to_hex(frame[i]); - log_string_length += sizeof(uint16_t); - log_string[log_string_length++] = ' '; - } - - log_string[log_string_length - 1] = '\n'; - - if (config.stdout_tracing) - { - stdio_log(log_string, log_string_length); - } - if (config.file_tracing) - { - file_log(log_string, log_string_length); - } -} diff --git a/module/cpc/cpcd/utility/logs.h b/module/cpc/cpcd/utility/logs.h deleted file mode 100644 index 490a6e9..0000000 --- a/module/cpc/cpcd/utility/logs.h +++ /dev/null @@ -1,207 +0,0 @@ - - -#ifndef LOGGING_H -#define LOGGING_H - -#include -#include -#include -#include -#include - -/// Struct representing CPC CPCd debug counters. -typedef struct -{ - uint32_t endpoint_opened; - uint32_t endpoint_closed; - uint32_t rxd_frame; - uint32_t txd_reject_destination_unreachable; - uint32_t txd_completed; - uint32_t retxd_data_frame; - uint32_t invalid_header_checksum; - uint32_t invalid_payload_checksum; -} cpc_cpcd_dbg_cts_t; - -void logging_init(void); - -void init_file_logging(); - -void init_stats_logging(void); - -void logging_kill(void); - -void trace(const bool force_stdout, const char *string, ...); - -void trace_no_timestamp(const char *string, ...); - -void trace_frame(const char *string, const void *buffer, size_t len); - -void logging_driver_print_stats(void); - -extern cpc_cpcd_dbg_cts_t primary_cpcd_debug_counters; -extern cpc_cpcd_dbg_cts_t secondary_cpcd_debug_counters; - -#define EVENT_COUNTER_INC(counter) ((primary_cpcd_debug_counters.counter)++) - -#define TRACE(string, ...) do { trace(false, string, ## __VA_ARGS__); } while (0) - -#define TRACE_FORCE_STDOUT(string, ...) do { trace(true, string, ## __VA_ARGS__); } while (0) - -#define PRINT_INFO(string, ...) TRACE_FORCE_STDOUT("Info : " string "\n", ## __VA_ARGS__) - -#define TRACE_HAL(string, ...) TRACE("HAL : " string "\n", ## __VA_ARGS__) - -#define TRACE_CPCD(string, ...) TRACE("CPCd : " string "\n", ## __VA_ARGS__) - -#define TRACE_cpcd_EVENT(event, string, ...) do { EVENT_COUNTER_INC(event); TRACE("CPCd : " string "\n", ## __VA_ARGS__); } while (0) - -#define TRACE_PRIMARY(string, ...) TRACE("PRI : " string "\n", ## __VA_ARGS__) - -#define TRACE_SYSTEM(string, ...) TRACE("SYS : " string "\n", ## __VA_ARGS__) - -#define TRACE_RESET(string, ...) TRACE("Reset Sequence : " string "\n", ## __VA_ARGS__) - -#define trace_lib(string, ...) TRACE("Lib : " string "\n", ## __VA_ARGS__) - -#define TRACE_ASSERT(string, ...) TRACE_FORCE_STDOUT("*** ASSERT *** : " string, ## __VA_ARGS__) - -#define TRACE_WARN(string, ...) TRACE_FORCE_STDOUT("WARNING : " string, ## __VA_ARGS__) - -#define TRACE_FRAME(string, buffer, length) trace_frame(string, buffer, length) - -#define TRACE_cpcd_OPEN_ENDPOINT(ep_id) TRACE_cpcd_EVENT(endpoint_opened, "Open ep #%u", ep_id) - -#define TRACE_cpcd_CLOSE_ENDPOINT(ep_id) TRACE_cpcd_EVENT(endpoint_closed, "Close ep #%u", ep_id) - -#define TRACE_cpcd_RXD_FRAME(buffer, len) do { EVENT_COUNTER_INC(rxd_frame); TRACE_FRAME("CPCd : Rx frame from cpc : ", buffer, len); } while (0) - -#define TRACE_cpcd_TXD_REJECT_DESTINATION_UNREACHABLE() TRACE_cpcd_EVENT(txd_reject_destination_unreachable, "txd reject destination unreachable") - -#define TRACE_cpcd_INVALID_HEADER_CHECKSUM() TRACE_cpcd_EVENT(invalid_header_checksum, "invalid hcs") - -#define TRACE_cpcd_INVALID_PAYLOAD_CHECKSUM() TRACE_cpcd_EVENT(invalid_payload_checksum, "invalid pcs") - -#define TRACE_cpcd_TXD_TRANSMIT_COMPLETED() TRACE_cpcd_EVENT(txd_completed, "txd transmit completed") - -#define TRACE_EP_RXD_DATA_FRAME(ep) TRACE_CPCD("EP #%u: rxd I-frame", ep->id) - -#define TRACE_EP_RXD_DATA_FRAME_QUEUED(ep) TRACE_CPCD("EP #%u: rxd I-frame queued", ep->id) - -#define TRACE_EP_RXD_SFRAME_FRAME(ep) TRACE_CPCD("EP #%u: rxd S-frame", ep->id) - -#define TRACE_EP_RXD_SFRAME_PROCESSED(ep) TRACE_CPCD("EP #%u: rxd S-frame processed", ep->id) - -#define TRACE_EP_RXD_SFRAME_DROPPED(ep) TRACE_CPCD("EP #%u: rxd S-frame dropped", ep->id) - -#define TRACE_EP_RXD_UFRAME_FRAME(ep) TRACE_CPCD("EP #%u: rxd U-frame", ep->id) - -#define TRACE_EP_RXD_UFRAME_DROPPED(ep, reason) TRACE_CPCD("EP #%d: U-frame dropped : %s", ((ep == NULL) ? -1 : (signed)ep->id), reason) - -#define TRACE_EP_RXD_UFRAME_PROCESSED(ep) TRACE_CPCD("EP #%u: U-frame processed", ep->id) - -#define TRACE_EP_RXD_DUPLICATE_DATA_FRAME(ep) TRACE_CPCD("EP #%u: rxd duplicate I-frame", ep->id) - -#define TRACE_EP_RXD_ACK(ep, ack) TRACE_CPCD("EP #%u: rxd ack %u", ep->id, ack) - -#define TRACE_EP_RXD_REJECT_DESTINATION_UNREACHABLE(ep) TRACE_CPCD("EP #%u: rxd reject destination unreachable", ep->id) - -#define TRACE_EP_RXD_REJECT_SEQ_MISMATCH(ep) TRACE_CPCD("EP #%u: rxd reject seq mismatch", ep->id) - -#define TRACE_EP_RXD_REJECT_CHECKSUM_MISMATCH(ep) TRACE_CPCD("EP #%u: rxd reject checksum mismatch", ep->id) - -#define TRACE_EP_RXD_REJECT_SECURITY_ISSUE(ep) TRACE_CPCD("EP #%u: rxd reject security issue", ep->id) - -#define TRACE_EP_RXD_REJECT_OUT_OF_MEMORY(ep) TRACE_CPCD("EP #%u: rxd reject out of memory", ep->id) - -#define TRACE_EP_RXD_REJECT_FAULT(ep) TRACE_CPCD("EP #%u: rxd reject fault", ep->id) - -#define TRACE_EP_TXD_ACK(ep) TRACE_CPCD("EP #%u: txd ack", ep->id) - -#define TRACE_EP_TXD_REJECT_DESTINATION_UNREACHABLE(ep) TRACE_CPCD("EP #%d: txd reject destination unreachable", (ep == NULL) ? -1 : (signed)ep->id) - -#define TRACE_EP_TXD_REJECT_SEQ_MISMATCH(ep) TRACE_CPCD("EP #%u: txd reject seq mismatch", ep->id) - -#define TRACE_EP_TXD_REJECT_CHECKSUM_MISMATCH(ep) TRACE_CPCD("EP #%u: txd reject checksum mismatch", ep->id) - -#define TRACE_EP_TXD_REJECT_SECURITY_ISSUE(ep) TRACE_CPCD("EP #%u: txd reject security issue", ep->id) - -#define TRACE_EP_TXD_REJECT_OUT_OF_MEMORY(ep) TRACE_CPCD("EP #%u: txd reject out of memory", ep->id) - -#define TRACE_EP_TXD_REJECT_FAULT(ep) TRACE_CPCD("EP #%u: txd reject fault", ep->id) - -#define TRACE_EP_RETXD_DATA_FRAME(ep) do { EVENT_COUNTER_INC(retxd_data_frame); TRACE_CPCD("EP #%u: re-txd data frame", ep->id); } while (0) - -#define TRACE_EP_FRAME_TRANSMIT_SUBMITTED(ep) TRACE_CPCD("EP #%d: frame transmit submitted", (ep == NULL) ? -1 : (signed)ep->id) - -#define TRACE_HAL_INVALID_HEADER_CHECKSUM() do { EVENT_COUNTER_INC(invalid_header_checksum); TRACE_HAL("invalid header checksum in driver"); } while (0) - -#define OUT_FILE stderr - -__attribute__((noreturn)) void signal_crash(void); - -#define CRASH() do { signal_crash(); } while (0) - -#define WARN(msg, ...) \ - do { \ - TRACE_WARN("[WARN : %s : %d] " msg "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - fprintf(OUT_FILE, "[WARN : %s : %d] " msg "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - } while (0) - -#define WARN_ON(cond) \ - do { \ - if (cond) { \ - TRACE_WARN("On '%s' in function '%s' in file %s at line #%d\n", #cond, __func__, __FILE__, __LINE__); \ - fprintf(OUT_FILE, "WARNING on '%s' in function '%s' in file %s at line #%d\n", #cond, __func__, __FILE__, __LINE__); \ - } \ - } while (0) - -#define ERROR(msg, ...) \ - do { \ - TRACE_ASSERT("[ERROR : %s : %d] " msg "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - fprintf(OUT_FILE, "[ERROR : %s : %d] " msg "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - CRASH(); \ - } while (0) - -#define ERROR_ON(cond) \ - do { \ - if (cond) { \ - TRACE_ASSERT("[ERROR_%s : %s : %d]\n",#cond, __FILE__, __LINE__); \ - fprintf(OUT_FILE, "[ERROR_%s : %s : %d]\n",#cond, __FILE__, __LINE__); \ - CRASH(); \ - } \ - } while (0) - -#define ERROR_SYSCALL_ON(cond) \ - do { \ - if (cond) { \ - TRACE_ASSERT("[ERROR_SYS : %s : %d]%m\n", __FILE__, __LINE__); \ - fprintf(OUT_FILE, "[ERROR_SYS : %s : %d]%m\n", __FILE__, __LINE__); \ - CRASH(); \ - } \ - } while (0) - -/* Special version used specifically when the trace file hasn't been opened yet (error while creating it) */ -#define FATAL_SYSCALL_NO_TRACE_FILE_ON(cond) \ - do { \ - if (cond) { \ - fprintf(OUT_FILE, "[FATAL_SYS : %s : %d]%m\n", __FILE__, __LINE__); \ - CRASH(); \ - } \ - } while (0) - -#define ASSERT(msg, ...) \ - do { \ - TRACE_ASSERT("[ASSERT : file %s : %d : " msg "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - fprintf(OUT_FILE, "[ASSERT : file %s : %d : " msg "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - CRASH(); \ - } while (0) - -#define ASSERT_ON(cond) \ - do { \ - if (cond) { \ - TRACE_ASSERT("ASSERT_%s : %s : %d\n",#cond, __FILE__, __LINE__); \ - fprintf(OUT_FILE, "ASSERT_%s : %s : %d\n",#cond, __FILE__, __LINE__); \ - CRASH(); \ - } \ - } while (0) -#endif //TRACING_H diff --git a/module/cpc/cpcd/utility/sleep.c b/module/cpc/cpcd/utility/sleep.c deleted file mode 100644 index 43fe342..0000000 --- a/module/cpc/cpcd/utility/sleep.c +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file sleep.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-10-30 - * - * - */ - -#include "sleep.h" - -#include -#include - - -int sleep_us(uint32_t us) -{ - int ret; - struct timespec ts; - - if (us < 1000000) - { - ts.tv_sec = 0; - ts.tv_nsec = (long)(us * 1000); - } else - { - ts.tv_sec = (time_t)(us / 1000000); - ts.tv_nsec = (long)((us % 1000000) * 1000); - } - do - { - ret = nanosleep(&ts, &ts); - } while (ret != 0 && errno == EINTR); - return ret; -} - -int sleep_s(uint32_t s) -{ - int ret; - struct timespec ts; - - ts.tv_sec = (time_t)s; - ts.tv_nsec = 0; - do - { - ret = nanosleep(&ts, &ts); - } while (ret != 0 && errno == EINTR); - return ret; -} diff --git a/module/cpc/cpcd/utility/sleep.h b/module/cpc/cpcd/utility/sleep.h deleted file mode 100644 index b5a3181..0000000 --- a/module/cpc/cpcd/utility/sleep.h +++ /dev/null @@ -1,17 +0,0 @@ - - -#ifndef SLEEP_H -#define SLEEP_H - -#include - -int sleep_us(uint32_t us); - -static inline int sleep_ms(uint32_t ms) -{ - return sleep_us(ms * 1000); -} - -int sleep_s(uint32_t s); - -#endif /* SLEEP_H */ diff --git a/module/cpc/cpcd/utility/slist.c b/module/cpc/cpcd/utility/slist.c deleted file mode 100644 index 86a55eb..0000000 --- a/module/cpc/cpcd/utility/slist.c +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file slist.c - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-08-03 - * - * @copyright Copyright (c) 2023 - * - */ - - -#include "slist.h" -#include -#include -#include -#include - - -void slist_init(slist_node_t **head) -{ - *head = 0; -} - - -void slist_push(slist_node_t **head, - slist_node_t *item) -{ - item->node = *head; - *head = item; -} - -void slist_push_back(slist_node_t **head, - slist_node_t *item) -{ - slist_node_t **node_ptr = head; - - while (*node_ptr != NULL) - { - node_ptr = &((*node_ptr)->node); - } - - item->node = NULL; - *node_ptr = item; -} - -slist_node_t *slist_pop(slist_node_t **head) -{ - slist_node_t *item; - - item = *head; - if (item == NULL) - { - return(NULL); - } - - *head = item->node; - - item->node = NULL; - - return(item); -} - - -void slist_insert(slist_node_t *item, - slist_node_t *pos) -{ - item->node = pos->node; - pos->node = item; -} - -void slist_remove(slist_node_t **head, - slist_node_t *item) -{ - slist_node_t **node_ptr; - - for (node_ptr = head; *node_ptr != NULL; node_ptr = &((*node_ptr)->node)) - { - if (*node_ptr == item) - { - *node_ptr = item->node; - return; - } - } -} - -void slist_sort(slist_node_t **head, - bool (*cmp_fnct)(slist_node_t *item_l, - slist_node_t *item_r)) -{ - bool swapped; - slist_node_t **pp_item_l; - - do - { - swapped = false; - - pp_item_l = head; - // Loop until end of list is found. - while ((*pp_item_l != NULL) && ((*pp_item_l)->node != NULL)) - { - slist_node_t *p_item_r = (*pp_item_l)->node; - bool ordered; - - // Call provided compare fnct. - ordered = cmp_fnct(*pp_item_l, p_item_r); - if (ordered == false) - { - // If order is not correct, swap items. - slist_node_t *p_tmp = p_item_r->node; - - // Swap the two items. - p_item_r->node = *pp_item_l; - (*pp_item_l)->node = p_tmp; - *pp_item_l = p_item_r; - pp_item_l = &(p_item_r->node); - // Indicate a swap has been done. - swapped = true; - } else - { - pp_item_l = &((*pp_item_l)->node); - } - } - // Re-loop until no items have been swapped. - } while (swapped == true); -} diff --git a/module/cpc/cpcd/utility/slist.h b/module/cpc/cpcd/utility/slist.h deleted file mode 100644 index c3695fb..0000000 --- a/module/cpc/cpcd/utility/slist.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file slist.h - * @author Rex Huang (rex.huang@rafaelmicro.com) - * @brief - * @version 0.1 - * @date 2023-08-03 - * - * @copyright Copyright (c) 2023 - * - */ - -#ifndef SLIST_H -#define SLIST_H - -#include -#include -#include - -/// List node type -typedef struct slist_node slist_node_t; - -/// List node -struct slist_node -{ - slist_node_t *node; ///< List node -}; - -#ifndef DOXYGEN -#define container_of(ptr, type, member) (type *)((uintptr_t)(ptr) - ((uintptr_t)(&((type *)0)->member))) - -#define SLIST_ENTRY container_of - -#define SLIST_FOR_EACH(slist_head, iterator) for ((iterator) = (slist_head); (iterator) != NULL; (iterator) = (iterator)->node) - -#define SLIST_FOR_EACH_ENTRY(slist_head, entry, type, member) for ((entry) = SLIST_ENTRY(slist_head, type, member); \ - (type *)(entry) != SLIST_ENTRY(NULL, type, member); \ - (entry) = SLIST_ENTRY((entry)->member.node, type, member)) -#endif - -void slist_init(slist_node_t **head); - -void slist_push(slist_node_t **head, slist_node_t *item); - -void slist_push_back(slist_node_t **head, slist_node_t *item); - -slist_node_t *slist_pop(slist_node_t **head); - -void slist_insert(slist_node_t *item, slist_node_t *pos); - -void slist_remove(slist_node_t **head, slist_node_t *item); - -void slist_sort(slist_node_t **head, bool (*cmp_fnct)(slist_node_t *item_l, slist_node_t *item_r)); - -#endif /* SLIST_H */ diff --git a/module/cpc/cpcd/utility/status.h b/module/cpc/cpcd/utility/status.h deleted file mode 100644 index 7d66771..0000000 --- a/module/cpc/cpcd/utility/status.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef STATUS_H -#define STATUS_H - -#include - -typedef enum -{ - STATUS_OK = 0, - STATUS_FAIL, - STATUS_IN_PROGRESS = 5, - STATUS_ABORT, - STATUS_TIMEOUT, - STATUS_WOULD_BLOCK = 9, -}E_STATUS; - -typedef uint32_t status_t; - -#endif /* STATUS_H */ diff --git a/module/cpc/cpcd/utility/utils.c b/module/cpc/cpcd/utility/utils.c deleted file mode 100644 index 1a35f64..0000000 --- a/module/cpc/cpcd/utility/utils.c +++ /dev/null @@ -1,82 +0,0 @@ - -#include - -#include "utility/utils.h" -#include "utility/logs.h" - -int recursive_mkdir(const char *dir, size_t len, const mode_t mode) -{ - char *tmp = NULL; - char *p = NULL; - struct stat sb; - int ret; - - tmp = (char *)calloc_port(len + 1); - ERROR_ON(tmp == NULL); - - /* copy path */ - ret = snprintf(tmp, len + 1, "%s", dir); - ERROR_ON(ret < 0 || (size_t)ret >= (len + 1)); - - /* remove trailing slash */ - if (tmp[len - 1] == '/') - { - tmp[len - 1] = '\0'; - } - - /* check if path exists and is a directory */ - if (stat(tmp, &sb) == 0) - { - if (S_ISDIR(sb.st_mode)) - { - goto return_ok; - } - } - - /* recursive mkdir */ - for (p = tmp + 1; *p; p++) - { - if (*p == '/') - { - *p = 0; - /* test path */ - if (stat(tmp, &sb) != 0) - { - /* path does not exist - create directory */ - if (mkdir(tmp, mode) < 0) - { - goto return_err; - } - } else if (!S_ISDIR(sb.st_mode)) - { - /* not a directory */ - goto return_err; - } - *p = '/'; - } - } - - /* test path */ - if (stat(tmp, &sb) != 0) - { - /* path does not exist - create directory */ - if (mkdir(tmp, mode) < 0) - { - goto return_err; - } - } else if (!S_ISDIR(sb.st_mode)) - { - /* not a directory */ - goto return_err; - } - - /* Fall through to return_ok */ - - return_ok: - free(tmp); - return 0; - - return_err: - free(tmp); - return -1; -} diff --git a/module/cpc/cpcd/utility/utils.h b/module/cpc/cpcd/utility/utils.h deleted file mode 100644 index a1da69b..0000000 --- a/module/cpc/cpcd/utility/utils.h +++ /dev/null @@ -1,21 +0,0 @@ - - -#ifndef UTILS_H -#define UTILS_H - -#include -#include - -#define SIZEOF_MEMBER(T, m) (sizeof(((T *)0)->m)) -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -#define PAD_TO_8_BYTES(x) (x + 8 - (x % 8)) - -static inline void *calloc_port(size_t size) -{ - return calloc(1, size); -} - -int recursive_mkdir(const char *dir, size_t len, const mode_t mode); - -#endif diff --git a/module/subg/CMakeLists.txt b/module/subg/CMakeLists.txt index db2b440..b7fc3d0 100644 --- a/module/subg/CMakeLists.txt +++ b/module/subg/CMakeLists.txt @@ -1 +1,21 @@ -ext_add_subdirectory(cpc-subg) +add_executable(ezmesh-subg main.c) +target_link_libraries(ezmesh-subg ezmesh util pthread) + +get_target_property(EZMESH_SOURCE_DIR ezmesh SOURCE_DIR) +target_include_directories(ezmesh-subg PRIVATE ${EZMESH_SOURCE_DIR}/library) + +ext_install( "TARGET_RUNTIME" ezmesh-subg "bin" ezmesh-subg) + +# set(DEFAULT_EZMESH_ZBGW_INSTALL_PATH /var/lib/ezmesh-subg) +# set(DEFAULT_EZMESHD_SERVICE_PATH /lib/systemd/system) +# if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) +# install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_ZBGW_INSTALL_PATH} COMPONENT ezmesh-subg) +# set(EZMESHD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESHD_SERVICE_PATH}) +# set(EZMESH_ZBGW_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_ZBGW_INSTALL_PATH}) +# else() +# install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_ZBGW_INSTALL_PATH} COMPONENT ezmesh-subg) +# set(EZMESHD_SERVICE_PATH ${DEFAULT_EZMESHD_SERVICE_PATH}) +# set(EZMESH_ZBGW_SERVICE_PATH ${DEFAULT_EZMESH_ZBGW_INSTALL_PATH}) +# endif() + +# ext_install("EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/ezmesh-subg ${EZMESH_ZBGW_SERVICE_PATH} ezmesh-subg) diff --git a/module/subg/cpc-subg/CMakeLists.txt b/module/subg/cpc-subg/CMakeLists.txt deleted file mode 100644 index 9664d0f..0000000 --- a/module/subg/cpc-subg/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -add_executable(cpc-subg - src/main.c - ) -target_link_libraries(cpc-subg - cpc - util - pthread -) - -get_target_property(CPC_SOURCE_DIR cpc SOURCE_DIR) -target_include_directories(cpc-subg PRIVATE ${CPC_SOURCE_DIR}/lib) - -ext_install( "TARGET_RUNTIME" cpc-subg "bin" cpc-subg) - -set(DEFAULT_CPC_ZBGW_INSTALL_PATH /var/lib/cpc-subg) -set(DEFAULT_CPCD_SERVICE_PATH /lib/systemd/system) -if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_ZBGW_INSTALL_PATH} COMPONENT cpc-subg) - set(CPCD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_ZBGW_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_ZBGW_INSTALL_PATH}) -else() - install(DIRECTORY DESTINATION ${DEFAULT_CPC_ZBGW_INSTALL_PATH} COMPONENT cpc-subg) - set(CPCD_SERVICE_PATH ${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_ZBGW_SERVICE_PATH ${DEFAULT_CPC_ZBGW_INSTALL_PATH}) -endif() - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/cpc-subg - ${CPC_ZBGW_SERVICE_PATH} - cpc-subg -) diff --git a/module/subg/cpc-subg/src/main.c b/module/subg/main.c similarity index 69% rename from module/subg/cpc-subg/src/main.c rename to module/subg/main.c index 2f9fe81..c50416b 100644 --- a/module/subg/cpc-subg/src/main.c +++ b/module/subg/main.c @@ -1,4 +1,4 @@ -#include "libcpc.h" +#include "libezmesh.h" #include #include #include @@ -9,26 +9,26 @@ #include #include -#define LOG_TAG "cpc-bluetooth" +#define LOG_TAG "ezmesh-bluetooth" -#define TO_CPC_BUF_SIZE 400 -#define FROM_CPC_BUF_SIZE LIB_CPC_READ_MINIMUM_SIZE +#define TO_EZMESH_BUF_SIZE 400 +#define FROM_EZMESH_BUF_SIZE LIB_EZMESH_READ_MINIMUM_SIZE #define INST_NAME_LEN 100 #define RETRY_COUNT 10 -#define CPC_RETRY_SLEEP_NS 100000000L -#define CPC_RESET_SLEEP_NS 10000L +#define EZMESH_RETRY_SLEEP_NS 100000000L +#define EZMESH_RESET_SLEEP_NS 10000L #define THREAD_SLEEP_NS 1000000L -#define CPC_TRANSMIT_WINDOW 1 +#define EZMESH_TRANSMIT_WINDOW 1 #define SYMLINK_PATH "pts_subg" -// cpc related structures -static cpc_handle_t lib_handle; -static cpc_ep_t endpoint; +// ezmesh related structures +static ezmesh_handle_t lib_handle; +static ezmesh_ep_t endpoint; // tx/rx buffers -static uint8_t data_to_cpc[TO_CPC_BUF_SIZE]; -static uint8_t data_from_cpc[FROM_CPC_BUF_SIZE]; -// cpc instance name -static char cpc_instance[INST_NAME_LEN]; +static uint8_t data_to_ezmesh[TO_EZMESH_BUF_SIZE]; +static uint8_t data_from_ezmesh[FROM_EZMESH_BUF_SIZE]; +// ezmesh instance name +static char ezmesh_instance[INST_NAME_LEN]; static int pty_m; static int pty_s; @@ -45,8 +45,8 @@ static pthread_t thread_rx; static pthread_t thread_tx; // Static receive function -static void *cpc_to_pty_func(void *ptr); -static void *pty_to_cpc_func(void *ptr); +static void *ezmesh_to_pty_func(void *ptr); +static void *pty_to_ezmesh_func(void *ptr); // Custom signal handler. static void signal_handler(int sig) @@ -56,39 +56,39 @@ static void signal_handler(int sig) } /**************************************************************************//** - * Starts CPC and pty. + * Starts EZMESH and pty. *****************************************************************************/ uint32_t startup(void) { int ret; uint8_t retry = 0; - // Initialize CPC communication + // Initialize EZMESH communication do { - ret = libcpc_init(&lib_handle, cpc_instance, reset_cb); + ret = libezmesh_init(&lib_handle, ezmesh_instance, reset_cb); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); if (ret < 0) { - perror("cpc_init: "); + perror("ezmesh_init: "); return ret; } - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_USER_ID_1, - CPC_TRANSMIT_WINDOW); + EP_USER_ID_1, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { - perror("cpc_open_ep "); + perror("ezmesh_open_ep "); return ret; } printf("Endpoint opened\n"); @@ -126,9 +126,9 @@ static void reset_cb(void) } /**************************************************************************//** - * Reset CPC communication after other end restarted. + * Reset EZMESH communication after other end restarted. *****************************************************************************/ -int reset_cpc(void) +int reset_ezmesh(void) { int ret; uint8_t retry = 0; @@ -138,28 +138,28 @@ int reset_cpc(void) // Restart cpp communication do { - ret = libcpc_reset(&lib_handle); + ret = libezmesh_reset(&lib_handle); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); has_reset = false; if (ret < 0) { - perror("cpc restart "); + perror("ezmesh restart "); return ret; } // Open Bluetooth endpoint - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_USER_ID_1, - CPC_TRANSMIT_WINDOW); + EP_USER_ID_1, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { perror(" open endpoint "); @@ -203,50 +203,50 @@ int main(int argc, char *argv[]) // Set device unique name if different from default if (argc > 1) { - strcpy(cpc_instance, argv[1]); + strcpy(ezmesh_instance, argv[1]); } else { - strcpy(cpc_instance, "cpcd_0"); + strcpy(ezmesh_instance, "ezmeshd_1"); } - // Start CPC and PTY communication + // Start EZMESH and PTY communication if (startup() < 0) { exit(EXIT_FAILURE); } // Creating receiving working threads - ret = pthread_create(&thread_rx, NULL, cpc_to_pty_func, NULL); + ret = pthread_create(&thread_rx, NULL, ezmesh_to_pty_func, NULL); if (ret) { exit(EXIT_FAILURE); } - ret = pthread_create(&thread_tx, NULL, pty_to_cpc_func, NULL); + ret = pthread_create(&thread_tx, NULL, pty_to_ezmesh_func, NULL); if (ret) { exit(EXIT_FAILURE); } - // Reset cpc communication if daemon signals + // Reset ezmesh communication if daemon signals while (run) { if (has_reset) { - ret = reset_cpc(); + ret = reset_ezmesh(); if (ret < 0) { perror("reset "); exit(EXIT_FAILURE); } } - nanosleep((const struct timespec[]){{ 0, CPC_RESET_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RESET_SLEEP_NS } }, NULL); } } /**************************************************************************//** - * Working thread from CPCd + * Working thread from EZMESHd *****************************************************************************/ -void *cpc_to_pty_func(void *ptr) +void *ezmesh_to_pty_func(void *ptr) { ssize_t size = 0; @@ -255,14 +255,14 @@ void *cpc_to_pty_func(void *ptr) while (run) { - // Read data from cpc - size = libcpc_read_ep(endpoint, - &data_from_cpc[0], - FROM_CPC_BUF_SIZE, - CPC_EP_READ_FLAG_NON_BLOCKING); + // Read data from ezmesh + size = libezmesh_read_ep(endpoint, + &data_from_ezmesh[0], + FROM_EZMESH_BUF_SIZE, + EP_READ_FLAG_NON_BLOCKING); if (size > 0) { - if (write(pty_m, &data_from_cpc[0], size) == -1) + if (write(pty_m, &data_from_ezmesh[0], size) == -1) { perror("write error "); } @@ -279,17 +279,17 @@ void *cpc_to_pty_func(void *ptr) printf("\n"); } - printf(" %02X", data_from_cpc[i]); + printf(" %02X", data_from_ezmesh[i]); } printf("\n\n"); - memset(&data_from_cpc[0], 0, FROM_CPC_BUF_SIZE); + memset(&data_from_ezmesh[0], 0, FROM_EZMESH_BUF_SIZE); } else if (has_reset) { // intentionally left blank } else if (errno != EAGAIN && errno != ECONNRESET) { - perror("cpc_to_pty_func error "); + perror("ezmesh_to_pty_func error "); exit(-1); } nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); @@ -298,9 +298,9 @@ void *cpc_to_pty_func(void *ptr) } /**************************************************************************//** - * Working thread to CPCd + * Working thread to EZMESHd *****************************************************************************/ -void *pty_to_cpc_func(void *ptr) +void *pty_to_ezmesh_func(void *ptr) { ssize_t size = 0; unsigned int d_len = 0; @@ -311,7 +311,7 @@ void *pty_to_cpc_func(void *ptr) while (run) { // Read data from pty - size = read(pty_m, &data_to_cpc[d_len], TO_CPC_BUF_SIZE); + size = read(pty_m, &data_to_ezmesh[d_len], TO_EZMESH_BUF_SIZE); if (size > 0) { printf("w-> %ld\n", size); @@ -325,17 +325,17 @@ void *pty_to_cpc_func(void *ptr) printf("\n"); } - printf(" %02X", data_to_cpc[i+d_len]); + printf(" %02X", data_to_ezmesh[i+d_len]); } printf("\n\n"); d_len += size; - if (data_to_cpc[d_len-1] == 0x0D) + if (data_to_ezmesh[d_len-1] == 0x0D) { - libcpc_write_ep(endpoint, &data_to_cpc[0], d_len, 0); - memset(&data_to_cpc[0], 0, TO_CPC_BUF_SIZE); + libezmesh_write_ep(endpoint, &data_to_ezmesh[0], d_len, 0); + memset(&data_to_ezmesh[0], 0, TO_EZMESH_BUF_SIZE); d_len = 0; } } else if (has_reset) @@ -343,7 +343,7 @@ void *pty_to_cpc_func(void *ptr) // intentionally left blank } else if (errno != EAGAIN && errno != ECONNRESET) { - perror("pty_to_cpc_func error"); + perror("pty_to_ezmesh_func error"); exit(-1); } nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); diff --git a/module/upgrade/CMakeLists.txt b/module/upgrade/CMakeLists.txt new file mode 100644 index 0000000..ab8766c --- /dev/null +++ b/module/upgrade/CMakeLists.txt @@ -0,0 +1,21 @@ +add_executable(ezmesh-upgrade src/ezmesh-upgrade.c src/fsm.c) +target_link_libraries(ezmesh-upgrade + ezmesh + util + pthread +) + +get_target_property(EZMESH_SOURCE_DIR ezmesh SOURCE_DIR) +target_include_directories(ezmesh-upgrade PRIVATE + ${EZMESH_SOURCE_DIR}/library + src/include +) + +ext_install( "TARGET_RUNTIME" ezmesh-upgrade "bin" ezmesh-upgrade) + +# set(DEFAULT_EZMESH_INSTALL_PATH /var/lib/ezmesh) +# if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) +# install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_INSTALL_PATH} COMPONENT ezmesh-upgrade) +# else() +# install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_INSTALL_PATH} COMPONENT ezmesh-upgrade) +# endif() \ No newline at end of file diff --git a/module/cpc/cpcd-system/src/upgrade/cpc-upgrade.c b/module/upgrade/src/ezmesh-upgrade.c similarity index 84% rename from module/cpc/cpcd-system/src/upgrade/cpc-upgrade.c rename to module/upgrade/src/ezmesh-upgrade.c index 2ed87e8..4f8c6ec 100644 --- a/module/cpc/cpcd-system/src/upgrade/cpc-upgrade.c +++ b/module/upgrade/src/ezmesh-upgrade.c @@ -1,4 +1,4 @@ -#include "libcpc.h" +#include "libezmesh.h" #include "fsm.h" #include #include @@ -10,13 +10,13 @@ #include #include -#define FROM_CPC_BUF_SIZE LIB_CPC_READ_MINIMUM_SIZE +#define FROM_EZMESH_BUF_SIZE LIB_EZMESH_READ_MINIMUM_SIZE #define INST_NAME_LEN 100 #define RETRY_COUNT 10 -#define CPC_RETRY_SLEEP_NS 100000000L -#define CPC_RESET_SLEEP_NS 10000L +#define EZMESH_RETRY_SLEEP_NS 100000000L +#define EZMESH_RESET_SLEEP_NS 10000L #define THREAD_SLEEP_NS 1000000L -#define CPC_TRANSMIT_WINDOW 1 +#define EZMESH_TRANSMIT_WINDOW 1 #define DW_REQ_FIXED_LEN 35 #define DW_REQ_PER_PKT_LEN 255 @@ -134,13 +134,13 @@ static size_t file_size = 0, total_pkt = 0; static size_t g_pkt_size = 0x160; static int current_pkt = 0; static bool cnt_check = 0; -// cpc related structures -static cpc_handle_t lib_handle; -static cpc_ep_t endpoint; +// ezmesh related structures +static ezmesh_handle_t lib_handle; +static ezmesh_ep_t endpoint; // tx/rx buffers -static uint8_t data_from_cpc[FROM_CPC_BUF_SIZE]; -// cpc instance name -static char cpc_instance[INST_NAME_LEN]; +static uint8_t data_from_ezmesh[FROM_EZMESH_BUF_SIZE]; +// ezmesh instance name +static char ezmesh_instance[INST_NAME_LEN]; static int pty_m; static int pty_s; @@ -213,7 +213,7 @@ static void a_send_clear(void *p_data) { 0xFF, 0xFC, 0xFC, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x08 }; - libcpc_write_ep(endpoint, &fw_clear_request_cmd[0], sizeof(fw_clear_request_cmd), 0); + libezmesh_write_ep(endpoint, &fw_clear_request_cmd[0], sizeof(fw_clear_request_cmd), 0); } static void a_send_image(void *p_data) @@ -253,7 +253,7 @@ static void a_send_image(void *p_data) pkt_len += DW_REQ_FIXED_LEN; - libcpc_write_ep(endpoint, &ota_download_request_cmd[0], pkt_len, 0); + libezmesh_write_ep(endpoint, &ota_download_request_cmd[0], pkt_len, 0); printf("------------------------ >>>> GW ------------------------\n"); _log_mem(" ", ota_download_request_cmd, pkt_len); @@ -281,7 +281,7 @@ static void a_send_image(void *p_data) pkt_len = DW_REQ_FIXED_LEN + g_pkt_size; - libcpc_write_ep(endpoint, &ota_download_request_cmd[0], pkt_len, 0); + libezmesh_write_ep(endpoint, &ota_download_request_cmd[0], pkt_len, 0); printf("------------------------ >>>> GW ------------------------\n"); _log_mem(" ", ota_download_request_cmd, pkt_len); @@ -297,43 +297,43 @@ static void a_send_active(void *p_data) fw_active_cmd[12] = _gateway_checksum_calc(&fw_active_cmd[4], 8); - libcpc_write_ep(endpoint, &fw_active_cmd[0], sizeof(fw_active_cmd), 0); + libezmesh_write_ep(endpoint, &fw_active_cmd[0], sizeof(fw_active_cmd), 0); } /**************************************************************************/ /** - * Starts CPC and pty. + * Starts EZMESH and pty. *****************************************************************************/ uint32_t startup(void) { int ret; uint8_t retry = 0; - // Initialize CPC communication + // Initialize EZMESH communication do { - ret = libcpc_init(&lib_handle, cpc_instance, reset_cb); + ret = libezmesh_init(&lib_handle, ezmesh_instance, reset_cb); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); if (ret < 0) { - perror("cpc_init: "); + perror("ezmesh_init: "); return ret; } - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_USER_ID_0, - CPC_TRANSMIT_WINDOW); + EP_USER_ID_0, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { - perror("cpc_open_ep "); + perror("ezmesh_open_ep "); return ret; } printf("Endpoint opened\n"); @@ -350,9 +350,9 @@ static void reset_cb(void) } /**************************************************************************/ /** - * Reset CPC communication after other end restarted. + * Reset EZMESH communication after other end restarted. *****************************************************************************/ -int reset_cpc(void) +int reset_ezmesh(void) { int ret; uint8_t retry = 0; @@ -362,20 +362,20 @@ int reset_cpc(void) // Restart cpp communication do { - ret = libcpc_reset(&lib_handle); + ret = libezmesh_reset(&lib_handle); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); has_reset = false; if (ret < 0) { - perror("cpc restart "); + perror("ezmesh restart "); return ret; } @@ -383,10 +383,10 @@ int reset_cpc(void) return ret; // Open Bluetooth endpoint - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_USER_ID_0, - CPC_TRANSMIT_WINDOW); + EP_USER_ID_0, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { perror(" open endpoint "); @@ -409,10 +409,10 @@ int main(int argc, char *argv[]) if (argc > 2) { - strcpy(cpc_instance, argv[2]); + strcpy(ezmesh_instance, argv[2]); } else { - strcpy(cpc_instance, "cpcd_0"); + strcpy(ezmesh_instance, "ezmeshd_0"); } fp = fopen(argv[1], "rb"); @@ -429,7 +429,7 @@ int main(int argc, char *argv[]) printf("Image : %s size %ld, Total Pkt %ld\n", argv[1], file_size, total_pkt); fsm_init(&upgrade_fsm, &upgrade_fsm_descriptor); - // Start CPC and PTY communication + // Start EZMESH and PTY communication if (startup() < 0) { exit(EXIT_FAILURE); @@ -444,26 +444,26 @@ int main(int argc, char *argv[]) fsm_event_post(&upgrade_fsm, E_UPGRADE_START, NULL); - // Reset cpc communication if daemon signals + // Reset ezmesh communication if daemon signals while (run) { if (has_reset) { - ret = reset_cpc(); + ret = reset_ezmesh(); if (ret < 0) { perror("reset "); exit(EXIT_FAILURE); } } - nanosleep((const struct timespec[]){{ 0, CPC_RESET_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RESET_SLEEP_NS } }, NULL); } return upg_complete; } /**************************************************************************/ /** - * Working thread from CPCd + * Working thread from EZMESHd *****************************************************************************/ void *rx_handler(void *ptr) { @@ -477,14 +477,14 @@ void *rx_handler(void *ptr) while (run) { - // Read data from cpc - size = libcpc_read_ep(endpoint, - &data_from_cpc[0], - FROM_CPC_BUF_SIZE, - CPC_EP_READ_FLAG_NON_BLOCKING); + // Read data from ezmesh + size = libezmesh_read_ep(endpoint, + &data_from_ezmesh[0], + FROM_EZMESH_BUF_SIZE, + EP_READ_FLAG_NON_BLOCKING); if (size > 0) { - pt_pd = (gateway_cmd_pd *)&data_from_cpc[5]; + pt_pd = (gateway_cmd_pd *)&data_from_ezmesh[5]; cmd_index = pt_pd->command_id; if (cmd_index == 0xF0008000) @@ -518,14 +518,14 @@ void *rx_handler(void *ptr) upg_complete = 0; } - memset(&data_from_cpc[0], 0, FROM_CPC_BUF_SIZE); + memset(&data_from_ezmesh[0], 0, FROM_EZMESH_BUF_SIZE); } else { timeout++; if (timeout >= 10000) { timeout = 1; - reset_cpc(); + reset_ezmesh(); // fsm_event_post(&upgrade_fsm, E_UPGRADE_FILE_DOWNLOAD, NULL); } } @@ -533,4 +533,3 @@ void *rx_handler(void *ptr) } return NULL; } - diff --git a/module/cpc/cpcd-system/src/upgrade/fsm.c b/module/upgrade/src/fsm.c similarity index 100% rename from module/cpc/cpcd-system/src/upgrade/fsm.c rename to module/upgrade/src/fsm.c diff --git a/module/cpc/cpcd-system/src/upgrade/include/fsm.h b/module/upgrade/src/include/fsm.h similarity index 100% rename from module/cpc/cpcd-system/src/upgrade/include/fsm.h rename to module/upgrade/src/include/fsm.h diff --git a/module/cpc/cpcd-system/src/upgrade/include/fsm_assist.h b/module/upgrade/src/include/fsm_assist.h similarity index 100% rename from module/cpc/cpcd-system/src/upgrade/include/fsm_assist.h rename to module/upgrade/src/include/fsm_assist.h diff --git a/module/zigbee/CMakeLists.txt b/module/zigbee/CMakeLists.txt index 5fc2b3b..5344540 100644 --- a/module/zigbee/CMakeLists.txt +++ b/module/zigbee/CMakeLists.txt @@ -1 +1,2 @@ -ext_add_subdirectory(cpc-zbgw) +ext_add_subdirectory(ezmesh-zbgw) +ext_add_subdirectory(ezmesh-zbbackup) \ No newline at end of file diff --git a/module/zigbee/cpc-zbgw/CMakeLists.txt b/module/zigbee/cpc-zbgw/CMakeLists.txt deleted file mode 100644 index b86988b..0000000 --- a/module/zigbee/cpc-zbgw/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -add_executable(cpc-zbgw - src/main.c - src/Queue.c - src/C2S.c - src/S2C.c - src/server.c - src/system.c - src/coordinator.c - src/M2Z.c - src/Z2M.c - ) -target_link_libraries(cpc-zbgw - cpc - util - pthread -) - -get_target_property(CPC_SOURCE_DIR cpc SOURCE_DIR) -target_include_directories(cpc-zbgw PRIVATE ${CPC_SOURCE_DIR}/lib) - -ext_install( "TARGET_RUNTIME" cpc-zbgw "bin" cpc-zbgw) - -set(DEFAULT_CPC_ZBGW_INSTALL_PATH /var/lib/cpc-zbgw) -set(DEFAULT_CPCD_SERVICE_PATH /lib/systemd/system) -if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_ZBGW_INSTALL_PATH} COMPONENT cpc-zbgw) - set(CPCD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_ZBGW_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_CPC_ZBGW_INSTALL_PATH}) -else() - install(DIRECTORY DESTINATION ${DEFAULT_CPC_ZBGW_INSTALL_PATH} COMPONENT cpc-zbgw) - set(CPCD_SERVICE_PATH ${DEFAULT_CPCD_SERVICE_PATH}) - set(CPC_ZBGW_SERVICE_PATH ${DEFAULT_CPC_ZBGW_INSTALL_PATH}) -endif() - -ext_install( - "EXECUTE" - ${CMAKE_CURRENT_BINARY_DIR}/cpc-zbgw - ${CPC_ZBGW_SERVICE_PATH} - cpc-zbgw -) - -ext_install( - "DIRECTORY" - zbdb - ${CPC_ZBGW_SERVICE_PATH} - cpc-zbgw -) - -if(CPCD_LOCATION) - # Install configuration file - ext_install( - "FILE" ${CPCD_LOCATION}/etc/cpcd.conf - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} - cpcd) -else() - # Install binaries they come from custom target build_cpcd - ext_install( - "TARGET_HEADER" cpc - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} - cpc-zbgw - ) -endif() diff --git a/module/zigbee/ezmesh-zbbackup/CMakeLists.txt b/module/zigbee/ezmesh-zbbackup/CMakeLists.txt new file mode 100644 index 0000000..822c178 --- /dev/null +++ b/module/zigbee/ezmesh-zbbackup/CMakeLists.txt @@ -0,0 +1,17 @@ +add_executable(ezmesh-zbbackup src/ezmesh-zbbackup.c src/fsm.c) +target_link_libraries(ezmesh-zbbackup ezmesh util pthread) + +get_target_property(EZMESH_SOURCE_DIR ezmesh SOURCE_DIR) +target_include_directories(ezmesh-zbbackup PRIVATE + ${EZMESH_SOURCE_DIR}/library + src/include +) + +ext_install("TARGET_RUNTIME" ezmesh-zbbackup "bin" ezmesh-zbbackup) + +# set(DEFAULT_EZMESH_ZBBU_INSTALL_PATH /var/lib/ezmesh-zbbackup) +# if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) +# install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_ZBBU_INSTALL_PATH} COMPONENT ezmesh-zbbackup) +# else() +# install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_ZBBU_INSTALL_PATH} COMPONENT ezmesh-zbbackup) +# endif() \ No newline at end of file diff --git a/module/cpc/cpcd-system/src/zbbackup/cpc-zbbackup.c b/module/zigbee/ezmesh-zbbackup/src/ezmesh-zbbackup.c similarity index 83% rename from module/cpc/cpcd-system/src/zbbackup/cpc-zbbackup.c rename to module/zigbee/ezmesh-zbbackup/src/ezmesh-zbbackup.c index c57887c..a89ef19 100644 --- a/module/cpc/cpcd-system/src/zbbackup/cpc-zbbackup.c +++ b/module/zigbee/ezmesh-zbbackup/src/ezmesh-zbbackup.c @@ -1,4 +1,4 @@ -#include "libcpc.h" +#include "libezmesh.h" #include "fsm.h" #include #include @@ -10,13 +10,13 @@ #include #include -#define FROM_CPC_BUF_SIZE LIB_CPC_READ_MINIMUM_SIZE +#define FROM_EZMESH_BUF_SIZE LIB_EZMESH_READ_MINIMUM_SIZE #define INST_NAME_LEN 100 #define RETRY_COUNT 10 -#define CPC_RETRY_SLEEP_NS 100000000L -#define CPC_RESET_SLEEP_NS 10000L +#define EZMESH_RETRY_SLEEP_NS 100000000L +#define EZMESH_RESET_SLEEP_NS 10000L #define THREAD_SLEEP_NS 1000000L -#define CPC_TRANSMIT_WINDOW 1 +#define EZMESH_TRANSMIT_WINDOW 1 static void a_page_read(void *p_data); static void a_finish(void *p_data); @@ -33,7 +33,7 @@ typedef struct __attribute__((packed)) } gateway_cmd_pd; -#define EVENT_LIST E_START, \ +#define EVENT_LIST E_START, \ E_PAGE_READ, \ E_WRITE_START,\ E_WRITE, \ @@ -133,13 +133,13 @@ static fsm_t flashctl_fsm; static FILE *fp; static FILE *fp_zbaddr; -// cpc related structures -static cpc_handle_t lib_handle; -static cpc_ep_t endpoint; +// ezmesh related structures +static ezmesh_handle_t lib_handle; +static ezmesh_ep_t endpoint; // tx/rx buffers -static uint8_t data_from_cpc[FROM_CPC_BUF_SIZE]; -// cpc instance name -static char cpc_instance[INST_NAME_LEN]; +static uint8_t data_from_ezmesh[FROM_EZMESH_BUF_SIZE]; +// ezmesh instance name +static char ezmesh_instance[INST_NAME_LEN]; static int upg_complete = -1; @@ -207,7 +207,7 @@ static void a_write(void *p_data) fread(&fw_wr_cmd[12], 0x100, 1, fp); - libcpc_write_ep(endpoint, &fw_wr_cmd[0], 0x10D, 0); + libezmesh_write_ep(endpoint, &fw_wr_cmd[0], 0x10D, 0); printf("------------------------ >>>> GW ------------------------\n"); _log_mem(" ", fw_wr_cmd, sizeof(fw_wr_cmd)); @@ -222,7 +222,7 @@ static void a_read_mac_addr(void *p_data) 0xE0, 0x00, 0x00, 0x00, 0x08 }; - libcpc_write_ep(endpoint, &fw_read_mac_cmd[0], sizeof(fw_read_mac_cmd), 0); + libezmesh_write_ep(endpoint, &fw_read_mac_cmd[0], sizeof(fw_read_mac_cmd), 0); } static void a_write_start(void *p_data) @@ -246,7 +246,7 @@ static void a_write_start(void *p_data) fread(&fw_wr_start_cmd[20], 8, 1, fp_zbaddr); fclose(fp_zbaddr); - libcpc_write_ep(endpoint, &fw_wr_start_cmd[0], sizeof(fw_wr_start_cmd), 0); + libezmesh_write_ep(endpoint, &fw_wr_start_cmd[0], sizeof(fw_wr_start_cmd), 0); } @@ -266,7 +266,7 @@ static void a_page_read(void *p_data) page_read_cmd[13] = (start_address >> 8) & 0xFF; page_read_cmd[14] = (start_address >> 16) & 0xFF; page_read_cmd[15] = (start_address >> 24) & 0xFF; - libcpc_write_ep(endpoint, &page_read_cmd[0], sizeof(page_read_cmd), 0); + libezmesh_write_ep(endpoint, &page_read_cmd[0], sizeof(page_read_cmd), 0); printf("------------------------ >>>> GW ------------------------\n"); _log_mem(" ", page_read_cmd, sizeof(page_read_cmd)); @@ -280,39 +280,39 @@ static void a_finish(void *p_data) } /**************************************************************************/ /** - * Starts CPC and pty. + * Starts EZMESH and pty. *****************************************************************************/ uint32_t startup(void) { int ret; uint8_t retry = 0; - // Initialize CPC communication + // Initialize EZMESH communication do { - ret = libcpc_init(&lib_handle, cpc_instance, reset_cb); + ret = libezmesh_init(&lib_handle, ezmesh_instance, reset_cb); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); if (ret < 0) { - perror("cpc_init: "); + perror("ezmesh_init: "); return ret; } - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_USER_ID_0, - CPC_TRANSMIT_WINDOW); + EP_USER_ID_0, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { - perror("cpc_open_ep "); + perror("ezmesh_open_ep "); return ret; } printf("Endpoint opened\n"); @@ -329,9 +329,9 @@ static void reset_cb(void) } /**************************************************************************/ /** - * Reset CPC communication after other end restarted. + * Reset EZMESH communication after other end restarted. *****************************************************************************/ -int reset_cpc(void) +int reset_ezmesh(void) { int ret; uint8_t retry = 0; @@ -341,20 +341,20 @@ int reset_cpc(void) // Restart cpp communication do { - ret = libcpc_reset(&lib_handle); + ret = libezmesh_reset(&lib_handle); if (ret == 0) { // speed up boot process if everything seems ok break; } - nanosleep((const struct timespec[]){{ 0, CPC_RETRY_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RETRY_SLEEP_NS } }, NULL); retry++; } while ((ret != 0) && (retry < RETRY_COUNT)); has_reset = false; if (ret < 0) { - perror("cpc restart "); + perror("ezmesh restart "); return ret; } @@ -362,10 +362,10 @@ int reset_cpc(void) return ret; // Open Bluetooth endpoint - ret = libcpc_open_ep(lib_handle, + ret = libezmesh_open_ep(lib_handle, &endpoint, - CPC_EP_USER_ID_0, - CPC_TRANSMIT_WINDOW); + EP_USER_ID_0, + EZMESH_TRANSMIT_WINDOW); if (ret < 0) { perror(" open endpoint "); @@ -388,15 +388,15 @@ int main(int argc, char *argv[]) if (argc > 3) { - strcpy(cpc_instance, argv[3]); + strcpy(ezmesh_instance, argv[3]); } else { - strcpy(cpc_instance, "cpcd_0"); + strcpy(ezmesh_instance, "ezmeshd_0"); } fsm_init(&flashctl_fsm, &flashctl_fsm_descriptor); - // Start CPC and PTY communication + // Start EZMESH and PTY communication if (startup() < 0) { exit(EXIT_FAILURE); @@ -433,26 +433,26 @@ int main(int argc, char *argv[]) } - // Reset cpc communication if daemon signals + // Reset ezmesh communication if daemon signals while (run) { if (has_reset) { - ret = reset_cpc(); + ret = reset_ezmesh(); if (ret < 0) { perror("reset "); exit(EXIT_FAILURE); } } - nanosleep((const struct timespec[]){{ 0, CPC_RESET_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RESET_SLEEP_NS } }, NULL); } return upg_complete; } /**************************************************************************/ /** - * Working thread from CPCd + * Working thread from EZMESHd *****************************************************************************/ void *rx_handler(void *ptr) { @@ -466,14 +466,14 @@ void *rx_handler(void *ptr) while (run) { - // Read data from cpc - size = libcpc_read_ep(endpoint, - &data_from_cpc[0], - FROM_CPC_BUF_SIZE, - CPC_EP_READ_FLAG_NON_BLOCKING); + // Read data from ezmesh + size = libezmesh_read_ep(endpoint, + &data_from_ezmesh[0], + FROM_EZMESH_BUF_SIZE, + EP_READ_FLAG_NON_BLOCKING); if (size > 0) { - pt_pd = (gateway_cmd_pd *)&data_from_cpc[5]; + pt_pd = (gateway_cmd_pd *)&data_from_ezmesh[5]; cmd_index = pt_pd->command_id; if (cmd_index == 0xE0008000) @@ -531,7 +531,7 @@ void *rx_handler(void *ptr) fsm_event_post(&flashctl_fsm, E_PAGE_READ, NULL); } - memset(&data_from_cpc[0], 0, FROM_CPC_BUF_SIZE); + memset(&data_from_ezmesh[0], 0, FROM_EZMESH_BUF_SIZE); } nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); } diff --git a/module/cpc/cpcd-system/src/zbbackup/fsm.c b/module/zigbee/ezmesh-zbbackup/src/fsm.c similarity index 100% rename from module/cpc/cpcd-system/src/zbbackup/fsm.c rename to module/zigbee/ezmesh-zbbackup/src/fsm.c diff --git a/module/cpc/cpcd-system/src/zbbackup/include/fsm.h b/module/zigbee/ezmesh-zbbackup/src/include/fsm.h similarity index 100% rename from module/cpc/cpcd-system/src/zbbackup/include/fsm.h rename to module/zigbee/ezmesh-zbbackup/src/include/fsm.h diff --git a/module/cpc/cpcd-system/src/zbbackup/include/fsm_assist.h b/module/zigbee/ezmesh-zbbackup/src/include/fsm_assist.h similarity index 100% rename from module/cpc/cpcd-system/src/zbbackup/include/fsm_assist.h rename to module/zigbee/ezmesh-zbbackup/src/include/fsm_assist.h diff --git a/module/zigbee/ezmesh-zbgw/CMakeLists.txt b/module/zigbee/ezmesh-zbgw/CMakeLists.txt new file mode 100644 index 0000000..80e5172 --- /dev/null +++ b/module/zigbee/ezmesh-zbgw/CMakeLists.txt @@ -0,0 +1,40 @@ +add_executable(ezmesh-zbgw + src/main.c + src/Queue.c + src/C2S.c + src/S2C.c + src/server.c + src/system.c + src/coordinator.c + src/M2Z.c + src/Z2M.c +) +target_link_libraries(ezmesh-zbgw ezmesh util pthread) + +get_target_property(EZMESH_SOURCE_DIR ezmesh SOURCE_DIR) +target_include_directories(ezmesh-zbgw PRIVATE ${EZMESH_SOURCE_DIR}/library) + +ext_install( "TARGET_RUNTIME" ezmesh-zbgw "bin" ezmesh-zbgw) + +set(DEFAULT_EZMESH_ZBGW_INSTALL_PATH /var/lib/ezmesh-zbgw) +set(DEFAULT_EZMESHD_SERVICE_PATH /lib/systemd/system) +if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + install(DIRECTORY DESTINATION ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_ZBGW_INSTALL_PATH} COMPONENT ezmesh-zbgw) + set(EZMESHD_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESHD_SERVICE_PATH}) + set(EZMESH_ZBGW_SERVICE_PATH ${CMAKE_INSTALL_PREFIX}/${DEFAULT_EZMESH_ZBGW_INSTALL_PATH}) +else() + install(DIRECTORY DESTINATION ${DEFAULT_EZMESH_ZBGW_INSTALL_PATH} COMPONENT ezmesh-zbgw) + set(EZMESHD_SERVICE_PATH ${DEFAULT_EZMESHD_SERVICE_PATH}) + set(EZMESH_ZBGW_SERVICE_PATH ${DEFAULT_EZMESH_ZBGW_INSTALL_PATH}) +endif() + +ext_install("EXECUTE" ${CMAKE_CURRENT_BINARY_DIR}/ezmesh-zbgw ${EZMESH_ZBGW_SERVICE_PATH} ezmesh-zbgw) +ext_install("DIRECTORY" zbdb ${EZMESH_ZBGW_SERVICE_PATH} ezmesh-zbgw) + +if(EZMESHD_LOCATION) + # Install configuration file + ext_install("FILE" ${EZMESHD_LOCATION}/etc/config.ini ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR} ezmeshd) +else() + # Install binaries they come from custom target build_ezmeshd + ext_install("TARGET_HEADER" ezmesh ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} ezmesh-zbgw) +endif() diff --git a/module/zigbee/cpc-zbgw/src/C2S.c b/module/zigbee/ezmesh-zbgw/src/C2S.c similarity index 88% rename from module/zigbee/cpc-zbgw/src/C2S.c rename to module/zigbee/ezmesh-zbgw/src/C2S.c index 8dd47c5..5acc65a 100644 --- a/module/zigbee/cpc-zbgw/src/C2S.c +++ b/module/zigbee/ezmesh-zbgw/src/C2S.c @@ -13,6 +13,6 @@ void C2S_CMD(unsigned char *dareal,unsigned short rlen) { - cpc_write_data(dareal, rlen); + ezmesh_write_data(dareal, rlen); } diff --git a/module/zigbee/cpc-zbgw/src/C2S.h b/module/zigbee/ezmesh-zbgw/src/C2S.h similarity index 100% rename from module/zigbee/cpc-zbgw/src/C2S.h rename to module/zigbee/ezmesh-zbgw/src/C2S.h diff --git a/module/zigbee/cpc-zbgw/src/M2Z.c b/module/zigbee/ezmesh-zbgw/src/M2Z.c similarity index 85% rename from module/zigbee/cpc-zbgw/src/M2Z.c rename to module/zigbee/ezmesh-zbgw/src/M2Z.c index 50045e1..792dcf9 100644 --- a/module/zigbee/cpc-zbgw/src/M2Z.c +++ b/module/zigbee/ezmesh-zbgw/src/M2Z.c @@ -11,7 +11,7 @@ #include "server.h" #include "Queue.h" #include "common.h" -#include "libcpc.h" +#include "libezmesh.h" #include "S2C.h" #include @@ -37,14 +37,14 @@ void gw_cmd_start(uint8_t channel, uint16_t panid, uint8_t reset) Command_String[15] = reset; memcpy(&Command_String[13], (uint8_t *)&panid, 2); - cpc_write_data(Command_String, sizeof(Command_String)); + ezmesh_write_data(Command_String, sizeof(Command_String)); } void gw_cmd_pj() { uint8_t Command_String[] = {0xFF, 0xFC, 0xFC, 0xFF, 0x09, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x01, 0xBF}; - cpc_write_data(Command_String, sizeof(Command_String)); + ezmesh_write_data(Command_String, sizeof(Command_String)); } void gw_cmd_act_ep(uint16_t saddr) @@ -56,7 +56,7 @@ void gw_cmd_act_ep(uint16_t saddr) Command_String[12] = (saddr & 0xFF); Command_String[13] = ((saddr >> 8) & 0xFF); - cpc_write_data(Command_String, sizeof(Command_String)); + ezmesh_write_data(Command_String, sizeof(Command_String)); } void gw_cmd_simple_desc_req(uint16_t saddr, uint8_t ep) { @@ -70,5 +70,5 @@ void gw_cmd_simple_desc_req(uint16_t saddr, uint8_t ep) Command_String[14] = ep; - cpc_write_data(Command_String, sizeof(Command_String)); + ezmesh_write_data(Command_String, sizeof(Command_String)); } \ No newline at end of file diff --git a/module/zigbee/cpc-zbgw/src/Queue.c b/module/zigbee/ezmesh-zbgw/src/Queue.c similarity index 100% rename from module/zigbee/cpc-zbgw/src/Queue.c rename to module/zigbee/ezmesh-zbgw/src/Queue.c diff --git a/module/zigbee/cpc-zbgw/src/Queue.h b/module/zigbee/ezmesh-zbgw/src/Queue.h similarity index 100% rename from module/zigbee/cpc-zbgw/src/Queue.h rename to module/zigbee/ezmesh-zbgw/src/Queue.h diff --git a/module/zigbee/cpc-zbgw/src/S2C.c b/module/zigbee/ezmesh-zbgw/src/S2C.c similarity index 100% rename from module/zigbee/cpc-zbgw/src/S2C.c rename to module/zigbee/ezmesh-zbgw/src/S2C.c diff --git a/module/zigbee/cpc-zbgw/src/S2C.h b/module/zigbee/ezmesh-zbgw/src/S2C.h similarity index 100% rename from module/zigbee/cpc-zbgw/src/S2C.h rename to module/zigbee/ezmesh-zbgw/src/S2C.h diff --git a/module/zigbee/cpc-zbgw/src/Z2M.c b/module/zigbee/ezmesh-zbgw/src/Z2M.c similarity index 100% rename from module/zigbee/cpc-zbgw/src/Z2M.c rename to module/zigbee/ezmesh-zbgw/src/Z2M.c diff --git a/module/zigbee/cpc-zbgw/src/Z2M.h b/module/zigbee/ezmesh-zbgw/src/Z2M.h similarity index 100% rename from module/zigbee/cpc-zbgw/src/Z2M.h rename to module/zigbee/ezmesh-zbgw/src/Z2M.h diff --git a/module/zigbee/cpc-zbgw/src/common.h b/module/zigbee/ezmesh-zbgw/src/common.h similarity index 97% rename from module/zigbee/cpc-zbgw/src/common.h rename to module/zigbee/ezmesh-zbgw/src/common.h index f37d68d..0e48cd9 100644 --- a/module/zigbee/cpc-zbgw/src/common.h +++ b/module/zigbee/ezmesh-zbgw/src/common.h @@ -68,7 +68,7 @@ typedef struct __attribute__((packed)) } gateway_cmd_end; -void cpc_write_data(uint8_t *pdata, uint16_t len); +void ezmesh_write_data(uint8_t *pdata, uint16_t len); void System_Initial(); void Show_Fuction(); diff --git a/module/zigbee/cpc-zbgw/src/coordinator.c b/module/zigbee/ezmesh-zbgw/src/coordinator.c similarity index 97% rename from module/zigbee/cpc-zbgw/src/coordinator.c rename to module/zigbee/ezmesh-zbgw/src/coordinator.c index 02ea090..267f4cb 100644 --- a/module/zigbee/cpc-zbgw/src/coordinator.c +++ b/module/zigbee/ezmesh-zbgw/src/coordinator.c @@ -11,15 +11,15 @@ #include "server.h" #include "Queue.h" #include "common.h" -#include "libcpc.h" +#include "libezmesh.h" #include "S2C.h" #include struct _EndDevice ED[EndDeviceMax]; struct _Coordinator CR; -char EndDevice_Filename[]="/usr/local/var/lib/cpc-zbgw/zbdb/sc_enddevice.dat"; -char Coordinator_Filename[]="/usr/local/var/lib/cpc-zbgw/zbdb/sc_coordinator.dat"; +char EndDevice_Filename[]="/usr/local/var/lib/ez-zbgw/zbdb/sc_enddevice.dat"; +char Coordinator_Filename[]="/usr/local/var/lib/ez-zbgw/zbdb/sc_coordinator.dat"; int FileExist(char *fname) { diff --git a/module/zigbee/cpc-zbgw/src/main.c b/module/zigbee/ezmesh-zbgw/src/main.c similarity index 77% rename from module/zigbee/cpc-zbgw/src/main.c rename to module/zigbee/ezmesh-zbgw/src/main.c index 2ef385d..081ea09 100644 --- a/module/zigbee/cpc-zbgw/src/main.c +++ b/module/zigbee/ezmesh-zbgw/src/main.c @@ -14,16 +14,16 @@ #include "server.h" #include "Queue.h" #include "common.h" -#include "libcpc.h" +#include "libezmesh.h" #include "S2C.h" -#define FROM_CPC_BUF_SIZE LIB_CPC_READ_MINIMUM_SIZE -#define CPC_RETRY_SLEEP_NS 100000000L -#define CPC_RESET_SLEEP_NS 10000000L +#define FROM_EZMESH_BUF_SIZE LIB_EZMESH_READ_MINIMUM_SIZE +#define EZMESH_RETRY_SLEEP_NS 100000000L +#define EZMESH_RESET_SLEEP_NS 10000000L #define THREAD_SLEEP_NS 10000000L -static uint8_t data_from_cpc[FROM_CPC_BUF_SIZE]; +static uint8_t data_from_ezmesh[FROM_EZMESH_BUF_SIZE]; //Thread Ptr pthread_t tcp_server_listen; @@ -33,10 +33,10 @@ pthread_t thd_EndEvent; pthread_t thd_System; static pthread_t thread_rx; -static char cpc_instance[100]; +static char ezmesh_instance[100]; -static cpc_handle_t lib_handle; -static cpc_ep_t endpoint; +static ezmesh_handle_t lib_handle; +static ezmesh_ep_t endpoint; static volatile bool run = true; // signal if the controller was reset @@ -165,21 +165,20 @@ int main(int argc, char *argv[]) res = pthread_create(&thd_EndEvent, NULL, Task_Console_Key_Event, NULL); - strcpy(cpc_instance, "cpcd_0"); + strcpy(ezmesh_instance, "ezmeshd_0"); - res = libcpc_init(&lib_handle, cpc_instance, reset_cb); + res = libezmesh_init(&lib_handle, ezmesh_instance, reset_cb); - res = libcpc_open_ep(lib_handle, - &endpoint, - CPC_EP_ZIGBEE, - 1); - if (res < 0) { - - perror("cpc_open_ep "); - + perror("ezmesh_init "); return res; + } + + res = libezmesh_open_ep(lib_handle, &endpoint, EP_ZIGBEE, 1); + if (res < 0) { + perror("ezmesh_open_ep "); + return res; } printf("Endpoint opened\n"); @@ -193,20 +192,20 @@ int main(int argc, char *argv[]) while (run) { - nanosleep((const struct timespec[]){{ 0, CPC_RESET_SLEEP_NS } }, NULL); + nanosleep((const struct timespec[]){{ 0, EZMESH_RESET_SLEEP_NS } }, NULL); } return 0; } -void cpc_write_data(uint8_t *pdata, uint16_t len) +void ezmesh_write_data(uint8_t *pdata, uint16_t len) { ssize_t ret; - ret = libcpc_write_ep(endpoint, pdata, len, CPC_EP_WRITE_FLAG_NONE); + ret = libezmesh_write_ep(endpoint, pdata, len, EP_WRITE_FLAG_NONE); if (ret < 0) { - perror("cpc_write_ep "); + perror("ezmesh_write_ep "); } } @@ -221,15 +220,15 @@ void *rx_handler(void *ptr) while (run) { - // Read data from cpc - size = libcpc_read_ep(endpoint, - &data_from_cpc[0], - FROM_CPC_BUF_SIZE, - CPC_EP_READ_FLAG_NON_BLOCKING); + // Read data from ezmesh + size = libezmesh_read_ep(endpoint, + &data_from_ezmesh[0], + FROM_EZMESH_BUF_SIZE, + EP_READ_FLAG_NON_BLOCKING); if (size > 0) { - Queue_TX_Write(data_from_cpc, size); - memset(&data_from_cpc[0], 0, FROM_CPC_BUF_SIZE); + Queue_TX_Write(data_from_ezmesh, size); + memset(&data_from_ezmesh[0], 0, FROM_EZMESH_BUF_SIZE); } nanosleep((const struct timespec[]){{ 0, THREAD_SLEEP_NS } }, NULL); } diff --git a/module/zigbee/cpc-zbgw/src/server.c b/module/zigbee/ezmesh-zbgw/src/server.c similarity index 100% rename from module/zigbee/cpc-zbgw/src/server.c rename to module/zigbee/ezmesh-zbgw/src/server.c diff --git a/module/zigbee/cpc-zbgw/src/server.h b/module/zigbee/ezmesh-zbgw/src/server.h similarity index 100% rename from module/zigbee/cpc-zbgw/src/server.h rename to module/zigbee/ezmesh-zbgw/src/server.h diff --git a/module/zigbee/cpc-zbgw/src/setting.ini b/module/zigbee/ezmesh-zbgw/src/setting.ini similarity index 100% rename from module/zigbee/cpc-zbgw/src/setting.ini rename to module/zigbee/ezmesh-zbgw/src/setting.ini diff --git a/module/zigbee/cpc-zbgw/src/system.c b/module/zigbee/ezmesh-zbgw/src/system.c similarity index 98% rename from module/zigbee/cpc-zbgw/src/system.c rename to module/zigbee/ezmesh-zbgw/src/system.c index 894132d..e7c5aa7 100644 --- a/module/zigbee/cpc-zbgw/src/system.c +++ b/module/zigbee/ezmesh-zbgw/src/system.c @@ -11,7 +11,7 @@ #include "server.h" #include "Queue.h" #include "common.h" -#include "libcpc.h" +#include "libezmesh.h" #include "S2C.h" void System_Initial() diff --git a/module/zigbee/cpc-zbgw/zbdb/sc_enddevice.dat b/module/zigbee/ezmesh-zbgw/zbdb/sc_enddevice.dat similarity index 100% rename from module/zigbee/cpc-zbgw/zbdb/sc_enddevice.dat rename to module/zigbee/ezmesh-zbgw/zbdb/sc_enddevice.dat diff --git a/project.conf b/project.conf index d7e939e..08d3ff9 100644 --- a/project.conf +++ b/project.conf @@ -1,5 +1,9 @@ -set(CONFIG_CPC true) +set(CONFIG_CONTROLLER true) +set(CONFIG_UPGRADE true) set(CONFIG_BLUETOOTH true) set(CONFIG_BORDER_ROUTER true) set(CONFIG_ZIGBEE_GW_SERVICE true) set(CONFIG_SUBG_SERVICE true) + +set(CONFIG_GEN_SYSTEM true) +set(CONFIG_PLATEFROM debian) \ No newline at end of file