diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..44428ba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,159 @@ +cmake_minimum_required(VERSION 3.15) +project(sigfox_ep_lib) + +# Define macro to manage the options +macro(opt TYPE FLAG DEFAULT DESC) + if(${TYPE} STREQUAL TYPE_BOOL) + option(${FLAG} ${DESC} ${DEFAULT}) + elseif(${TYPE} STREQUAL TYPE_VALUE) + set(${FLAG} ${DEFAULT} CACHE STRING ${DESC}) + else() + message(FATAL_ERROR "Only TYPE_BOOL and TYPE_VALUE are supported") + endif() + list(APPEND COMPILE_FLAG_LIST ${FLAG}) +endmacro() + +set(LIB_SOURCES + src/sigfox_ep_api.c + src/sigfox_error.c + src/core/sigfox_crc.c + src/core/sigfox_ep_bitstream.c + src/core/sigfox_ep_frequency.c + src/core/sigfox_tx_control.c +) + +set(LIB_HEADERS + inc/sigfox_ep_version.h + inc/sigfox_ep_api.h + inc/sigfox_ep_api_test.h + inc/sigfox_error.h + inc/sigfox_rc.h + inc/sigfox_types.h + inc/core/sigfox_ep_bitstream.h + inc/core/sigfox_ep_frequency.h + inc/core/sigfox_tx_control.h + inc/core/sigfox_crc.h + inc/manuf/mcu_api.h + inc/manuf/rf_api.h +) + +set(LIB_PUBLIC_HEADERS + inc/core/sigfox_ep_bitstream.h + inc/core/sigfox_ep_frequency.h + inc/core/sigfox_tx_control.h + inc/core/sigfox_crc.h + inc/manuf/rf_api.h + inc/manuf/mcu_api.h + inc/sigfox_ep_api.h + inc/sigfox_ep_api_test.h + inc/sigfox_error.h + inc/sigfox_rc.h + inc/sigfox_types.h + inc/sigfox_ep_version.h +) + +set(MANUF_SOURCES + src/manuf/mcu_api.c + src/manuf/rf_api.c +) + +# Set the path for the static library +set(LIB_LOCATION ${CMAKE_BINARY_DIR}/lib/ CACHE STRING "") + +# Set the path for the public header of the library +set(API_LOCATION ${CMAKE_BINARY_DIR}/lib/api CACHE STRING "") + +#Options Use sigfox_ep_flag.h +opt(TYPE_BOOL USE_SIGFOX_EP_FLAGS_H ON "library compilation options. ON:in sigfox_ep_flag.h file OFF:in command line") +#Option addon RFP contents +opt(TYPE_BOOL ADDON_RFP OFF "Add RFP addon contents to build it with library") + +#When sigfox_ep_flag.h is don't used +if(${USE_SIGFOX_EP_FLAGS_H} STREQUAL "ON") + list(APPEND DEF_FLAG_LIST "-DUSE_SIGFOX_EP_FLAGS_H") + list(APPEND LIB_HEADERS "inc/sigfox_ep_flags.h") +else() + opt(TYPE_BOOL RC1 ON "Support RC1 (Europe, Middle-East and Africa)") + opt(TYPE_BOOL RC2 ON "Support RC2 (Brazil, Canada, Mexico, Puerto Rico and USA)") + opt(TYPE_BOOL RC3C ON "Support RC3C with LBT (Japan)") + opt(TYPE_BOOL RC3D ON "Support RC3D with DC (Japan)") + opt(TYPE_BOOL RC4 ON "Support RC4 (Latin America and Asia Pacific)") + opt(TYPE_BOOL RC5 ON "Support RC5 (South-Corea)") + opt(TYPE_BOOL RC6 ON "Support RC6 (India)") + opt(TYPE_BOOL RC7 ON "Support RC7 (Russia)") + opt(TYPE_BOOL APPLICATION_MESSAGES ON "Support uplink application messages") + opt(TYPE_BOOL CONTROL_KEEP_ALIVE_MESSAGE ON "Support uplink control keep alive message") + opt(TYPE_BOOL BIDIRECTIONAL ON "Support downlink communication") + opt(TYPE_BOOL ASYNCHRONOUS ON "Support Asynchronous mode") + opt(TYPE_BOOL LOW_LEVEL_OPEN_CLOSE ON "Enable MCU and RF open/close functions") + opt(TYPE_BOOL REGULATORY ON "Enable Regulatory before transmission (DC, FH or LBT)") + opt(TYPE_BOOL SINGLE_FRAME OFF "Send only 1 frame per message (N=1)") + opt(TYPE_BOOL PARAMETERS_CHECK ON "Enable parameters check") + opt(TYPE_BOOL CERTIFICATION ON "Enable certification functions") + opt(TYPE_BOOL PUBLIC_KEY_CAPABLE ON "Enable public key switch feature") + opt(TYPE_BOOL VERBOSE ON "Enable versionning functions") + opt(TYPE_BOOL CRC_HW OFF "Support hardware CRC") + opt(TYPE_BOOL ERROR_CODES ON "Enable error codes on all functions") + opt(TYPE_VALUE UL_BIT_RATE_BPS OFF "Fixed uplink bit rate in bps (100/600)") + opt(TYPE_VALUE T_IFU_MS OFF "Fixed inter-frame delay in ms (10 to 2000)") + opt(TYPE_VALUE T_CONF_MS OFF "Fixed DL confirmation delay in ms (1400 to 4000)") + opt(TYPE_VALUE UL_PAYLOAD_SIZE OFF "Fixed UL payload size in bytes (0 to 12)") + opt(TYPE_VALUE TX_POWER_DBM_EIRP OFF "Fixed the TX power supported by the radio") + opt(TYPE_VALUE MESSAGE_COUNTER_ROLLOVER OFF "Fixed message counter rollover (128, 256, 512, 1024, 2048 or 4096)") + opt(TYPE_VALUE ERROR_STACK 32 "Enable error stack and defined the depth") + + foreach( COMPILE_FLAG ${COMPILE_FLAG_LIST} ) + if((NOT ${COMPILE_FLAG} STREQUAL OFF)) + if(${${COMPILE_FLAG}} STREQUAL ON) + list(APPEND DEF_FLAG_LIST "-D${COMPILE_FLAG}") + else() + list(APPEND DEF_FLAG_LIST "-D${COMPILE_FLAG}=${${COMPILE_FLAG}} ") + list(APPEND DEF_FLAG_WITH_VALUE_LIST "${COMPILE_FLAG}") + endif() + endif() + endforeach() + if(${CRC_HW} STREQUAL ON) + list(REMOVE_ITEM LIB_SOURCES "src/core/sigfox_crc.c") + list(REMOVE_ITEM LIB_HEADERS "inc/core/sigfox_crc.h") + list(REMOVE_ITEM LIB_PUBLIC_HEADERS "inc/core/sigfox_crc.h") + endif() + if(${REGULATORY} STREQUAL OFF) + list(REMOVE_ITEM LIB_SOURCES "src/core/sigfox_tx_control.c") + list(REMOVE_ITEM LIB_HEADERS "inc/core/sigfox_tx_control.h") + list(REMOVE_ITEM LIB_PUBLIC_HEADERS "inc/core/sigfox_tx_control.h") + endif() + if(${CERTIFICATION} STREQUAL OFF) + list(REMOVE_ITEM LIB_HEADERS "inc/sigfox_ep_api_test.h") + list(REMOVE_ITEM LIB_PUBLIC_HEADERS "inc/sigfox_ep_api_test.h") + endif() +endif() +#add DEF_FLAG_LIST to parent scope to be used by a child +if(NOT (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})) + set(DEF_FLAG_LIST ${DEF_FLAG_LIST} PARENT_SCOPE) +endif() + +#Add Cmake module path +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") + +#Precompile module +include(precompile) +#Addon RFP module +if(${ADDON_RFP} STREQUAL "ON") + unset(SFX_LIB_CORE_PROTOCOL_DIR CACHE) + include(addon_rfp) +endif() + +add_library(${PROJECT_NAME} STATIC ${PRECOMPIL_LIB_SOURCES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${PRECOMPIL_DIR}/inc) +target_compile_definitions(${PROJECT_NAME} PUBLIC ${DEF_FLAG_LIST}) +target_compile_options(${PROJECT_NAME} PRIVATE -Wall) +set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${PRECOMPIL_LIB_PUBLIC_HEADERS}") +set_target_properties(${PROJECT_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${LIB_LOCATION} + LIBRARY_OUTPUT_DIRECTORY ${LIB_LOCATION} +) +install(TARGETS ${PROJECT_NAME} + ARCHIVE DESTINATION ${LIB_LOCATION} + PUBLIC_HEADER DESTINATION ${API_LOCATION} +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..80cc91c --- /dev/null +++ b/README.md @@ -0,0 +1,156 @@ +# Sigfox End-Point library (EP_LIB) + +## Description + +The **Sigfox End-Point library** is an example of the [Sigfox radio protocol](https://build.sigfox.com/sigfox-device-radio-specifications) implementation. The stack is designed to operate either in **blocking** or **asynchronous** mode, and supports most of **MCUs** and **radio chipsets**. + +The user API is provided in the `inc/sigfox_ep_api.h` file, to send **application messages** and **control messages** over the Sigfox network. + +## Stack architecture + +

+ +

+ +## Hardware + +The stack relies on **low level drivers** (called manufacturer drivers) which need to be implemented to run on your specific hardware. There are divided in 2 groups: + +* **MCU_API** : MCU related functions such as timers, non-volatile memory and encryption. +* **RF_API** : radio related functions such as uplink transmission and downlink reception. + +These drivers are located in the `src/manuf` folder. + +## Code optimization + +Most of Sigfox radio parameters and features are conditionned to a **dedicated flag**, so that the stack can be configured to perfectly match your application, **without dead code** and thus with a **minimum memory footprint**. The flags are located in the `inc/sigfox_ep_flags.h` file, but can also be set through the **cmake** command when building the project. + +To have such a flexibilty, the stack use a lot of preprocessor directives, which makes the source code less readable. If you plan to look or modify the source files, we advise you to **run the cmake pre-compilation command**, that will remove all preprocessor directives according to your flags selection. + +Below is the list of available flags. + +| **Flag name** | **Value** | **Description** | +|:----------------------------:|:--------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| `RCx` | `undefined` / `defined` | Support the RCx radio configuration if defined | +| `APPLICATION_MESSAGES` | `undefined` / `defined` | Support uplink application messages if defined | +| `CONTROL_KEEP_ALIVE_MESSAGE` | `undefined` / `defined` | Support uplink control keep alive message if defined | +| `BIDIRECTIONAL` | `undefined` / `defined` | Support bidirectional procedure (downlink) if defined. Only applicable to application messages. Otherwise all messages will be uplink only. | +| `ASYNCHRONOUS` | `undefined` / `defined` | Asynchronous mode if defined, blocking mode otherwise. | +| `LOW_LEVEL_OPEN_CLOSE` | `undefined` / `defined` | Enable MCU and RF open/close functions if defined. | +| `REGULATORY` | `undefined` / `defined` | Enable radio regulatory control (DC, FH or LBT check) if defined. | +| `SINGLE_FRAME` | `undefined` / `defined` | Send 1 frame per message (N=1) if defined. Otherwise number of frames per message is dynamically given when sending a message (N=1, N=2 or N=3). | +| `UL_BIT_RATE_BPS` | `undefined` / `100` / `600` | If defined, give the only uplink bit rate supported (100 or 600 depending on the RC). Otherwise, value is dynamically given when sending a message. | +| `TX_POWER_DBM_EIRP` | `undefined` / `` | If defined, give the only TX power supported by the radio. Otherwise the value is dynamically given when sending a message. | +| `T_IFU_MS` | `undefined` / `` | If defined, give the fixed inter-frame delay used between uplink frames of a same message (0 to 2000ms). Value 0 disables the delay and associated timers to optimize memory space. Otherwise value is dynamically given when sending a message. | +| `T_CONF_MS` | `undefined` / `` | If defined, give the fixed delay between downlink frame reception and uplink confirmation message (1400 to 4000ms). Otherwise value is dynamically given when sending a message. | +| `UL_PAYLOAD_SIZE` | `undefined` / `` | If defined, give the only uplink payload length supported (0 to 12). Value 0 enables the bit 0, bit 1 and empty messages. Otherwise, all uplink payload lengths are dynamically supported. | +| `CRC_HW` | `undefined` / `defined` | If defined, enable hardware CRC through MCU API functions. Otherwise the embedded driver is used. | +| `MESSAGE_COUNTER_ROLLOVER` | `undefined` / `128` / `256` / `512` / `1024` / `2048` / `4096` | If defined, give the only message counter rollover value supported. Otherwise, value is dynamically given when opening the library. | +| `PARAMETERS_CHECK` | `undefined` / `defined` | Enable parameters check if defined. | +| `CERTIFICATION` | `undefined` / `defined` | Enable certification features if defined. | +| `PUBLIC_KEY_CAPABLE` | `undefined` / `defined` | Enable public key switch feature if defined. | +| `VERBOSE` | `undefined` / `defined` | Enable credentials (ID / PAC) API access and version control functions if defined. | +| `ERROR_CODES` | `undefined` / `defined` | Use return codes if defined, otherwise all functions return void. | +| `ERROR_STACK` | `undefined` / `` | If defined, store low level errors in a stack (the macro gives the depth). Errors can be read with the `SIGFOX_EP_API_unstack_error()` function. | + +## Getting Started + +### Cloning the repository + +```bash +$ git clone https://github.com/sigfox-tech-radio/sigfox-ep-lib.git +``` + +### Usage + +This library can be used in 3 different ways: + * The [original source code](#original-source-code) to used the raw sources files + * The [precompiled source code](#precompiled-source-code) to remove all unused source code and have more readability. + * The [static-library](#static-library) to used a compiled library. + +### Original source code + +Sources files are available in the `inc` and `src` folders and must be copied directly in your embedded project. Then you can customize the `inc/sigfox_ep_flags.h` according to your flags selection. + +### Precompiled source code + +#### Dependency + +Before building process install **unifdef** and **cmake**. The unifdef tool is used to remove dead code and cmake to build. + +#### Building process + +If you want to **precompile** the sources files for a given flags selection, you need to use the **cmake** commands: + +Create a build folder: + +```bash +$ cd sigfox-ep-lib +$ mkdir build +$ cd build +``` + +* Precompiling by reading the `inc/sigfox_ep_flags.h` file: + +```bash +$ cmake -DUSE_SIGFOX_EP_FLAGS_H=ON .. +$ make precompil +``` +* Precompiling by entering the flags selection on command line: + +```bash +$ cmake -DUSE_SIGFOX_EP_FLAGS_H=OFF \ + -DRC1=ON \ + -DRC2=ON \ + -DRC3C=ON \ + -DRC3D=ON \ + -DRC4=ON \ + -DRC5=ON \ + -DRC6=ON \ + -DRC7=ON \ + -DAPPLICATION_MESSAGES=ON \ + -DCONTROL_KEEP_ALIVE_MESSAGE=ON \ + -DBIDIRECTIONAL=ON \ + -DASYNCHRONOUS=ON \ + -DLOW_LEVEL_OPEN_CLOSE=ON \ + -DREGULATORY=ON \ + -DSINGLE_FRAME=ON \ + -DPARAMETERS_CHECK=ON \ + -DCERTIFICATION=ON \ + -DPUBLIC_KEY_CAPABLE=ON \ + -DVERBOSE=ON \ + -DCRC_HW=OFF \ + -DERROR_CODES=ON \ + -DUL_BIT_RATE_BPS=OFF \ + -DT_IFU_MS=OFF \ + -DT_CONF_MS=OFF \ + -DUL_PAYLOAD_SIZE=OFF \ + -DMESSAGE_COUNTER_ROLLOVER=OFF \ + -DERROR_STACK=12 .. +$ make precompil +``` + +The precompiled files will be generated in the `build/precompil` folder. + +### Static library + +If you want to build a **static library**, you need to run this additionnal **cmake** command: + +```bash +$ make sigfox_ep_lib +``` + +The archive will be generated in the `build/lib` folder. + + +## Addons + +### RF & Protocol + +In order to **test your implementation** against Sigfox specifications, you can use the [Sigfox End-Point RF & Protocol addon](https://github.com/sigfox-tech-radio/sigfox-ep-addon-rfp) which will drive the library to perform some test modes. + +The addon can be directly generated from the Sigfox End-Point library **cmake** by using the `ADDON_RFP` option: + +```bash +$ cmake -DADDON_RFP=ON .. +``` diff --git a/cmake/addon_rfp.cmake b/cmake/addon_rfp.cmake new file mode 100644 index 0000000..27a856c --- /dev/null +++ b/cmake/addon_rfp.cmake @@ -0,0 +1,20 @@ +include(ExternalProject) +include(FetchContent) +Set(FETCHCONTENT_QUIET FALSE) +FetchContent_Declare( + addon_rfp + GIT_REPOSITORY "https://github.com/sigfox-tech-radio/sigfox-ep-addon-rfp" + GIT_TAG "master" + GIT_PROGRESS TRUE + GIT_SHALLOW 1 + #SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/addons/rfp + UPDATE_DISCONNECTED TRUE + STEP_TARGETS update +) +FetchContent_GetProperties(addon_rfp) +if (NOT platform_POPULATED) + FetchContent_Populate(addon_rfp) + add_subdirectory(${addon_rfp_SOURCE_DIR} ${addon_rfp_BINARY_DIR}) +endif() +#FetchContent_MakeAvailable(addon_rfp) + diff --git a/cmake/precompile.cmake b/cmake/precompile.cmake new file mode 100644 index 0000000..3958eac --- /dev/null +++ b/cmake/precompile.cmake @@ -0,0 +1,118 @@ + +find_program(UNIFDEF unifdef REQUIRED) +if(NOT UNIFDEF) + message(FATAL_ERROR "unifdef not found!") +endif() +find_program(SPLINT splint REQUIRED) +if(NOT SPLINT) + message(FATAL_ERROR "splint not found!") +endif() +# specify the precompil files location +set(PRECOMPIL_DIR ${CMAKE_BINARY_DIR}/precompil CACHE STRING "") + +#List of precompileInc and precompileSrc files +foreach(X IN LISTS LIB_SOURCES) + LIST(APPEND PRECOMPIL_LIB_SOURCES "${PRECOMPIL_DIR}/${X}") + LIST(APPEND SPLINT_PRECOMPIL_LIB_SOURCES "${PRECOMPIL_DIR}/splint/${X}") +endforeach() +foreach(X IN LISTS MANUF_SOURCES) + LIST(APPEND PRECOMPIL_MANUF_SOURCES "${PRECOMPIL_DIR}/${X}") +endforeach() +foreach(X IN LISTS LIB_HEADERS) + LIST(APPEND PRECOMPIL_LIB_HEADERS "${PRECOMPIL_DIR}/${X}") +endforeach() +foreach(X IN LISTS LIB_PUBLIC_HEADERS) + LIST(APPEND PRECOMPIL_LIB_PUBLIC_HEADERS "${PRECOMPIL_DIR}/${X}") +endforeach() + +#Custom command Loop for all Sources +foreach(X IN LISTS LIB_SOURCES MANUF_SOURCES) +add_custom_command( + OUTPUT "${PRECOMPIL_DIR}/${X}" + DEPENDS ${CMAKE_BINARY_DIR}/undefs_file + DEPENDS ${CMAKE_BINARY_DIR}/defs_file + DEPENDS ${LIB_HEADERS} + DEPENDS ${X} + COMMAND ${CMAKE_COMMAND} -E make_directory ${PRECOMPIL_DIR}/src/core ${PRECOMPIL_DIR}/src/manuf + COMMAND unifdef -B -k -x 2 -f ${CMAKE_BINARY_DIR}/undefs_file -f ${CMAKE_BINARY_DIR}/defs_file ${PROJECT_SOURCE_DIR}/${X} > "${PRECOMPIL_DIR}/${X}" + VERBATIM +) +endforeach() + +#Custom command Loop for all Sources : SPLINT analysis +foreach(X IN LISTS LIB_SOURCES MANUF_SOURCES) +add_custom_command( + OUTPUT "${PRECOMPIL_DIR}/splint/${X}" + DEPENDS ${CMAKE_BINARY_DIR}/undefs_file + DEPENDS ${CMAKE_BINARY_DIR}/defs_file + DEPENDS ${LIB_HEADERS} + DEPENDS ${X} + COMMAND ${CMAKE_COMMAND} -E make_directory ${PRECOMPIL_DIR}/splint ${PRECOMPIL_DIR}/splint/src/core ${PRECOMPIL_DIR}/splint/src/manuf + COMMAND splint +linelength 150 +weak +show-summary +stats -slashslashcomment -preproc -I${PRECOMPIL_DIR}/inc/core/ -I${PRECOMPIL_DIR}/inc/manuf/ -I${PRECOMPIL_DIR}/inc/ ${PRECOMPIL_DIR}/${X} > ${PRECOMPIL_DIR}/splint/${X}.log + # Keep a log trace even if the splint failed + COMMAND cat ${PRECOMPIL_DIR}/splint/${X}.log > ${PRECOMPIL_DIR}/splint/${X} +# VERBATIM +) +endforeach() + + +#Custom command Loop for all Headers +foreach(X IN LISTS LIB_HEADERS MANUF_HEADERS) +if(${X} STREQUAL "inc/sigfox_types.h" AND ${USE_SIGFOX_EP_FLAGS_H} STREQUAL "OFF" AND NOT "${DEF_FLAG_WITH_VALUE_LIST}" STREQUAL "") +#Add Specific Macro in sigfox_types.h file + foreach(X IN LISTS DEF_FLAG_WITH_VALUE_LIST) + string(CONCAT DEF_FLAG_STRING ${DEF_FLAG_STRING} "\r\\n" "#define ${X} ${${X}}") + endforeach() + add_custom_command( + OUTPUT ${PRECOMPIL_DIR}/${X} + DEPENDS ${CMAKE_BINARY_DIR}/undefs_file + DEPENDS ${CMAKE_BINARY_DIR}/defs_file + DEPENDS ${LIB_HEADERS} + COMMAND ${CMAKE_COMMAND} -E make_directory ${PRECOMPIL_DIR}/inc/core ${PRECOMPIL_DIR}/inc/manuf + COMMAND unifdef -B -k -x 2 -f ${CMAKE_BINARY_DIR}/undefs_file -f ${CMAKE_BINARY_DIR}/defs_file ${PROJECT_SOURCE_DIR}/${X} > "${PRECOMPIL_DIR}/${X}" + COMMAND sed -i "/SIGFOX library common macros/a ${DEF_FLAG_STRING}" ${PRECOMPIL_DIR}/${X} + VERBATIM + ) +else() + add_custom_command( + OUTPUT ${PRECOMPIL_DIR}/${X} + DEPENDS ${CMAKE_BINARY_DIR}/undefs_file + DEPENDS ${CMAKE_BINARY_DIR}/defs_file + DEPENDS ${LIB_HEADERS} + COMMAND ${CMAKE_COMMAND} -E make_directory ${PRECOMPIL_DIR}/inc/core ${PRECOMPIL_DIR}/inc/manuf + COMMAND unifdef -B -k -x 2 -f ${CMAKE_BINARY_DIR}/undefs_file -f ${CMAKE_BINARY_DIR}/defs_file ${PROJECT_SOURCE_DIR}/${X} > "${PRECOMPIL_DIR}/${X}" + VERBATIM + ) +endif() +endforeach() + +add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/defs_file + DEPENDS ${LIB_HEADERS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND cc -E -dMM ${DEF_FLAG_LIST} -I config/ ${CMAKE_CURRENT_SOURCE_DIR}/inc/sigfox_types.h > "${CMAKE_BINARY_DIR}/defs_file.tmp" + COMMAND grep -v __ "${CMAKE_BINARY_DIR}/defs_file.tmp" | sort -u > "${CMAKE_BINARY_DIR}/defs_file" + COMMAND rm "${CMAKE_BINARY_DIR}/defs_file.tmp" +) + +add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/undefs_file + DEPENDS ${LIB_HEADERS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/core/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/manuf/*c ${CMAKE_CURRENT_SOURCE_DIR}/inc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/inc/core/*.h ${CMAKE_CURRENT_SOURCE_DIR}/inc/manuf/*.h | unifdef -s | sort -u | grep -v __ | sed "s/^/#undef /" >"${CMAKE_BINARY_DIR}/undefs_file" +) + +add_custom_target(precompil + DEPENDS ${CMAKE_BINARY_DIR}/undefs_file + DEPENDS ${CMAKE_BINARY_DIR}/defs_file + DEPENDS ${PRECOMPIL_LIB_SOURCES} + DEPENDS ${PRECOMPIL_LIB_HEADERS} + DEPENDS ${PRECOMPIL_MANUF_SOURCES} + VERBATIM +) + +add_custom_target(splintanalysis + DEPENDS precompil + DEPENDS ${SPLINT_PRECOMPIL_LIB_SOURCES} + VERBATIM +) + + diff --git a/docs/images/sigfox_ep_lib_architecture.png b/docs/images/sigfox_ep_lib_architecture.png new file mode 100644 index 0000000..29ed732 Binary files /dev/null and b/docs/images/sigfox_ep_lib_architecture.png differ diff --git a/inc/core/sigfox_crc.h b/inc/core/sigfox_crc.h new file mode 100644 index 0000000..783ea89 --- /dev/null +++ b/inc/core/sigfox_crc.h @@ -0,0 +1,116 @@ +/*!***************************************************************** + * \file sigfox_crc.h + * \brief Sigfox CRC driver. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_CRC_H__ +#define __SIGFOX_CRC_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +#ifndef CRC_HW + +/*** SIGFOX CRC structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum SIGFOX_CRC_status_t + * \brief Sigfox CRC driver error codes. + *******************************************************************/ +typedef enum { + SIGFOX_CRC_SUCCESS = 0, + SIGFOX_CRC_ERROR_NULL_PARAMETER, +} SIGFOX_CRC_status_t; +#else +typedef void SIGFOX_CRC_status_t; +#endif + +/*** SIGFOX CRC functions ***/ + +/*!****************************************************************** + * \fn SIGFOX_CRC_status_t SIGFOX_CRC_compute_crc16(sfx_u8 *crc_data, sfx_u8 data_size, sfx_u16 polynom, sfx_u16 *crc) + * \brief Compute a CRC16. + * \param[in] crc_data: Input data. + * \param[in] data_size: Number of bytes of the input data. + * \param[in] polynom: CRC polynom to use. + * \param[out] crc: Pointer to the computed CRC16 value. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_CRC_status_t SIGFOX_CRC_compute_crc16(sfx_u8 *crc_data, sfx_u8 data_size, sfx_u16 polynom, sfx_u16 *crc); + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \fn SIGFOX_CRC_status_t SIGFOX_CRC_compute_crc8(sfx_u8 *crc_data, sfx_u8 data_size, sfx_u8 polynom, sfx_u8 *crc) + * \brief Compute a CRC8. + * \param[in] crc_data: Input data. + * \param[in] data_size: Number of bytes of the input data. + * \param[in] polynom: CRC polynom to use. + * \param[out] crc: Pointer to the computed CRC8 value. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_CRC_status_t SIGFOX_CRC_compute_crc8(sfx_u8 *crc_data, sfx_u8 data_size, sfx_u8 polynom, sfx_u8 *crc); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_CRC_stack_error(void) + * \brief Generic macro which calls the error stack function for CRC errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define SIGFOX_CRC_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_CRC, crc_status) +#else +#define SIGFOX_CRC_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_CRC_check_status(error) + * \brief Generic macro to check a SIGFOX_CRC function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define SIGFOX_CRC_check_status(error) { if (crc_status != SIGFOX_CRC_SUCCESS) { SIGFOX_CRC_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* CRC_HW */ + +#endif /* __SIGFOX_CRC_H__ */ diff --git a/inc/core/sigfox_ep_bitstream.h b/inc/core/sigfox_ep_bitstream.h new file mode 100644 index 0000000..a9464f3 --- /dev/null +++ b/inc/core/sigfox_ep_bitstream.h @@ -0,0 +1,222 @@ +/*!***************************************************************** + * \file sigfox_ep_bitstream.h + * \brief Sigfox bitstream builder and decoder. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_EP_BITSTREAM_H__ +#define __SIGFOX_EP_BITSTREAM_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +/*** SIGFOX EP BITSTREAM macros ***/ + +#if (defined UL_PAYLOAD_SIZE) +#if (UL_PAYLOAD_SIZE == 0) +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 14 +#elif (UL_PAYLOAD_SIZE == 1) +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 15 +#elif (UL_PAYLOAD_SIZE == 2) || (UL_PAYLOAD_SIZE == 3) || (UL_PAYLOAD_SIZE == 4) +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 18 +#elif (UL_PAYLOAD_SIZE == 5) || (UL_PAYLOAD_SIZE == 6) || (UL_PAYLOAD_SIZE == 7) || (UL_PAYLOAD_SIZE == 8) +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 22 +#elif (UL_PAYLOAD_SIZE == 9) || (UL_PAYLOAD_SIZE == 10) || (UL_PAYLOAD_SIZE == 11) || (UL_PAYLOAD_SIZE == 12) +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 26 +#else +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 26 +#endif +#else +#define SIGFOX_EP_BITSTREAM_SIZE_BYTES 26 // Maximum value used as default. +#endif + +/*** SIGFOX EP BITSTREAM structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum SIGFOX_EP_BITSTREAM_status_t + * \brief Sigfox bitstream driver error codes. + *******************************************************************/ +typedef enum { + SIGFOX_EP_BITSTREAM_SUCCESS = 0, + SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER, + SIGFOX_EP_BITSTREAM_ERROR_MESSAGE_TYPE, + SIGFOX_EP_BITSTREAM_ERROR_PAYLOAD_SIZE, + SIGFOX_EP_BITSTREAM_ERROR_KEY_TYPE, + SIGFOX_EP_BITSTREAM_ERROR_FRAME_RANK, + SIGFOX_EP_BITSTREAM_ERROR_MESSAGE_COUNTER, + // Low level errors. + SIGFOX_EP_BITSTREAM_ERROR_CRC, + SIGFOX_EP_BITSTREAM_ERROR_MCU +} SIGFOX_EP_BITSTREAM_status_t; +#else +typedef void SIGFOX_EP_BITSTREAM_status_t; +#endif + +/*!****************************************************************** + * \struct SIGFOX_EP_BITSTREAM_common_t + * \brief Common parameters of application and control frames bitstream. + *******************************************************************/ +typedef struct { + sfx_u8 *ep_id; + sfx_u16 message_counter; +#ifndef MESSAGE_COUNTER_ROLLOVER + sfx_u16 message_counter_rollover; +#endif +#ifndef SINGLE_FRAME + SIGFOX_ul_frame_rank_t ul_frame_rank; +#endif +#ifdef PUBLIC_KEY_CAPABLE + SIGFOX_ep_key_t ep_key_type; +#endif +} SIGFOX_EP_BITSTREAM_common_t; + +#ifdef APPLICATION_MESSAGES +/*!****************************************************************** + * \struct SIGFOX_EP_BITSTREAM_application_frame_t + * \brief Specific parameters of application frames bitstream. + *******************************************************************/ +typedef struct { + SIGFOX_EP_BITSTREAM_common_t common_parameters; + SIGFOX_application_message_type_t message_type; +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + sfx_u8 *ul_payload; +#endif +#ifndef UL_PAYLOAD_SIZE + sfx_u8 ul_payload_size_bytes; +#endif +#ifdef BIDIRECTIONAL + sfx_bool bidirectional_flag; +#endif +} SIGFOX_EP_BITSTREAM_application_frame_t; +#endif + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*!****************************************************************** + * \struct SIGFOX_EP_BITSTREAM_control_frame_t + * \brief Specific parameters of control frames bitstream. + *******************************************************************/ +typedef struct { + SIGFOX_EP_BITSTREAM_common_t common_parameters; + SIGFOX_control_message_type_t message_type; + sfx_s16 temperature_tenth_degrees; + sfx_u16 voltage_tx_mv; + sfx_u16 voltage_idle_mv; +#ifdef BIDIRECTIONAL + sfx_s16 rssi_dbm; // For DL confirmation only. +#endif +} SIGFOX_EP_BITSTREAM_control_frame_t; +#endif + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \struct SIGFOX_EP_BITSTREAM_dl_frame_t + * \brief Specific parameters of downlink frames bitstream. + *******************************************************************/ +typedef struct { + sfx_u8 *dl_phy_content; // Raw bytes from radio. + sfx_u8 *ep_id; + sfx_u16 message_counter; // Message counter of the corresponding uplink frame that requested bidirectional procedure. +#ifdef PUBLIC_KEY_CAPABLE + SIGFOX_ep_key_t ep_key_type; +#endif +} SIGFOX_EP_BITSTREAM_dl_frame_t; +#endif + +/*** SIGFOX BISTREAM functions ***/ + +#ifdef APPLICATION_MESSAGES +/*!****************************************************************** + * \fn SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_build_application_frame(SIGFOX_EP_BITSTREAM_application_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes) + * \brief Build an application frame bistream. + * \param[in] input: Application frame input parameters. + * \param[out] bitstream: Computed bistream. + * \param[out] bitstream_size_bytes: Size of the computed bitstream in bytes. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_build_application_frame(SIGFOX_EP_BITSTREAM_application_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes); +#endif + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*!****************************************************************** + * \fn SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_build_control_frame(SIGFOX_EP_BITSTREAM_control_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes) + * \brief Build a control frame bistream. + * \param[in] input: Control frame input parameters. + * \param[out] bitstream: Computed bistream. + * \param[out] bitstream_size_bytes: Size of the computed bitstream in bytes. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_build_control_frame(SIGFOX_EP_BITSTREAM_control_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes); +#endif + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \fn SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_decode_downlink_frame(SIGFOX_EP_BITSTREAM_dl_frame_t *input, sfx_bool *dl_frame_valid, sfx_u8 *dl_payload) + * \brief Authenticate a downlink frame. + * \param[in] input: Received downlink frame input parameters. + * \param[out] dl_frame_valid: Pointer to the authentication result. + * \param[out] dl_payload: Contains the extracted DL user payload if dl_frame_valid is returned with SFX_TRUE value. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_decode_downlink_frame(SIGFOX_EP_BITSTREAM_dl_frame_t *input, sfx_bool *dl_frame_valid, sfx_u8 *dl_payload); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_EP_BITSTREAM_stack_error(void) + * \brief Generic macro which calls the error stack function for bitstream errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define SIGFOX_EP_BITSTREAM_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_BITSTREAM, bitstream_status) +#else +#define SIGFOX_EP_BITSTREAM_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_EP_BITSTREAM_check_status(error) + * \brief Generic macro to check a SIGFOX_EP_BITSTREAM function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define SIGFOX_EP_BITSTREAM_check_status(error) { if (bitstream_status != SIGFOX_EP_BITSTREAM_SUCCESS) { SIGFOX_EP_BITSTREAM_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* __SIGFOX_EP_BITSTREAM_H__ */ diff --git a/inc/core/sigfox_ep_frequency.h b/inc/core/sigfox_ep_frequency.h new file mode 100644 index 0000000..a216047 --- /dev/null +++ b/inc/core/sigfox_ep_frequency.h @@ -0,0 +1,157 @@ +/*!***************************************************************** + * \file sigfox_ep_frequency.h + * \brief Sigfox uplink and downlink frequency manager. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_EP_FREQUENCY_H__ +#define __SIGFOX_EP_FREQUENCY_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +/*** SIGFOX EP FREQUENCY structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum SIGFOX_EP_FREQUENCY_status_t + * \brief Sigfox frequency error codes. + *******************************************************************/ +typedef enum { + SIGFOX_EP_FREQUENCY_SUCCESS = 0, + SIGFOX_EP_FREQUENCY_ERROR_NULL_PARAMETER, + SIGFOX_EP_FREQUENCY_ERROR_FRAME_RANK, + SIGFOX_EP_FREQUENCY_ERROR_SPECTRUM_ACCESS_TYPE, + SIGFOX_EP_FREQUENCY_ERROR_RANDOM_GENERATION, + SIGFOX_EP_FREQUENCY_ERROR_FRAME_1_FREQUENCY, +} SIGFOX_EP_FREQUENCY_status_t; +#else +typedef void SIGFOX_EP_FREQUENCY_status_t; +#endif + +#ifndef SINGLE_FRAME +/*!****************************************************************** + * \struct SIGFOX_EP_FREQUENCY_uplink_signal_t + * \brief Frequency computation input parameters. + *******************************************************************/ +typedef struct { + SIGFOX_ul_frame_rank_t ul_frame_rank; +#ifdef BIDIRECTIONAL + sfx_bool bidirectional_flag; +#endif +} SIGFOX_EP_FREQUENCY_uplink_signal_t; +#endif + +/*** SIGFOX EP FREQUENCY functions ***/ + +/*!****************************************************************** + * \fn SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_init(const SIGFOX_rc_t *rc, sfx_u8 *ep_id, sfx_u16 last_random_value) + * \brief Init the frequecy driver. + * \param[in] rc: Radio configuration. + * \param[in] ep_id: Device ID (used to randomize the frequency algorithm). + * \param[in] last_random_value: Last random value (read in NVM at device start-up). + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_init(const SIGFOX_rc_t *rc, sfx_u8 *ep_id, sfx_u16 last_random_value); + +#ifdef SINGLE_FRAME +/*!****************************************************************** + * \fn SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_uplink(sfx_u32 *ul_frequency_hz) + * \brief Compute the next Sigfox signal uplink frequency. + * \param[in] none + * \param[out] ul_frequency_hz: Pointer that will contain the computed frequency in Hz. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_uplink(sfx_u32 *ul_frequency_hz); +#else +/*!****************************************************************** + * \fn SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_uplink(SIGFOX_EP_FREQUENCY_uplink_signal_t *input, sfx_u32 *ul_frequency_hz) + * \brief Compute the next Sigfox signal uplink frequency according to the input parameters. + * \param[in] input: Pointer to the signal parameters structure. + * \param[out] ul_frequency_hz: Pointer that will contain the computed frequency in Hz. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_uplink(SIGFOX_EP_FREQUENCY_uplink_signal_t *input, sfx_u32 *ul_frequency_hz); +#endif + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \fn SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_downlink(sfx_u32* dl_frequency_hz) + * \brief Compute the Sigfox downlink frequency. + * \param[in] none + * \param[in] dl_frequency_hz: Pointer that will contain the downlink frequency in Hz (computed according to the last data given to the SIGFOX_EP_FREQUENCY_compute_uplink function). + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_downlink(sfx_u32* dl_frequency_hz); +#endif + +/*!****************************************************************** + * \fn SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_get_random_value(sfx_u16 *random_value) + * \brief Return the current random value of the frequency driver (to be stored in NVM). + * \param[in] none + * \param[out] random_value: Pointer that will contain current random value. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_get_random_value(sfx_u16 *random_value); + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_EP_FREQUENCY_stack_error(void) + * \brief Generic macro which calls the error stack function for frequency errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define SIGFOX_EP_FREQUENCY_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_FREQUENCY, frequency_status) +#else +#define SIGFOX_EP_FREQUENCY_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_EP_FREQUENCY_check_status(error) + * \brief Generic macro to check a SIGFOX_EP_FREQUENCY function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define SIGFOX_EP_FREQUENCY_check_status(error) { if (frequency_status != SIGFOX_EP_FREQUENCY_SUCCESS) { SIGFOX_EP_FREQUENCY_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* __SIGFOX_EP_FREQUENCY_H__ */ diff --git a/inc/core/sigfox_tx_control.h b/inc/core/sigfox_tx_control.h new file mode 100644 index 0000000..4512962 --- /dev/null +++ b/inc/core/sigfox_tx_control.h @@ -0,0 +1,215 @@ +/*!***************************************************************** + * \file sigfox_tx_control.h + * \brief Sigfox TX control driver for regulatory operations. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_TX_CONTROL_H__ +#define __SIGFOX_TX_CONTROL_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +#ifdef REGULATORY + +/*** SIGFOX TX CONTROL structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum SIGFOX_TX_CONTROL_status_t + * \brief Sigfox TX control driver error codes. + *******************************************************************/ +typedef enum { + SIGFOX_TX_CONTROL_SUCCESS = 0, + SIGFOX_TX_CONTROL_ERROR_NULL_PARAMETER, + SIGFOX_TX_CONTROL_ERROR_SPECTRUM_ACCESS, + // Low level errors. + SIGFOX_TX_CONTROL_ERROR_MCU, + SIGFOX_TX_CONTROL_ERROR_RF +} SIGFOX_TX_CONTROL_status_t; +#else +typedef void SIGFOX_TX_CONTROL_status_t; +#endif + +typedef enum { + SIGFOX_TX_CONTROL_RESULT_ALLOWED, + SIGFOX_TX_CONTROL_RESULT_FORBIDDEN, + SIGFOX_TX_CONTROL_RESULT_PENDING +} SIGFOX_TX_CONTROL_result_t; + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \brief Sigfox TX control driver callback functions. + * \fn SIGFOX_TX_CONTROL_process_cb_t To be called when the TX control needs to be processed. + * \fn SIGFOX_TX_CONTROL_check_cplt_cb_t To be called when the TX control check is complete. + *******************************************************************/ +typedef void (*SIGFOX_TX_CONTROL_process_cb_t)(void); +typedef void (*SIGFOX_TX_CONTROL_check_cplt_cb_t)(void); +#endif + +/*!****************************************************************** + * \enum SIGFOX_TX_CONTROL_check_type + * \brief TX control check type. + *******************************************************************/ +typedef enum { + SIGFOX_TX_CONTROL_TYPE_PRE_CHECK, + SIGFOX_TX_CONTROL_TYPE_POST_CHECK, + SIGFOX_TX_CONTROL_TYPE_LAST +} SIGFOX_TX_CONTROL_check_type; + +/*!****************************************************************** + * \struct SIGFOX_TX_CONTROL_parameters_t + * \brief Parameters for TX control check. + *******************************************************************/ +typedef struct { + SIGFOX_TX_CONTROL_check_type type; + sfx_u8 bitstream_length_bytes; + sfx_bool last_message_frame; +#ifndef SINGLE_FRAME + SIGFOX_ul_frame_rank_t ul_frame_rank; + sfx_u8 number_of_frames; +#endif +#ifndef UL_BIT_RATE + sfx_u16 ul_bit_rate_bps; +#endif +#ifdef BIDIRECTIONAL + sfx_bool ack_message; +#endif +#if !(defined SINGLE_FRAME) || (defined BIDIRECTIONAL) + sfx_u32 interframe_ms; // Tifu, Tifb or Tconf. +#endif +#ifdef CERTIFICATION +#ifdef SPECTRUM_ACCESS_FH + sfx_bool fh_timer_enable; +#endif +#ifdef SPECTRUM_ACCESS_LBT + sfx_bool lbt_enable; +#endif +#endif +#ifdef ASYNCHRONOUS + SIGFOX_TX_CONTROL_check_cplt_cb_t cplt_cb; +#endif +} SIGFOX_TX_CONTROL_parameters_t; + +/*!****************************************************************** + * \struct SIGFOX_TX_CONTROL_config_t + * \brief Sigfox TX control configuration structure. + *******************************************************************/ +typedef struct { + const SIGFOX_rc_t *rc; +#ifdef ASYNCHRONOUS + SIGFOX_TX_CONTROL_process_cb_t process_cb; +#endif +} SIGFOX_TX_CONTROL_config_t; + +/*** SIGFOX TX CONTROL functions ***/ + +/*!****************************************************************** + * \fn SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_open(SIGFOX_TX_CONTROL_config_t *config) + * \brief Open the TX control driver. + * \param[in] config: Pointer to the TX control configuration. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_open(SIGFOX_TX_CONTROL_config_t *config); + +/*!****************************************************************** + * \fn SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_check(SIGFOX_TX_CONTROL_parameters_t *params) + * \brief Start TX control operation. + * \brief In asynchronous mode, the check completion should be notified by calling the given cplt_cb() function. + * \param[in] params: Pointers to the TX control parameters. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_check(SIGFOX_TX_CONTROL_parameters_t *params); + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \fn SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_process(void) + * \brief Process TX CONTROL driver, this function will be call by SIGFOX_EP_API_process just after the process_callback has been sent to process TX control interruptions in main context. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_process(void); +#endif + +/*!****************************************************************** + * \fn sfx_bool SIGFOX_TX_CONTROL_is_radio_required(SIGFOX_TX_CONTROL_check_type check_type) + * \brief Indicate if the RF_API is required to perform the given check. + * \param[in] none + * \param[out] none + * \retval SFX_TRUE if the radio is required; SFX_FALSE otherwise. + *******************************************************************/ +sfx_bool SIGFOX_TX_CONTROL_is_radio_required(SIGFOX_TX_CONTROL_check_type check_type); + +/*!****************************************************************** + * \fn SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_get_result(SIGFOX_TX_CONTROL_result_t *result) + * \brief Get last TX control operation result + * \param[in] none + * \param[out] result: Pointer that will contain the TX control result. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_get_result(SIGFOX_TX_CONTROL_result_t *result); + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_TX_CONTROL_stack_error(void) + * \brief Generic macro which calls the error stack function for TX control errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define SIGFOX_TX_CONTROL_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_TX_CONTROL, tx_control_status) +#else +#define SIGFOX_TX_CONTROL_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_TX_CONTROL_check_status(error) + * \brief Generic macro to check a SIGFOX_TX_CONTROL function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define SIGFOX_TX_CONTROL_check_status(error) { if (tx_control_status != SIGFOX_TX_CONTROL_SUCCESS) { SIGFOX_TX_CONTROL_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* REGULATORY */ + +#endif /* __SIGFOX_TX_CONTROL_H__ */ diff --git a/inc/manuf/mcu_api.h b/inc/manuf/mcu_api.h new file mode 100644 index 0000000..6909c92 --- /dev/null +++ b/inc/manuf/mcu_api.h @@ -0,0 +1,339 @@ +/*!***************************************************************** + * \file mcu_api.h + * \brief MCU drivers. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __MCU_API_H__ +#define __MCU_API_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +/*** MCU API structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum MCU_API_status_t + * \brief MCU driver error codes. + *******************************************************************/ +typedef enum { + MCU_API_SUCCESS = 0, + MCU_API_ERROR + // Additional custom error codes can be added here (up to sfx_u32). + // They will be logged in the library error stack if the ERROR_STACK flag is defined. +} MCU_API_status_t; +#else +typedef void MCU_API_status_t; +#endif + +#ifdef ASYNCHRONOUS +/******************************** + * \brief MCU driver callback functions. + * \fn MCU_API_process_cb_t To be called when the MCU driver needs to be processed. + * \fn MCU_API_error_cb_t To be called when an error occurs during MCU operation. + * \fn MCU_API_timer_cplt_cb_t To be called when a timer ellapses. + *******************************/ +typedef void (*MCU_API_process_cb_t)(void); +#ifdef ERROR_CODES +typedef void (*MCU_API_error_cb_t)(MCU_API_status_t status); +#else +typedef void (*MCU_API_error_cb_t)(void); +#endif +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +typedef void (*MCU_API_timer_cplt_cb_t)(void); +#endif +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +/*!****************************************************************** + * \enum MCU_API_timer_instance_t + * \brief MCU timer instances. + *******************************************************************/ +typedef enum { + MCU_API_TIMER_1, +#ifdef BIDIRECTIONAL + MCU_API_TIMER_2, +#endif +#ifdef CERTIFICATION + MCU_API_TIMER_3, +#endif + MCU_API_TIMER_LAST +} MCU_API_timer_instance_t; +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +/*!****************************************************************** + * \struct MCU_API_timer_t + * \brief MCU API timer structure. + *******************************************************************/ +typedef struct { + MCU_API_timer_instance_t instance; + sfx_u32 duration_ms; +#ifdef ASYNCHRONOUS + MCU_API_timer_cplt_cb_t cplt_cb; +#endif +} MCU_API_timer_t; +#endif + +/*!****************************************************************** + * \struct MCU_API_encryption_data_t + * \brief MCU API encryption data structure. + *******************************************************************/ +typedef struct { + sfx_u8 *data; + sfx_u8 data_size_bytes; +#ifdef PUBLIC_KEY_CAPABLE + SIGFOX_ep_key_t key; +#endif +} MCU_API_encryption_data_t; + +/*!****************************************************************** + * \struct MCU_API_config_t + * \brief MCU API configuration structure. + *******************************************************************/ +typedef struct { + const SIGFOX_rc_t *rc; +#ifdef ASYNCHRONOUS + MCU_API_process_cb_t process_cb; + MCU_API_error_cb_t error_cb; +#endif +} MCU_API_config_t; + +/*** MCU API functions ***/ + +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_open(MCU_API_config_t *mcu_api_config) + * \brief Open the MCU driver. + * \param[in] mcu_api_config: Pointer to the MCU API configuration. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_open(MCU_API_config_t *mcu_api_config); +#endif + +#ifdef LOW_LEVEL_OPEN_CLOSE +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_close(void) + * \brief Close the MCU driver. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_close(void); +#endif + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \fn void MCU_API_process(void) + * \brief Process MCU driver, this function will be call by SIGFOX_EP_API_process just after the process_callback has been sent to process MCU interruptions in main context. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_process(void); +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_timer_start(MCU_API_timer_t *timer) + * \brief Start a timer. Timer completion should be notified by calling the given cplt_cb() function. + * \param[in] timer: Pointer to the timer structure to start. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_timer_start(MCU_API_timer_t *timer); +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_timer_stop(MCU_API_timer_instance_t timer_instance) + * \brief Stop a timer. + * \param[in] timer_instance: Timer to stop. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_timer_stop(MCU_API_timer_instance_t timer_instance); +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +#ifndef ASYNCHRONOUS +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_timer_wait_cplt(MCU_API_timer_instance_t timer_instance) + * \brief Blocking function waiting for timer completion. + * \param[in] timer_instance: Timer to wait for. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_timer_wait_cplt(MCU_API_timer_instance_t timer_instance); +#endif +#endif + +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_aes_128_cbc_encrypt(MCU_API_encryption_data_t *aes_data) + * \brief Function performing the AES-128 encryption algorithm with specified key (for uplink UL-AUTH field computing and downlink frame authentication). + * \param[in] aes_data: AES data structure. + * \param[out] none. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_aes_128_cbc_encrypt(MCU_API_encryption_data_t *aes_data); + +#ifdef CRC_HW +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_compute_crc16(sfx_u8 *data, sfx_u8 data_size, sfx_u16 polynom, sfx_u16 *crc) + * \brief Compute a CRC16. + * \param[in] data: Input data. + * \param[in] data_size: Number of bytes of the input data. + * \param[in] polynom: CRC polynom to use. + * \param[out] crc: Pointer to the computed CRC16 value. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_compute_crc16(sfx_u8 *data, sfx_u8 data_size, sfx_u16 polynom, sfx_u16 *crc); +#endif + +#if (defined CRC_HW) && (defined BIDIRECTIONAL) +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_compute_crc8(sfx_u8 *data, sfx_u8 data_size, sfx_u16 polynom, sfx_u8 *crc) + * \brief Compute a CRC8. + * \param[in] data: Input data. + * \param[in] data_size: Number of bytes of the input data. + * \param[in] polynom: CRC polynom to use. + * \param[out] crc: Pointer to the computed CRC8 value. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_compute_crc8(sfx_u8 *data, sfx_u8 data_size, sfx_u16 polynom, sfx_u8 *crc); +#endif + +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_get_ep_id(sfx_u8 *ep_id, sfx_u8 ep_id_size_bytes) + * \brief Get end-point ID. + * \param[in] ep_id_size_bytes: Number of bytes of the ID to read. + * \param[out] ep_id: End-point ID. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_get_ep_id(sfx_u8 *ep_id, sfx_u8 ep_id_size_bytes); + +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_get_nvm(sfx_u8 *nvm_data, sfx_u8 nvm_data_size_bytes) + * \brief Read NVM data. + * \param[in] nvm_data_size_bytes: Number of bytes to read. + * \param[out] nvm_data: Read NVM data. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_get_nvm(sfx_u8 *nvm_data, sfx_u8 nvm_data_size_bytes); + +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_set_nvm(sfx_u8 *nvm_data, sfx_u8 nvm_data_size_bytes) + * \brief Write NVM data. + * \param[in] nvm_data: NVM data to write. + * \param[in] nvm_data_size_bytes: Number of bytes to write. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_set_nvm(sfx_u8 *nvm_data, sfx_u8 nvm_data_size_bytes); + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_get_voltage_temperature(sfx_u16 *voltage_idle_mv, sfx_u16 *voltage_tx_mv, sfx_s16 *temperature_tenth_degrees) + * \brief Get voltage and temperature measurements (used in control message payload). + * \param[out] voltage_idle_mv: Device power supply voltage in mV measured in idle state. + * \param[out] voltage_tx_mv: Device power supply voltage in mV measured during TX operation. + * \param[out] temperature_tenth_degrees: Device temperature in 1/10 degrees. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_get_voltage_temperature(sfx_u16 *voltage_idle_mv, sfx_u16 *voltage_tx_mv, sfx_s16 *temperature_tenth_degrees); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_get_initial_pac(sfx_u8 *initial_pac, sfx_u8 initial_pac_size_bytes) + * \brief Get device initital PAC code. + * \param[in] initial_pac_size_bytes: Number of bytes of the PAC to read (full size is SIGFOX_EP_PAC_SIZE_BYTES). + * \param[out] initial_pac: Initial PAC. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_get_initial_pac(sfx_u8 *initial_pac, sfx_u8 initial_pac_size_bytes); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn MCU_API_status_t MCU_API_get_version(sfx_u8 **version, sfx_u8 *version_size_char) + * \brief Get MCU driver version. + * \param[in] none + * \param[out] version: MCU driver version. + * \param[out] version_size_char: Pointer that will contain the string size. + * \retval Function execution status. + *******************************************************************/ +MCU_API_status_t MCU_API_get_version(sfx_u8 **version, sfx_u8 *version_size_char); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void MCU_API_error(void) + * \brief Function called by the library if any error occurred during the processing. + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +void MCU_API_error(void); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void MCU_API_stack_error(void) + * \brief Generic macro which calls the error stack function for MCU errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define MCU_API_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_MCU, mcu_status) +#else +#define MCU_API_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void MCU_API_check_status(error) + * \brief Generic macro to check an MCU_API function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define MCU_API_check_status(error) { if (mcu_status != MCU_API_SUCCESS) { MCU_API_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* __MCU_API_H__ */ diff --git a/inc/manuf/rf_api.h b/inc/manuf/rf_api.h new file mode 100644 index 0000000..b941347 --- /dev/null +++ b/inc/manuf/rf_api.h @@ -0,0 +1,347 @@ +/*!***************************************************************** + * \file rf_api.h + * \brief Radio drivers. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __RF_API_H__ +#define __RF_API_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +/*** RF API structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum RF_API_status_t + * \brief RF driver error codes. + *******************************************************************/ +typedef enum { + RF_API_SUCCESS = 0, + RF_API_ERROR + // Additional custom error codes can be added here (up to sfx_u32). + // They will be logged in the library error stack if the ERROR_STACK flag is defined. +} RF_API_status_t; +#else +typedef void RF_API_status_t; +#endif + +#ifdef ASYNCHRONOUS +/******************************** + * \brief RF driver callback functions. + * \fn RF_API_process_cb_t To be called when the RF driver needs to be processed. + * \fn RF_API_error_cb_t To be called when an error occurs during RF operation. + * \fn RF_API_tx_cplt_cb_t To be called when a frame transmission is complete. + * \fn RF_API_rx_data_received_cb_t To be called when a diwnlink frame is received. + * \fn RF_API_channel_free_cb_t To be called when the carrier sense operation is complete. + *******************************/ +typedef void (*RF_API_process_cb_t)(void); +#ifdef ERROR_CODES +typedef void (*RF_API_error_cb_t)(RF_API_status_t status); +#else +typedef void (*RF_API_error_cb_t)(void); +#endif +typedef void (*RF_API_tx_cplt_cb_t)(void); +#ifdef BIDIRECTIONAL +typedef void (*RF_API_rx_data_received_cb_t)(void); +#endif +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) +typedef void (*RF_API_channel_free_cb_t)(void); +#endif +#endif + +/*!****************************************************************** + * \enum RF_API_mode_t + * \brief RF modes list. + *******************************************************************/ +typedef enum { + RF_API_MODE_TX, +#if (defined BIDIRECTIONAL) || ((defined REGULATORY && (defined SPECTRUM_ACCESS_LBT))) + RF_API_MODE_RX, +#endif + RF_API_MODE_LAST +} RF_API_mode_t; + +/*!****************************************************************** + * \enum RF_API_modulation_t + * \brief RF modulations list. + *******************************************************************/ +typedef enum { + RF_API_MODULATION_NONE, + RF_API_MODULATION_DBPSK, + RF_API_MODULATION_GFSK, + RF_API_MODULATION_LAST +} RF_API_modulation_t; + +/*!****************************************************************** + * \struct RF_API_radio_parameters_t + * \brief Radio parameters structure. + *******************************************************************/ +typedef struct { + RF_API_mode_t rf_mode; + sfx_u32 frequency_hz; + RF_API_modulation_t modulation; + sfx_u16 bit_rate_bps; + sfx_s8 tx_power_dbm_eirp; +#ifdef BIDIRECTIONAL + sfx_u32 deviation_hz; +#endif +} RF_API_radio_parameters_t; + +/*!****************************************************************** + * \struct RF_API_tx_data_t + * \brief RF TX data structure. + *******************************************************************/ +typedef struct { + sfx_u8 *bitstream; + sfx_u8 bitstream_size_bytes; +#ifdef ASYNCHRONOUS + RF_API_tx_cplt_cb_t cplt_cb; +#endif +} RF_API_tx_data_t; + +/*!****************************************************************** + * \struct RF_API_rx_data_t + * \brief RF RX data structure. + *******************************************************************/ +typedef struct { + sfx_u8 dl_phy_content_size; +#if (defined ASYNCHRONOUS) && (defined BIDIRECTIONAL) + RF_API_rx_data_received_cb_t data_received_cb; +#else + sfx_bool data_received; +#endif +} RF_API_rx_data_t; + +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) +/*!****************************************************************** + * \struct RF_API_carrier_sense_parameters_t + * \brief RF carrier sense parameters structure. + *******************************************************************/ +typedef struct { + sfx_u32 bandwidth_hz; + sfx_s8 threshold_dbm; + sfx_u32 min_duration_ms; +#ifdef ASYNCHRONOUS + RF_API_channel_free_cb_t channel_free_cb; +#else + sfx_bool *channel_free; +#endif +} RF_API_carrier_sense_parameters_t; +#endif + +/*!****************************************************************** + * \struct RF_API_config_t + * \brief RF API configuration structure. + *******************************************************************/ +typedef struct { + const SIGFOX_rc_t *rc; +#ifdef ASYNCHRONOUS + RF_API_process_cb_t process_cb; + RF_API_error_cb_t error_cb; +#endif +} RF_API_config_t; + +/*** RF API functions ***/ + +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) +/*!****************************************************************** + * \fn RF_API_status_t RF_API_open(RF_API_config_t *rf_api_config) + * \brief Open the RF driver. + * \param[in] rf_api_config: Pointer to the RF API configuration. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_open(RF_API_config_t *rf_api_config); +#endif + +#ifdef LOW_LEVEL_OPEN_CLOSE +/*!****************************************************************** + * \fn RF_API_status_t RF_API_close(void) + * \brief Close the RF driver. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_close(void); +#endif + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \fn RF_API_status_t RF_API_process(void) + * \brief Process RF driver, this function will be call by SIGFOX_EP_API_process just after the process_callback has been sent to process RF interruptions in main context. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_process(void); +#endif + +/*!****************************************************************** + * \fn RF_API_status_t RF_API_wake_up(void) + * \brief Wake-up the radio before each overall TX or RX sequence. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_wake_up(void); + +/*!****************************************************************** + * \fn RF_API_status_t RF_API_sleep(void) + * \brief Release the radio after each overall TX or RX sequence. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_sleep(void); + +/*!****************************************************************** + * \fn RF_API_status_t RF_API_init(RF_API_radio_parameters_t *radio_parameters) + * \brief Initialize the radio operation before each individual frame transmission or reception. + * \param[in] radio_parameters: Pointers to the radio parameters. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_init(RF_API_radio_parameters_t *radio_parameters); + +/*!****************************************************************** + * \fn RF_API_status_t RF_API_de_init(void) + * \brief Stop the radio operation after each individual frame transmission or reception. + * \param[in] rf_mode: Radio mode. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_de_init(void); + +/*!****************************************************************** + * \fn RF_API_status_t RF_API_send(RF_API_tx_data_t *tx_data) + * \brief Sending a bitstream over the air. + * \brief In blocking mode, this function blocks until the full bitstream is sent. + * \brief In asynchronous, this function only starts the transmission. End of transmission should be notified through the cplt_cb() callback. + * \param[in] tx_data: Pointer to the TX parameters. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_send(RF_API_tx_data_t *tx_data); + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \fn RF_API_status_t RF_API_receive(RF_API_rx_data_t *rx_data) + * \brief Start downlink reception. Could be called multiple times if several downlink frames are received during the RX window. + * \brief In blocking mode, this function blocks until a valid downlink data is received or the MCU_API_TIMER_2 has elapsed. + * \brief In asynchronous mode, this function only starts the reception. Data reception should be notified through the rx_data_received() callback. + * \param[in] rx_data: Pointer to the RX parameters. + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_receive(RF_API_rx_data_t *rx_data); +#endif + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \fn RF_API_status_t RF_API_get_dl_phy_content_and_rssi(sfx_u8 *dl_phy_content, sfx_u8 dl_phy_content_size, sfx_s16 *dl_rssi_dbm) + * \brief Read DL-PHY content and RSSI received by the radio. + * \brief In blocking mode, this function will be called only if the data_received parameter of the RF_API_receive() function is returned with SFX_TRUE value. + * \brief in asynchronous mode, this function will be called only if the data_received_cb callback is triggered during reception. + * \param[in] dl_phy_content_size: Number of bytes to copy in dl_phy_content. + * \param[out] dl_phy_content: Array to be filled with the received DL-PHY content. + * \param[out] dl_rssi_dbm: Pointer to 16-bits signed value to be filled with the DL RSSI in dBm. + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_get_dl_phy_content_and_rssi(sfx_u8 *dl_phy_content, sfx_u8 dl_phy_content_size, sfx_s16 *dl_rssi_dbm); +#endif + +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) +/*!****************************************************************** + * \fn RF_API_status_t RF_API_carrier_sense(RF_API_carrier_sense_parameters_t *carrier_sense_params) + * \brief In blocking mode, the function until the LBT condition is met or the MCU_API_TIMER_1 has elapsed. + * \brief In asynchronous mode, this function only starts the carrier sense operation. Channel free event should be notified through the channel_free_cb() callback. + * \param[in] carrier_sense_params: Pointer to the carrier sense parameters. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_carrier_sense(RF_API_carrier_sense_parameters_t *carrier_sense_params); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn RF_API_status_t RF_API_get_version(sfx_u8 **version, sfx_u8 *version_size_char) + * \brief Get RF driver version. + * \param[in] none + * \param[out] version: RF driver version. + * \param[out] version_size_char: Pointer tha will contain the string size. + * \retval Function execution status. + *******************************************************************/ +RF_API_status_t RF_API_get_version(sfx_u8 **version, sfx_u8 *version_size_char); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void RF_API_error(void) + * \brief Function called by the library if any error occurred during the processing. + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +void RF_API_error(void); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void RF_API_stack_error(void) + * \brief Generic macro which calls the error stack function for RF errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define RF_API_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_RF, rf_status) +#else +#define RF_API_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void RF_API_check_status(error) + * \brief Generic macro to check an RF_API function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define RF_API_check_status(error) { if (rf_status != RF_API_SUCCESS) { RF_API_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* __RF_API_H__ */ diff --git a/inc/sigfox_ep_api.h b/inc/sigfox_ep_api.h new file mode 100644 index 0000000..0b1aae1 --- /dev/null +++ b/inc/sigfox_ep_api.h @@ -0,0 +1,402 @@ +/*!***************************************************************** + * \file sigfox_ep_api.h + * \brief Sigfox End-Point library API. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_EP_API_H__ +#define __SIGFOX_EP_API_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" +#include "sigfox_error.h" + +/*** SIGFOX EP API structures ***/ + +#ifdef ERROR_CODES +/*!****************************************************************** + * \enum SIGFOX_EP_API_status_t + * \brief Sigfox EP library error codes. + *******************************************************************/ +typedef enum { + // Core library errors. + SIGFOX_EP_API_SUCCESS = 0, + SIGFOX_EP_API_ERROR_NULL_PARAMETER, + SIGFOX_EP_API_ERROR_RC, + SIGFOX_EP_API_ERROR_MESSAGE_TYPE, + SIGFOX_EP_API_ERROR_UL_PAYLOAD_SIZE, + SIGFOX_EP_API_ERROR_DL_PAYLOAD_SIZE, + SIGFOX_EP_API_ERROR_DL_PAYLOAD_UNAVAILABLE, + SIGFOX_EP_API_ERROR_EP_ID, + SIGFOX_EP_API_ERROR_EP_PAC, + SIGFOX_EP_API_ERROR_EP_KEY, + SIGFOX_EP_API_ERROR_STATE, + SIGFOX_EP_API_ERROR_RF_MODE, + SIGFOX_EP_API_ERROR_MODULATION, + SIGFOX_EP_API_ERROR_BIT_RATE, + SIGFOX_EP_API_ERROR_TX_POWER, + SIGFOX_EP_API_ERROR_NUMBER_OF_FRAMES, + SIGFOX_EP_API_ERROR_T_IFU, + SIGFOX_EP_API_ERROR_T_CONF, + SIGFOX_EP_API_ERROR_MESSAGE_COUNTER_ROLLOVER, + SIGFOX_EP_API_ERROR_TX_FORBIDDEN, + SIGFOX_EP_API_ERROR_VERSION, + // Low level errors. + // Activate the ERROR_STACK flag and use the SIGFOX_EP_API_unstack_error() function to get more details. + SIGFOX_EP_API_ERROR_MCU, + SIGFOX_EP_API_ERROR_RF, + SIGFOX_EP_API_ERROR_BITSTREAM, + SIGFOX_EP_API_ERROR_FREQUENCY, + SIGFOX_EP_API_ERROR_NVM, + SIGFOX_EP_API_ERROR_TX_CONTROL +} SIGFOX_EP_API_status_t; +#else +typedef void SIGFOX_EP_API_status_t; +#endif + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \enum SIGFOX_EP_API_state_t + * \brief Sigfox EP library state. + *******************************************************************/ +typedef enum { + SIGFOX_EP_API_STATE_CLOSED, + SIGFOX_EP_API_STATE_READY, +#ifdef REGULATORY + SIGFOX_EP_API_STATE_REGULATORY, +#endif + SIGFOX_EP_API_STATE_UL_MODULATION_PENDING, +#if !(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0) || (defined BIDIRECTIONAL)) + SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER, +#endif +#ifdef BIDIRECTIONAL + SIGFOX_EP_API_STATE_DL_TIMER, + SIGFOX_EP_API_STATE_DL_LISTENING, + SIGFOX_EP_API_STATE_DL_CONFIRMATION_TIMER, + SIGFOX_EP_API_STATE_DL_CONFIRMATION, +#endif + SIGFOX_EP_API_STATE_LAST +} SIGFOX_EP_API_state_t; +#endif + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \brief Sigfox EP library callback functions. + * \fn SIGFOX_EP_API_process_cb_t: Will be called each time a low level IRQ is handled by the library. Warning: runs in a IRQ context. Should only change variables state, and call as soon as possible @ref SIGFOX_EP_API_process. + * \fn SIGFOX_EP_API_uplink_cplt_cb_t: Will be called when the TX sequence is done (1 to 3 frames). Optional, could be set to NULL. + * \fn SIGFOX_EP_API_downlink_cplt_cb: Will be called if a valid downlink frame has been received. Optional, could be set to NULL. + * \fn SIGFOX_EP_API_message_cplt_cb: Will be called when the whole message process is finished, indicating that the library is ready again for a new operation. Optional, could be set to NULL. + *******************************************************************/ +typedef void (*SIGFOX_EP_API_process_cb_t)(void); +typedef void (*SIGFOX_EP_API_uplink_cplt_cb_t)(void); +#ifdef BIDIRECTIONAL +typedef void (*SIGFOX_EP_API_downlink_cplt_cb)(void); +#endif +typedef void (*SIGFOX_EP_API_message_cplt_cb)(void); +#endif + +/*!****************************************************************** + * \struct SIGFOX_EP_API_config_t + * \brief Sigfox EP library configuration structure. + *******************************************************************/ +typedef struct { + const SIGFOX_rc_t *rc; +#ifdef ASYNCHRONOUS + SIGFOX_EP_API_process_cb_t process_cb; +#endif +#ifndef MESSAGE_COUNTER_ROLLOVER + SIGFOX_message_counter_rollover_t message_counter_rollover; +#endif +} SIGFOX_EP_API_config_t; + +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) +/*!****************************************************************** + * \struct SIGFOX_EP_API_common_t + * \brief Common parameters of application and control messages structures. + *******************************************************************/ +typedef struct { +#ifndef UL_BIT_RATE_BPS + SIGFOX_ul_bit_rate_t ul_bit_rate; +#endif +#ifndef TX_POWER_DBM_EIRP + sfx_s8 tx_power_dbm_eirp; +#endif +#ifndef SINGLE_FRAME + sfx_u8 number_of_frames; +#ifndef T_IFU_MS + sfx_u16 t_ifu_ms; +#endif +#endif +#ifdef PUBLIC_KEY_CAPABLE + SIGFOX_ep_key_t ep_key_type; +#endif +} SIGFOX_EP_API_common_t; +#endif + +#ifdef APPLICATION_MESSAGES +/*!****************************************************************** + * \struct SIGFOX_EP_API_application_message_t + * \brief Application message data. + *******************************************************************/ +typedef struct { +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + SIGFOX_EP_API_common_t common_parameters; +#endif + SIGFOX_application_message_type_t type; +#ifdef ASYNCHRONOUS + SIGFOX_EP_API_uplink_cplt_cb_t uplink_cplt_cb; +#ifdef BIDIRECTIONAL + SIGFOX_EP_API_downlink_cplt_cb downlink_cplt_cb; +#endif + SIGFOX_EP_API_message_cplt_cb message_cplt_cb; +#endif +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + sfx_u8 *ul_payload; +#endif +#ifndef UL_PAYLOAD_SIZE + sfx_u8 ul_payload_size_bytes; +#endif +#ifdef BIDIRECTIONAL + sfx_u8 bidirectional_flag; +#ifndef T_CONF_MS + sfx_u16 t_conf_ms; +#endif +#endif +} SIGFOX_EP_API_application_message_t; +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*!****************************************************************** + * \struct SIGFOX_EP_API_control_message_t + * \brief Control message data. + *******************************************************************/ +typedef struct { +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + SIGFOX_EP_API_common_t common_parameters; +#endif + SIGFOX_control_message_type_t type; +#ifdef ASYNCHRONOUS + SIGFOX_EP_API_uplink_cplt_cb_t uplink_cplt_cb; + SIGFOX_EP_API_message_cplt_cb message_cplt_cb; +#endif +} SIGFOX_EP_API_control_message_t; +#endif + +/*!****************************************************************** + * \union SIGFOX_EP_API_message_status_t + * \brief Message status bitfield. + *******************************************************************/ +typedef union { + struct { + unsigned app_frame_1 : 1; + unsigned app_frame_2 : 1; + unsigned app_frame_3 : 1; + unsigned downlink_frame : 1; + unsigned ack_frame : 1; + unsigned error : 1; + }; + sfx_u8 all; +} SIGFOX_EP_API_message_status_t; + +/*** SIGFOX EP API functions ***/ + +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_open(SIGFOX_EP_API_config_t *config) + * \brief Open the EP library. + * \param[in] config: Pointer to the library configuration. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_open(SIGFOX_EP_API_config_t *config); + +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_close(void) + * \brief Close the EP library. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_close(void); + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_process(void) + * \brief Main process function of the library. This function should be called as soon as possible when the process callback is triggered. + * \param[in] none + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_process(void); +#endif + +#ifdef APPLICATION_MESSAGES +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_send_application_message(SIGFOX_EP_API_application_message_t *application_message) + * \brief Send an application message over Sigfox network. + * \param[in] application_message: Pointer to the application message data. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_send_application_message(SIGFOX_EP_API_application_message_t *application_message); +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_send_control_message(SIGFOX_EP_API_control_message_t *control_message) + * \brief Send a control message over Sigfox network. + * \param[in] control_message: Pointer to the control message data. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_send_control_message(SIGFOX_EP_API_control_message_t *control_message); +#endif + +#ifdef BIDIRECTIONAL +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_get_dl_payload(sfx_u8 *dl_payload, sfx_u8 dl_payload_size, sfx_s16 *rssi_dbm) + * \brief Get the current message status. + * \param[in] dl_payload: Byte array that will contain the downlink payload. + * \param[in] dl_payload_size: Number of bytes to read. + * \param[in] dl_rssi_dbm: Pointer to 16-bits signed value that will contain the RSSI of the received downlink frame. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_dl_payload(sfx_u8 *dl_payload, sfx_u8 dl_payload_size, sfx_s16 *rssi_dbm); +#endif + +/*!****************************************************************** + * \fn SIGFOX_EP_API_message_status_t SIGFOX_EP_API_get_message_status(void) + * \brief Get the current message status. + * \param[in] none + * \param[out] none + * \retval Status of the last transmission. + *******************************************************************/ +SIGFOX_EP_API_message_status_t SIGFOX_EP_API_get_message_status(void); + +#ifdef ASYNCHRONOUS +/*!****************************************************************** + * \fn SIGFOX_EP_API_state_t SIGFOX_EP_API_get_state(void) + * \brief Get the current library state. + * \param[in] none + * \param[out] none + * \retval Current library state. + *******************************************************************/ +SIGFOX_EP_API_state_t SIGFOX_EP_API_get_state(void); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_get_ep_id(sfx_u8* ep_id, sfx_u8 ep_id_size_bytes) + * \brief Get EP ID. + * \param[in] ep_id_size_bytes: Number of bytes of the ID to read (full size is SIGFOX_EP_ID_SIZE_BYTES). + * \param[out] ep_id: End-point ID. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_ep_id(sfx_u8* ep_id, sfx_u8 ep_id_size_bytes); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_get_initial_pac(sfx_u8 *initial_pac, sfx_u8 initial_pac_size_bytes) + * \brief Get initial PAC. + * \param[in] initial_pac_size_bytes: Number of bytes of the PAC to read (full size is SIGFOX_EP_PAC_SIZE_BYTES). + * \param[out] initial_pac: Initial PAC. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_initial_pac(sfx_u8 *initial_pac, sfx_u8 initial_pac_size_bytes); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_get_version(SIGFOX_version_t version_type, sfx_u8 **version, sfx_u8 *version_size_char) + * \brief Get EP library version. + * \param[in] version_type: Version to get. + * \param[out] version: Version string. + * \param[out] version_size_char: Pointer that will contain the string size. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_version(SIGFOX_version_t version_type, sfx_u8 **version, sfx_u8 *version_size_char); +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_get_flags(sfx_u8 **ep_flags, sfx_u8 *ep_flags_size_char) + * \brief Get EP library flags. + * \param[in] none + * \param[out] ep_flags: Flags string. + * \param[out] ep_flags_size_char: Pointer that will contain the string size. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_flags(sfx_u8 **ep_flags, sfx_u8 *ep_flags_size_char); +#endif + +#ifdef ERROR_STACK +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_unstack_error(SIGFOX_ERROR_t *error_ptr) + * \brief Read and clear the last (newest) error stored in the internal error stack. + * \brief This function can be called multiple times to unstack all errors which previously occurred during library execution, until it returns SIGFOX_EP_API_SUCCESS. + * \param[in] none + * \param[out] error_ptr: Pointer that will contain the last error in the stack. + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_unstack_error(SIGFOX_ERROR_t *error_ptr); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_EP_API_stack_error(void) + * \brief Generic macro which calls the error stack function for EP library errors (if enabled). + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_STACK +#define SIGFOX_EP_API_stack_error(void) SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_EP_LIBRARY, ep_api_status) +#else +#define SIGFOX_EP_API_stack_error(void) +#endif +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void SIGFOX_EP_API_check_status(error) + * \brief Generic macro to check a SIGFOX_EP_API function status and exit. + * \param[in] error: High level error code to rise. + * \param[out] none + * \retval none + *******************************************************************/ +#define SIGFOX_EP_API_check_status(error) { if (ep_api_status != SIGFOX_EP_API_SUCCESS) { SIGFOX_EP_API_stack_error(); EXIT_ERROR(error) } } +#endif + +#endif /* __SIGFOX_EP_API_H__ */ diff --git a/inc/sigfox_ep_api_test.h b/inc/sigfox_ep_api_test.h new file mode 100644 index 0000000..76b4e63 --- /dev/null +++ b/inc/sigfox_ep_api_test.h @@ -0,0 +1,90 @@ +/*!***************************************************************** + * \file sigfox_ep_api_test.h + * \brief Sigfox End-Point library test API. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_EP_API_TEST_H__ +#define __SIGFOX_EP_API_TEST_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_ep_api.h" +#include "sigfox_types.h" + +#ifdef CERTIFICATION + +/*** SIGFOX EP API TEST structures ***/ + +/*!****************************************************************** + * \struct SIGFOX_EP_API_TEST_parameters_t + * \brief Specific parameters for test (RFP ADDON). + *******************************************************************/ +typedef struct { + sfx_u32 tx_frequency_hz; // If non-zero, bypass the frequency driver of the core library. +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sfx_bool fh_timer_enable; // Enable or disable FH timer. +#endif +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) + sfx_bool lbt_enable; +#endif +} SIGFOX_EP_API_TEST_parameters_t; + +#ifdef APPLICATION_MESSAGES +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_TEST_send_application_message(SIGFOX_EP_API_application_message_t *application_message, SIGFOX_EP_API_TEST_parameters_t *test_parameters) + * \brief Send an application message over Sigfox network. + * \param[in] application_message: Pointer to the application message data. + * \param[in] test_parameters: Pointer to the test parameters. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_TEST_send_application_message(SIGFOX_EP_API_application_message_t *application_message, SIGFOX_EP_API_TEST_parameters_t *test_parameters); +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*!****************************************************************** + * \fn SIGFOX_EP_API_status_t SIGFOX_EP_API_TEST_send_control_message(SIGFOX_EP_API_control_message_t *control_message, SIGFOX_EP_API_TEST_parameters_t *test_parameters) + * \brief Send a control message over Sigfox network. + * \param[in] control_message: Pointer to the control message data. + * \param[in] test_parameters: Pointer to the test parameters. + * \param[out] none + * \retval Function execution status. + *******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_TEST_send_control_message(SIGFOX_EP_API_control_message_t *control_message, SIGFOX_EP_API_TEST_parameters_t *test_parameters); +#endif + +#endif /* CERTIFICATION */ + +#endif /* __SIGFOX_EP_API_TEST_H__ */ diff --git a/inc/sigfox_ep_flags.h b/inc/sigfox_ep_flags.h new file mode 100644 index 0000000..9cc5867 --- /dev/null +++ b/inc/sigfox_ep_flags.h @@ -0,0 +1,101 @@ +/*!***************************************************************** + * \file sigfox_ep_flags.h + * \brief Sigfox End-Point library compilations flags definition. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_EP_FLAGS_H__ +#define __SIGFOX_EP_FLAGS_H__ + +/*** Library compilation flags ***/ + +#define RC1 /*!< \brief Support radio configuration zone 1 (Europe, Middle-East and Africa). > */ +#define RC2 /*!< \brief Support radio configuration zone 2 (Brazil, Canada, Mexico, Puerto Rico and USA). > */ +#define RC3C /*!< \brief Support radio configuration zone 3 (Japan) with LBT. > */ +#define RC3D /*!< \brief Support radio configuration zone 3 (Japan) with DC. */ +#define RC4 /*!< \brief Support radio configuration zone 4 (Latin America and Asia Pacific). > */ +#define RC5 /*!< \brief Support radio configuration zone 5 (South-Corea). > */ +#define RC6 /*!< \brief Support radio configuration zone 6 (India). > */ +#define RC7 /*!< \brief Support radio configuration zone 7 (Russia). > */ + +#define APPLICATION_MESSAGES /*!< \brief Support uplink application messages if defined. > */ +#define CONTROL_KEEP_ALIVE_MESSAGE /*!< \brief Support uplink control keep alive message if defined. > */ + +#define BIDIRECTIONAL /*!< \brief Support bidirectional procedure (downlink) if defined. Only applicable to application messages. > */ + /*!< \brief Otherwise all messages will be uplink only. > */ + +#define ASYNCHRONOUS /*!< \brief Asynchronous mode if defined, blocking mode otherwise. > */ + +#define LOW_LEVEL_OPEN_CLOSE /*!< \brief Enable MCU and RF open/close functions if defined. > */ + +#define REGULATORY /*!< \brief Enable radio regulatory control (DC, FH or LBT check) if defined. > */ + +//#define SINGLE_FRAME /*!< \brief Send 1 frame per message (N=1) if defined. > */ + /*!< \brief Otherwise number of frames per message is dynamically given when sending a message (N=1, N=2 or N=3). > */ + +//#define UL_BIT_RATE_BPS 100 /*!< \brief If defined, give the only uplink bit rate supported (100 or 600 depending on the RC). > */ + /*!< \brief Otherwise, value is dynamically given when sending a message. > */ + +//#define TX_POWER_DBM_EIRP 16 /*!< \brief If defined, give the only TX power supported by the radio. > */ + /*!< \brief Otherwise the value is dynamically given when sending a message. > */ + +//#define T_IFU_MS 500 /*!< \brief If defined, give the fixed inter-frame delay used between uplink frames of a same message (0 to 2000ms). > */ + /*!< \brief Value 0 disables the delay and associated timers to optimize memory space. > */ + /*!< \brief Otherwise value is dynamically given when sending a message. > */ + +//#define T_CONF_MS 2000 /*!< \brief If defined, give the fixed delay between downlink frame reception and uplink confirmation message (1400 to 4000ms). > */ + /*!< \brief Otherwise value is dynamically given when sending a message. > */ + +//#define UL_PAYLOAD_SIZE 0 /*!< \brief If defined, give the only uplink payload length supported (0 to 12). > */ + /*!< \brief Value 0 enables the bit 0, bit 1 and empty messages. > */ + /*!< \brief Otherwise, all uplink payload lengths are dynamically supported. > */ + +//#define CRC_HW /*!< \brief If defined, enable hardware CRC through MCU API functions. Otherwise the embedded driver is used. > */ + +//#define MESSAGE_COUNTER_ROLLOVER 4096 /*!< \brief If defined, give the only message counter rollover value supported. > */ + /*!< \brief Otherwise, value is dynamically given when opening the library. > */ + +#define PARAMETERS_CHECK /*!< \brief Enable parameters check if defined. > */ + +#define CERTIFICATION /*!< \brief Enable certification features if defined. > */ + +#define PUBLIC_KEY_CAPABLE /*!< \brief Enable public key switch feature if defined. > */ + +#define VERBOSE /*!< \brief Enable credentials (ID/PAC) API access and version control functions if defined. > */ + +#define ERROR_CODES /*!< \brief Use return codes if defined, otherwise all functions return void. > */ + +#define ERROR_STACK 32 /*!< \brief If defined, store low level errors in a stack (the macro gives the depth). > */ + /*!< \brief Errors can be read with the SIGFOX_EP_API_unstack_error() function. > */ + +#endif /* __SIGFOX_EP_FLAGS_H__ */ diff --git a/inc/sigfox_ep_version.h b/inc/sigfox_ep_version.h new file mode 100644 index 0000000..61d3308 --- /dev/null +++ b/inc/sigfox_ep_version.h @@ -0,0 +1,250 @@ +/*!***************************************************************** + * \file sigfox_ep_version.h + * \brief Sigfox End-Point library version. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_EP_VERSION_H__ +#define __SIGFOX_EP_VERSION_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif + +/*** Main version ***/ + +#define SIGFOX_EP_VERSION "3.0" + +/*** Compilation flags ***/ + +#define SIGFOX_VERSION_SEPARATOR " " + +#ifdef USE_SIGFOX_EP_FLAGS_H +#define FLAGS_OPT "SIGFOX_EP_FLAGS_H" +#else +#define FLAGS_OPT "COMMAND_LINE_FLAGS" +#endif + +#ifdef RC1 +#define RC1_OPT SIGFOX_VERSION_SEPARATOR "RC1" +#else +#define RC1_OPT +#endif + +#ifdef RC2 +#define RC2_OPT SIGFOX_VERSION_SEPARATOR "RC2" +#else +#define RC2_OPT +#endif + +#ifdef RC3C +#define RC3C_OPT SIGFOX_VERSION_SEPARATOR "RC3C" +#else +#define RC3C_OPT +#endif + +#ifdef RC3D +#define RC3D_OPT SIGFOX_VERSION_SEPARATOR "RC3D" +#else +#define RC3D_OPT +#endif + +#ifdef RC4 +#define RC4_OPT SIGFOX_VERSION_SEPARATOR "RC4" +#else +#define RC4_OPT +#endif + +#ifdef RC5 +#define RC5_OPT SIGFOX_VERSION_SEPARATOR "RC5" +#else +#define RC5_OPT +#endif + +#ifdef RC6 +#define RC6_OPT SIGFOX_VERSION_SEPARATOR "RC6" +#else +#define RC6_OPT +#endif + +#ifdef RC7 +#define RC7_OPT SIGFOX_VERSION_SEPARATOR "RC7" +#else +#define RC7_OPT +#endif + +#ifdef APPLICATION_MESSAGES +#define APPLICATION_MESSAGES_OPT SIGFOX_VERSION_SEPARATOR "APPLICATION_MESSAGES" +#else +#define APPLICATION_MESSAGES_OPT +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +#define CONTROL_KEEP_ALIVE_MESSAGE_OPT SIGFOX_VERSION_SEPARATOR "CONTROL_KEEP_ALIVE_MESSAGE" +#else +#define CONTROL_KEEP_ALIVE_MESSAGE_OPT +#endif + +#ifdef BIDIRECTIONAL +#define BIDIRECTIONAL_OPT SIGFOX_VERSION_SEPARATOR "BIDIRECTIONAL" +#else +#define BIDIRECTIONAL_OPT +#endif + +#ifdef ASYNCHRONOUS +#define ASYNCHRONOUS_OPT SIGFOX_VERSION_SEPARATOR "ASYNCHRONOUS" +#else +#define ASYNCHRONOUS_OPT +#endif + +#ifdef LOW_LEVEL_OPEN_CLOSE +#define LOW_LEVEL_OPEN_CLOSE_OPT SIGFOX_VERSION_SEPARATOR "LOW_LEVEL_OPEN_CLOSE" +#else +#define LOW_LEVEL_OPEN_CLOSE_OPT +#endif + +#ifdef REGULATORY +#define REGULATORY_OPT SIGFOX_VERSION_SEPARATOR "REGULATORY" +#else +#define REGULATORY_OPT +#endif + +#ifdef SINGLE_FRAME +#define SINGLE_FRAME_OPT SIGFOX_VERSION_SEPARATOR "SINGLE_FRAME" +#else +#define SINGLE_FRAME_OPT +#endif + +#ifdef UL_BIT_RATE_BPS +#define UL_BIT_RATE_BPS_OPT SIGFOX_VERSION_SEPARATOR "UL_BIT_RATE_BPS" +#else +#define UL_BIT_RATE_BPS_OPT +#endif + +#ifdef T_IFU_MS +#define T_IFU_MS_OPT SIGFOX_VERSION_SEPARATOR "T_IFU_MS" +#else +#define T_IFU_MS_OPT +#endif + +#ifdef T_CONF_MS +#define T_CONF_MS_OPT SIGFOX_VERSION_SEPARATOR "T_CONF_MS" +#else +#define T_CONF_MS_OPT +#endif + +#ifdef UL_PAYLOAD_SIZE +#define UL_PAYLOAD_SIZE_OPT SIGFOX_VERSION_SEPARATOR "UL_PAYLOAD_SIZE" +#else +#define UL_PAYLOAD_SIZE_OPT +#endif + +#ifdef CRC_HW +#define CRC_HW_OPT SIGFOX_VERSION_SEPARATOR "CRC_HW" +#else +#define CRC_HW_OPT +#endif + +#ifdef MESSAGE_COUNTER_ROLLOVER +#define MESSAGE_COUNTER_ROLLOVER_OPT SIGFOX_VERSION_SEPARATOR "MESSAGE_COUNTER_ROLLOVER" +#else +#define MESSAGE_COUNTER_ROLLOVER_OPT +#endif + +#ifdef PARAMETERS_CHECK +#define PARAMETERS_CHECK_OPT SIGFOX_VERSION_SEPARATOR "PARAMETERS_CHECK" +#else +#define PARAMETERS_CHECK_OPT +#endif + +#ifdef CERTIFICATION +#define CERTIFICATION_OPT SIGFOX_VERSION_SEPARATOR "CERTIFICATION" +#else +#define CERTIFICATION_OPT +#endif + +#ifdef PUBLIC_KEY_CAPABLE +#define PUBLIC_KEY_CAPABLE_OPT SIGFOX_VERSION_SEPARATOR "PUBLIC_KEY_CAPABLE" +#else +#define PUBLIC_KEY_CAPABLE_OPT +#endif + +#ifdef VERBOSE +#define VERBOSE_OPT SIGFOX_VERSION_SEPARATOR "VERBOSE" +#else +#define VERBOSE_OPT +#endif + +#ifdef ERROR_CODES +#define ERROR_CODES_OPT SIGFOX_VERSION_SEPARATOR "ERROR_CODES" +#else +#define ERROR_CODES_OPT +#endif + +#ifdef ERROR_STACK +#define ERROR_STACK_OPT SIGFOX_VERSION_SEPARATOR "ERROR_STACK" +#else +#define ERROR_STACK_OPT +#endif + +#define SIGFOX_EP_FLAGS \ + FLAGS_OPT \ + RC1_OPT \ + RC2_OPT \ + RC3C_OPT \ + RC3D_OPT \ + RC4_OPT \ + RC5_OPT \ + RC6_OPT \ + RC7_OPT \ + APPLICATION_MESSAGES_OPT \ + CONTROL_KEEP_ALIVE_MESSAGE_OPT \ + BIDIRECTIONAL_OPT \ + ASYNCHRONOUS_OPT \ + LOW_LEVEL_OPEN_CLOSE_OPT \ + REGULATORY_OPT \ + SINGLE_FRAME_OPT \ + UL_BIT_RATE_BPS_OPT \ + T_IFU_MS_OPT \ + T_CONF_MS_OPT \ + UL_PAYLOAD_SIZE_OPT \ + CRC_HW_OPT \ + MESSAGE_COUNTER_ROLLOVER_OPT \ + PARAMETERS_CHECK_OPT \ + CERTIFICATION_OPT \ + PUBLIC_KEY_CAPABLE_OPT \ + VERBOSE_OPT \ + ERROR_CODES_OPT \ + ERROR_STACK_OPT \ + +#endif /* __SIGFOX_EP_VERSION_H__ */ diff --git a/inc/sigfox_error.h b/inc/sigfox_error.h new file mode 100644 index 0000000..41e0d16 --- /dev/null +++ b/inc/sigfox_error.h @@ -0,0 +1,149 @@ +/*!***************************************************************** + * \file sigfox_error.h + * \brief Sigfox error driver. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_ERROR_H__ +#define __SIGFOX_ERROR_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +#ifdef ERROR_STACK +/*** SIGFOX ERROR structures ***/ + +/*!****************************************************************** + * \enum SIGFOX_ERROR_source_t + * \brief Sigfox library low level errors sources. + *******************************************************************/ +typedef enum { + SIGFOX_ERROR_SOURCE_NONE = 0, + SIGFOX_ERROR_SOURCE_EP_LIBRARY, + SIGFOX_ERROR_SOURCE_MCU, + SIGFOX_ERROR_SOURCE_RF, + SIGFOX_ERROR_SOURCE_BITSTREAM, + SIGFOX_ERROR_SOURCE_CRC, + SIGFOX_ERROR_SOURCE_FREQUENCY, + SIGFOX_ERROR_SOURCE_TX_CONTROL, + SIGFOX_ERROR_SOURCE_LAST +} SIGFOX_ERROR_source_t; +#endif + +#ifdef ERROR_STACK +/*!****************************************************************** + * \struct SIGFOX_ERROR_t + * \brief Sigfox library low level error. + *******************************************************************/ +typedef struct { + SIGFOX_ERROR_source_t source; + sfx_u32 code; +} SIGFOX_ERROR_t; +#endif + +/*** SIGFOX ERROR functions ***/ + +#ifdef ERROR_STACK +/*!****************************************************************** + * \fn void SIGFOX_ERROR_init(void) + * \brief Init error stack. + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +void SIGFOX_ERROR_init(void); +#endif + +#ifdef ERROR_STACK +/*!****************************************************************** + * \fn void SIGFOX_ERROR_stack(SIGFOX_ERROR_source_t source, sfx_u32 code) + * \brief Store a new error in the internal stack. + * \param[in] source: Error source. + * \param[in] code: Error code. + * \param[out] none + * \retval none + *******************************************************************/ +void SIGFOX_ERROR_stack(SIGFOX_ERROR_source_t source, sfx_u32 code); +#endif + +#ifdef ERROR_STACK +/*!****************************************************************** + * \fn void SIGFOX_ERROR_unstack(SIGFOX_ERROR_t *error_ptr) + * \brief Read and clear the last (newest) error stored in the internal error stack. + * \brief This function can be called multiple times to unstack all errors which previously occurred during library execution, until it returns SIGFOX_EP_API_SUCCESS. + * \param[in] none + * \param[out] error_ptr: Pointer that will contain the last error in the stack. + * \retval none + *******************************************************************/ +void SIGFOX_ERROR_unstack(SIGFOX_ERROR_t *error_ptr); +#endif + +#ifdef ERROR_CODES +/*!****************************************************************** + * \fn void CHECK_STATUS(success_code) + * \brief Generic macro to check a status. + * \param[in] success_code: Success code to compare with. + * \param[out] none + * \retval none + *******************************************************************/ +#define CHECK_STATUS(success_code) { if (status != success_code) goto errors; } +#endif + +/*!****************************************************************** + * \fn void EXIT_ERROR(error) + * \brief Generic macro to update a status and exit a function. + * \param[in] error: Code of the risen error. + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_CODES +#define EXIT_ERROR(error) { status = error; goto errors; } +#else +#define EXIT_ERROR(error) { goto errors; } +#endif + +/*!****************************************************************** + * \fn void RETURN(void) + * \brief Generic macro for function return. + * \param[in] none + * \param[out] none + * \retval none + *******************************************************************/ +#ifdef ERROR_CODES +#define RETURN() { return status; } +#else +#define RETURN() { return; } +#endif +#endif /* __SIGFOX_ERROR_H__ */ diff --git a/inc/sigfox_rc.h b/inc/sigfox_rc.h new file mode 100644 index 0000000..10174d4 --- /dev/null +++ b/inc/sigfox_rc.h @@ -0,0 +1,294 @@ +/*!***************************************************************** + * \file sigfox_rc.h + * \brief Sigfox radio configuration zones definition. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_RC_H__ +#define __SIGFOX_RC_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +#ifdef SPECTRUM_ACCESS_DC +/*!****************************************************************** + * \var SIGFOX_SPECTRUM_ACCESS_DC + * \brief Duty cycle spectrum access parameters. + *******************************************************************/ +static const SIGFOX_spectrum_access_t SIGFOX_SPECTRUM_ACCESS_DC = { + .type = SIGFOX_SPECTRUM_ACCESS_TYPE_DC, +#ifdef BIDIRECTIONAL + .dl_t_w_ms = 20000, + .dl_t_rx_ms = 25000, +#ifndef SINGLE_FRAME + .delta_f_mf_hz = 6000, +#endif +#endif +}; +#endif + +#ifdef SPECTRUM_ACCESS_LDC +/*!****************************************************************** + * \var SIGFOX_SPECTRUM_ACCESS_LDC + * \brief Low Duty cycle spectrum access parameters. + *******************************************************************/ +static const SIGFOX_spectrum_access_t SIGFOX_SPECTRUM_ACCESS_LDC = { + .type = SIGFOX_SPECTRUM_ACCESS_TYPE_LDC, +#ifdef BIDIRECTIONAL + .dl_t_w_ms = 19000, + .dl_t_rx_ms = 33500, +#ifndef SINGLE_FRAME + .delta_f_mf_hz = 6000, +#endif +#endif +}; +#endif + +#ifdef SPECTRUM_ACCESS_FH +/*!****************************************************************** + * \var SIGFOX_SPECTRUM_ACCESS_FH + * \brief Frequency hopping spectrum access definition. + *******************************************************************/ +static const SIGFOX_spectrum_access_t SIGFOX_SPECTRUM_ACCESS_FH = { + .type = SIGFOX_SPECTRUM_ACCESS_TYPE_FH, +#ifdef BIDIRECTIONAL + .dl_t_w_ms = 20000, + .dl_t_rx_ms = 25000, +#ifndef SINGLE_FRAME + .delta_f_mf_hz = 25000, +#endif +#endif +}; +#endif + +#ifdef SPECTRUM_ACCESS_LBT_M80 +/*!****************************************************************** + * \var SIGFOX_SPECTRUM_ACCESS_LBT_M80 + * \brief Listen before talk spectrum access -80dBm definition. + *******************************************************************/ +static const SIGFOX_spectrum_access_t SIGFOX_SPECTRUM_ACCESS_LBT_M80 = { + .type = SIGFOX_SPECTRUM_ACCESS_TYPE_LBT, +#ifdef BIDIRECTIONAL + .dl_t_w_ms = 19000, + .dl_t_rx_ms = 33500, +#ifndef SINGLE_FRAME + .delta_f_mf_hz = 6000, +#endif +#endif +#ifdef REGULATORY + .cs_bandwidth_hz = 200000, + .cs_threshold_dbm = -80, + .cs_min_duration_ms = 5, + .cs_max_duration_first_frame_ms = 5000, // Could be changed by the user. +#endif +}; +#endif + +#ifdef SPECTRUM_ACCESS_LBT_M65 +/*!****************************************************************** + * \var SIGFOX_SPECTRUM_ACCESS_LBT_M65 + * \brief Listen before talk spectrum access -65dBm definition. + *******************************************************************/ +static const SIGFOX_spectrum_access_t SIGFOX_SPECTRUM_ACCESS_LBT_M65 = { + .type = SIGFOX_SPECTRUM_ACCESS_TYPE_LBT, +#ifdef BIDIRECTIONAL + .dl_t_w_ms = 19000, + .dl_t_rx_ms = 33500, +#ifndef SINGLE_FRAME + .delta_f_mf_hz = 6000, +#endif +#endif +#ifdef REGULATORY + .cs_bandwidth_hz = 200000, + .cs_threshold_dbm = -65, + .cs_min_duration_ms = 5, + .cs_max_duration_first_frame_ms = 5000, // Could be changed by the user. +#endif +}; +#endif + +#ifdef RC1 +/*!****************************************************************** + * \var SIGFOX_RC1 + * \brief RC1 radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC1 = { + .f_ul_hz = 868130000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 869525000, +#endif + .macro_channel_guard_band_hz = 17400, // For 20ppm local oscillator. Could be changed according to effective oscillator accuracy. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_DC, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_100BPS) | (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 16, +#endif +}; +#endif + +#ifdef RC2 +/*!****************************************************************** + * \var SIGFOX_RC2 + * \brief RC2 radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC2 = { + .f_ul_hz = 902200000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 905200000, +#endif + .macro_channel_guard_band_hz = SIGFOX_FH_MACRO_CHANNEL_GUARD_BAND_HZ, // Fixed to 1 micro-channel bandwidth. Should not be changed. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_FH, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 24, +#endif +}; +#endif + +#ifdef RC3C +/*!****************************************************************** + * \var SIGFOX_RC3C + * \brief RC3C radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC3C = { + .f_ul_hz = 923200000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 922200000, +#endif + .macro_channel_guard_band_hz = 18500, // For 20ppm local oscillator. Could be changed according to effective oscillator accuracy. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_LBT_M80, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_100BPS) | (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 16, +#endif +}; +#endif + +#ifdef RC3D +/*!****************************************************************** + * \var SIGFOX_RC3D + * \brief RC3D radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC3D = { + .f_ul_hz = 923200000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 922200000, +#endif + .macro_channel_guard_band_hz = 18500, // For 20ppm local oscillator. Could be changed according to effective oscillator accuracy. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_LDC, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_100BPS) | (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 16, +#endif +}; +#endif + +#ifdef RC4 +/*!****************************************************************** + * \var SIGFOX_RC4 + * \brief RC4 radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC4 = { + .f_ul_hz = 920800000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 922300000, +#endif + .macro_channel_guard_band_hz = SIGFOX_FH_MACRO_CHANNEL_GUARD_BAND_HZ, // Fixed to 1 micro-channel bandwidth. Should not be changed. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_FH, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 24, +#endif +}; +#endif + +#ifdef RC5 +/*!****************************************************************** + * \var SIGFOX_RC5 + * \brief RC5 radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC5 = { + .f_ul_hz = 923300000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 922300000, +#endif + .macro_channel_guard_band_hz = 18500, // For 20ppm local oscillator. Could be changed according to effective oscillator accuracy. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_LBT_M65, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_100BPS) | (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 14, +#endif +}; +#endif + +#ifdef RC6 +/*!****************************************************************** + * \var SIGFOX_RC6 + * \brief RC6 radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC6 = { + .f_ul_hz = 865200000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 866300000, +#endif + .macro_channel_guard_band_hz = 17400, // For 20ppm local oscillator. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_DC, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_100BPS) | (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 16, +#endif +}; +#endif + +#ifdef RC7 +/*!****************************************************************** + * \var SIGFOX_RC7 + * \brief RC7 radio configuration structure. + *******************************************************************/ +static const SIGFOX_rc_t SIGFOX_RC7 = { + .f_ul_hz = 868800000, +#ifdef BIDIRECTIONAL + .f_dl_hz = 869100000, +#endif + .macro_channel_guard_band_hz = 17400, // For 20ppm local oscillator. Could be changed according to effective oscillator accuracy. + .spectrum_access = &SIGFOX_SPECTRUM_ACCESS_DC, +#ifdef PARAMETERS_CHECK + .uplink_bit_rate_capability = (1 << SIGFOX_UL_BIT_RATE_100BPS) | (1 << SIGFOX_UL_BIT_RATE_600BPS), + .tx_power_dbm_eirp_max = 16, +#endif +}; +#endif + +#endif /* __SIGFOX_RC_H__ */ diff --git a/inc/sigfox_types.h b/inc/sigfox_types.h new file mode 100644 index 0000000..87aee64 --- /dev/null +++ b/inc/sigfox_types.h @@ -0,0 +1,388 @@ +/*!***************************************************************** + * \file sigfox_types.h + * \brief Sigfox types definition. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#ifndef __SIGFOX_TYPES_H__ +#define __SIGFOX_TYPES_H__ + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif + +/*** SIGFOX library common macros ***/ + +#define SIGFOX_EP_ID_SIZE_BYTES 4 +#define SIGFOX_EP_PAC_SIZE_BYTES 8 +#define SIGFOX_EP_KEY_SIZE_BYTES 16 + +#define SIGFOX_UL_PAYLOAD_MAX_SIZE_BYTES 12 +#ifndef SINGLE_FRAME +// Maximum delay between each frame of a same uplink message (for all RC). +#define SIGFOX_T_IFU_MAX_MS 2000 +#ifdef BIDIRECTIONAL +// Fixed inter frame delay when requesting a downlink. +#define SIGFOX_T_IFB_MS 500 +#endif +// Maximum duration of repeated frames transmission in case of LBT. +#define SIGFOX_T_LF_MS 8000 +#endif + +#ifdef BIDIRECTIONAL +// Downlink bit rate. +#define SIGFOX_DL_BIT_RATE_BPS 600 +// Downlink GFSK deviation. +#define SIGFOX_DL_GFSK_DEVIATION_HZ 800 +// Downlink frame size. +#define SIGFOX_DL_PAYLOAD_SIZE_BYTES 8 +#define SIGFOX_DL_PHY_CONTENT_SIZE_BYTES 15 +// Downlink preamble. +#define SIGFOX_DL_PR_PATTERN 0xAA +// Downlink synchronization word. +#define SIGFOX_DL_FT {0xB2, 0X27} +#define SIGFOX_DL_FT_SIZE_BYTES 2 +// Delay between downlink frame reception and uplink confirmation control message (for all RC). +#define SIGFOX_T_CONF_MIN_MS 1400 +#define SIGFOX_T_CONF_MAX_MS 4000 +#endif + +// Sigfox operational band width (for all RC). +#define SIGFOX_MACRO_CHANNEL_WIDTH_HZ 192000 + +#define SFX_NULL (void*) 0 + +/*** SIGFOX library types ***/ + +typedef unsigned char sfx_u8; +typedef signed char sfx_s8; +typedef unsigned short sfx_u16; +typedef signed short sfx_s16; +typedef unsigned int sfx_u32; +typedef signed int sfx_s32; + +/*!****************************************************************** + * \enum sfx_bool + * \brief Sigfox boolean type. + *******************************************************************/ +typedef enum { + SFX_FALSE = 0, + SFX_TRUE +} sfx_bool; + +/*** SIGFOX library structures ***/ + +#if !(defined UL_BIT_RATE_BPS) || (defined PARAMETERS_CHECK) +/*!****************************************************************** + * \enum SIGFOX_bit_rate_t + * \brief Sigfox signals bit rates list. + *******************************************************************/ +typedef enum { + SIGFOX_UL_BIT_RATE_100BPS, + SIGFOX_UL_BIT_RATE_600BPS, + SIGFOX_UL_BIT_RATE_LAST +} SIGFOX_ul_bit_rate_t; +#endif + +#if !(defined UL_BIT_RATE_BPS) || ((defined PARAMETERS_CHECK) && (defined ERROR_CODES)) +/*!****************************************************************** + * \const SIGFOX_EP_API_UL_BIT_RATE_BPS_LIST + * \brief Sigfox bit rates value. + *******************************************************************/ +static const sfx_u16 SIGFOX_UL_BIT_RATE_BPS_LIST[SIGFOX_UL_BIT_RATE_LAST] = {100, 600}; +#endif + +#ifdef APPLICATION_MESSAGES +/*!****************************************************************** + * \enum SIGFOX_application_message_type_t + * \brief Sigfox application message types. + *******************************************************************/ +typedef enum { +#ifdef UL_PAYLOAD_SIZE +#if (UL_PAYLOAD_SIZE == 0) + SIGFOX_APPLICATION_MESSAGE_TYPE_EMPTY, + SIGFOX_APPLICATION_MESSAGE_TYPE_BIT0, + SIGFOX_APPLICATION_MESSAGE_TYPE_BIT1, +#else + SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY, +#endif +#else + SIGFOX_APPLICATION_MESSAGE_TYPE_EMPTY, + SIGFOX_APPLICATION_MESSAGE_TYPE_BIT0, + SIGFOX_APPLICATION_MESSAGE_TYPE_BIT1, + SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY, +#endif + SIGFOX_APPLICATION_MESSAGE_TYPE_LAST +} SIGFOX_application_message_type_t; +#endif + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*!****************************************************************** + * \enum SIGFOX_control_message_type_t + * \brief Sigfox control message types. + *******************************************************************/ +typedef enum { +#ifdef CONTROL_KEEP_ALIVE_MESSAGE + SIGFOX_CONTROL_MESSAGE_TYPE_KEEP_ALIVE, +#endif +#ifdef BIDIRECTIONAL + SIGFOX_CONTROL_MESSAGE_TYPE_DL_CONFIRMATION, +#endif + SIGFOX_CONTROL_MESSAGE_TYPE_LAST +} SIGFOX_control_message_type_t; +#endif + +#ifndef SINGLE_FRAME +/*!****************************************************************** + * \enum SIGFOX_ul_frame_rank_t + * \brief Sigfox uplink frame rank list. + *******************************************************************/ +typedef enum { + SIGFOX_UL_FRAME_RANK_1 = 0, + SIGFOX_UL_FRAME_RANK_2, + SIGFOX_UL_FRAME_RANK_3, + SIGFOX_UL_FRAME_RANK_LAST +} SIGFOX_ul_frame_rank_t; +#endif + +#if !(defined MESSAGE_COUNTER_ROLLOVER) || (defined PARAMETERS_CHECK) +/*!****************************************************************** + * \enum SIGFOX_message_counter_rollover_t + * \brief Sigfox message counter rollover values list. + *******************************************************************/ +typedef enum { + SIGFOX_MESSAGE_COUNTER_ROLLOVER_128 = 0, + SIGFOX_MESSAGE_COUNTER_ROLLOVER_256, + SIGFOX_MESSAGE_COUNTER_ROLLOVER_512, + SIGFOX_MESSAGE_COUNTER_ROLLOVER_1024, + SIGFOX_MESSAGE_COUNTER_ROLLOVER_2048, + SIGFOX_MESSAGE_COUNTER_ROLLOVER_4096, + SIGFOX_MESSAGE_COUNTER_ROLLOVER_LAST +} SIGFOX_message_counter_rollover_t; +#endif + +#if !(defined MESSAGE_COUNTER_ROLLOVER) || (defined PARAMETERS_CHECK) +/*!****************************************************************** + * \const SIGFOX_EP_API_MESSAGE_COUNTER_ROLLOVER_LIST + * \brief Sigfox message counter value. + *******************************************************************/ +static const sfx_u16 SIGFOX_MESSAGE_COUNTER_ROLLOVER_LIST[SIGFOX_MESSAGE_COUNTER_ROLLOVER_LAST] = {128, 256, 512, 1024, 2048, 4096}; +#endif + +/*** Automatic spectrum access definition according to selected RCs ***/ + +#if (defined RC1) || (defined RC6) || (defined RC7) +#define SPECTRUM_ACCESS_DC +#endif +#if (defined RC2) || (defined RC4) +#define SPECTRUM_ACCESS_FH +#endif +#if (defined RC3C) +#define SPECTRUM_ACCESS_LBT +#define SPECTRUM_ACCESS_LBT_M80 +#endif +#if (defined RC3D) +#define SPECTRUM_ACCESS_LDC +#endif +#if (defined RC5) +#define SPECTRUM_ACCESS_LBT +#define SPECTRUM_ACCESS_LBT_M65 +#endif + +#ifdef SPECTRUM_ACCESS_FH +#define SIGFOX_FH_MACRO_CHANNEL_WIDTH_HZ 200000 +#define SIGFOX_FH_MACRO_CHANNEL_DELTA (SIGFOX_FH_MACRO_CHANNEL_WIDTH_HZ - SIGFOX_MACRO_CHANNEL_WIDTH_HZ) +#define SIGFOX_FH_MICRO_CHANNEL_NUMBER 8 +#define SIGFOX_FH_MICRO_CHANNEL_USED 6 +#define SIGFOX_FH_MICRO_CHANNEL_MASK 0x7E +#define SIGFOX_FH_MICRO_CHANNEL_WIDTH_HZ (SIGFOX_FH_MACRO_CHANNEL_WIDTH_HZ / SIGFOX_FH_MICRO_CHANNEL_NUMBER) +#define SIGFOX_FH_MACRO_CHANNEL_GUARD_BAND_HZ (SIGFOX_FH_MICRO_CHANNEL_WIDTH_HZ - (SIGFOX_FH_MACRO_CHANNEL_DELTA / 2)) +#define SIGFOX_FH_MICRO_CHANNEL_GUARD_BAND_HZ 1000 +#endif + +/*!****************************************************************** + * \enum SIGFOX_spectrum_access_type_t + * \brief Spectrum access types list. + *******************************************************************/ +typedef enum { +#ifdef SPECTRUM_ACCESS_DC + SIGFOX_SPECTRUM_ACCESS_TYPE_DC, +#endif +#ifdef SPECTRUM_ACCESS_LDC + SIGFOX_SPECTRUM_ACCESS_TYPE_LDC, +#endif +#ifdef SPECTRUM_ACCESS_FH + SIGFOX_SPECTRUM_ACCESS_TYPE_FH, +#endif +#ifdef SPECTRUM_ACCESS_LBT + SIGFOX_SPECTRUM_ACCESS_TYPE_LBT, +#endif + SIGFOX_SPECTRUM_ACCESS_TYPE_LAST +} SIGFOX_spectrum_access_type_t; + +/*!****************************************************************** + * \enum SIGFOX_spectrum_access_t + * \brief Spectrum access parameters structure. + *******************************************************************/ +typedef struct { + SIGFOX_spectrum_access_type_t type; +#ifdef BIDIRECTIONAL + // Common parameters. + sfx_u16 dl_t_w_ms; // Delay between the end of the first uplink frame and the beginning of the RX window. + sfx_u16 dl_t_rx_ms; // Maximum duration of the RX window. +#ifndef SINGLE_FRAME + sfx_u16 delta_f_mf_hz; // Fixed frequency offset applied to frames 2 and 3 in bidirectional procedure. +#endif +#endif +#if (defined SPECTRUM_ACCESS_LBT) && (defined REGULATORY) + // For LBT. + sfx_u32 cs_bandwidth_hz; + sfx_s8 cs_threshold_dbm; + sfx_u32 cs_min_duration_ms; + sfx_u32 cs_max_duration_first_frame_ms; +#endif +} SIGFOX_spectrum_access_t; + +/*!****************************************************************** + * \enum SIGFOX_rc_t + * \brief Sigfox radio configuration structure. + *******************************************************************/ +typedef struct { + sfx_u32 f_ul_hz; +#ifdef BIDIRECTIONAL + sfx_u32 f_dl_hz; +#endif + sfx_u16 macro_channel_guard_band_hz; +#ifdef PARAMETERS_CHECK + sfx_u8 uplink_bit_rate_capability; + sfx_s8 tx_power_dbm_eirp_max; +#endif + const SIGFOX_spectrum_access_t *spectrum_access; +} SIGFOX_rc_t; + +/*!****************************************************************** + * \enum SIGFOX_nvm_data_index_t + * \brief Sigfox NVM fields index. + *******************************************************************/ +typedef enum { + SIGFOX_NVM_DATA_INDEX_RANDOM_VALUE_LSB = 0, + SIGFOX_NVM_DATA_INDEX_RANDOM_VALUE_MSB, + SIGFOX_NVM_DATA_INDEX_MESSAGE_COUNTER_LSB, + SIGFOX_NVM_DATA_INDEX_MESSAGE_COUNTER_MSB, + SIGFOX_NVM_DATA_SIZE_BYTES +} SIGFOX_nvm_data_index_t; + +#ifdef PUBLIC_KEY_CAPABLE +/*!****************************************************************** + * \enum SIGFOX_ep_key_t + * \brief Sigfox end-point key type. + *******************************************************************/ +typedef enum { + SIGFOX_EP_KEY_PRIVATE, + SIGFOX_EP_KEY_PUBLIC, + SIGFOX_EP_KEY_LAST +} SIGFOX_ep_key_t; +#endif + +#ifdef CERTIFICATION +/*!****************************************************************** + * \var SIGFOX_EP_TEST_ID + * \var SIGFOX_EP_TEST_KEY + * \brief End-point IDs and keys used for test. + *******************************************************************/ +static const sfx_u8 SIGFOX_EP_TEST_ID[SIGFOX_EP_ID_SIZE_BYTES] = {0xFE, 0xDC, 0xBA, 0x98}; +static const sfx_u8 SIGFOX_EP_TEST_KEY[SIGFOX_EP_KEY_SIZE_BYTES] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; +#endif + +#ifdef PUBLIC_KEY_CAPABLE +/*!****************************************************************** + * \var SIGFOX_EP_PUBLIC_KEY + * \brief End-point public key used for test. + *******************************************************************/ +static const sfx_u8 SIGFOX_EP_PUBLIC_KEY[SIGFOX_EP_KEY_SIZE_BYTES] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; +#endif + +#ifdef VERBOSE +/*!****************************************************************** + * \enum SIGFOX_version_t + * \brief Sigfox EP library components version. + *******************************************************************/ +typedef enum { + SIGFOX_VERSION_EP_LIBRARY = 0, + SIGFOX_VERSION_MCU_DRIVER, + SIGFOX_VERSION_RF_DRIVER, + SIGFOX_VERSION_LAST +} SIGFOX_version_t; +#endif + +/*** Unwanted flag combinations and values ***/ + +#if !(defined RC1) && !(defined RC2) && !(defined RC3C) && !(defined RC3D) && !(defined RC4) && !(defined RC5) && !(defined RC6) && !(defined RC7) +#error "SIGFOX EP LIB flags error: None RC defined" +#endif +#if !(defined APPLICATION_MESSAGES) && !(defined CONTROL_KEEP_ALIVE_MESSAGE) +#error "SIGFOX EP LIB flags error: None message type defined" +#endif +#if !(defined APPLICATION_MESSAGES) && (defined BIDIRECTIONAL) +#error "SIGFOX EP LIB flags error: Bidirectional communication only applies to application messages which are disabled" +#endif +#if (defined UL_BIT_RATE_BPS) && (UL_BIT_RATE_BPS != 100) && (UL_BIT_RATE_BPS != 600) +#error "SIGFOX EP LIB flags error: Invalid UL_BIT_RATE_BPS value" +#endif +#if (defined T_IFU_MS) && (defined SINGLE_FRAME) +#error "SIGFOX EP LIB flags error: T_IFU_MS only applies when SINGLE_FRAME is disabled" +#endif +#ifndef SINGLE_FRAME +#if (defined T_IFU_MS) && (T_IFU_MS > SIGFOX_T_IFU_MAX_MS) +#error "SIGFOX EP LIB flags error: Invalid T_IFU_MS value" +#endif +#endif +#if (defined T_CONF_MS) && !(defined BIDIRECTIONAL) +#error "SIGFOX EP LIB flags error: T_CONF_MS only applies to bidirectional communication which is disabled" +#endif +#ifdef BIDIRECTIONAL +#if (defined T_CONF_MS) && ((T_CONF_MS < SIGFOX_T_CONF_MIN_MS) || (T_CONF_MS > SIGFOX_T_CONF_MAX_MS)) +#error "SIGFOX EP LIB flags error: Invalid T_CONF_MS value" +#endif +#endif +#if (defined UL_PAYLOAD_SIZE) && (UL_PAYLOAD_SIZE > SIGFOX_UL_PAYLOAD_MAX_SIZE_BYTES) +#error "SIGFOX EP LIB flags error: Unsupported UL_PAYLOAD_SIZE value" +#endif +#if (defined MESSAGE_COUNTER_ROLLOVER) && (MESSAGE_COUNTER_ROLLOVER != 128) && (MESSAGE_COUNTER_ROLLOVER != 256) && (MESSAGE_COUNTER_ROLLOVER != 512) && (MESSAGE_COUNTER_ROLLOVER != 1024) && (MESSAGE_COUNTER_ROLLOVER != 2048) && (MESSAGE_COUNTER_ROLLOVER != 4096) +#error "SIGFOX EP LIB flags error: Invalid MESSAGE_COUNTER_ROLLOVER value" +#endif +#if (defined ERROR_STACK) && !(defined ERROR_CODES) +#error "SIGFOX EP LIB flags error: ERROR_CODES are required to use ERROR_STACK" +#endif + +#endif /* __SIGFOX_TYPES_H__ */ diff --git a/src/core/sigfox_crc.c b/src/core/sigfox_crc.c new file mode 100644 index 0000000..d9aab60 --- /dev/null +++ b/src/core/sigfox_crc.c @@ -0,0 +1,115 @@ +/*!***************************************************************** + * \file sigfox_crc.c + * \brief Sigfox CRC driver. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#include "core/sigfox_crc.h" + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" +#include "sigfox_error.h" + +#ifndef CRC_HW + +/*** SIGFOX CRC functions ***/ + +/*******************************************************************/ +SIGFOX_CRC_status_t SIGFOX_CRC_compute_crc16(sfx_u8 *crc_data, sfx_u8 data_size, sfx_u16 polynom, sfx_u16 *crc) { + // Local variables. + sfx_u8 i = 0; + sfx_u8 j = 0; +#ifdef ERROR_CODES + SIGFOX_CRC_status_t status = SIGFOX_CRC_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if ((crc_data == SFX_NULL) || (crc == SFX_NULL)) { + EXIT_ERROR(SIGFOX_CRC_ERROR_NULL_PARAMETER); + } +#endif + // Compute CRC. + (*crc) = 0; + for (j=0 ; j 0) { + for (idx=0 ; idx 0) { + for (idx=0 ; idx> 8) & 0xFF; + sigfox_ep_bitstream_ctx.bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + sigfox_ep_bitstream_ctx.ul_payload_size_bytes + sigfox_ep_bitstream_ctx.ul_auth_size_bytes + 1] = (ul_crc >> 0) & 0xFF; +#else + sigfox_ep_bitstream_ctx.bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + UL_PAYLOAD_SIZE + sigfox_ep_bitstream_ctx.ul_auth_size_bytes + 0] = (ul_crc >> 8) & 0xFF; + sigfox_ep_bitstream_ctx.bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + UL_PAYLOAD_SIZE + sigfox_ep_bitstream_ctx.ul_auth_size_bytes + 1] = (ul_crc >> 0) & 0xFF; +#endif +#ifdef ERROR_CODES +errors:; +#endif + RETURN(); +} + +#ifndef SINGLE_FRAME +/*******************************************************************/ +static void _convolve(SIGFOX_ul_frame_rank_t ul_frame_rank) { + // Local variables. + sfx_u8 initial_bitstream[SIGFOX_EP_BITSTREAM_SIZE_BYTES]; + sfx_u8 idx = 0; + sfx_u8 mask = 0; + sfx_u8 state = 0; +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) || !(defined UL_PAYLOAD_SIZE) + sfx_u8 convolution_input_size_bytes = (SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_SIZE_BYTES + SIGFOX_EP_ID_SIZE_BYTES + sigfox_ep_bitstream_ctx.ul_payload_size_bytes + sigfox_ep_bitstream_ctx.ul_auth_size_bytes + SIGFOX_EP_BITSTREAM_UL_CRC_SIZE_BYTES); +#else + sfx_u8 convolution_input_size_bytes = (SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_SIZE_BYTES + SIGFOX_EP_ID_SIZE_BYTES + UL_PAYLOAD_SIZE + sigfox_ep_bitstream_ctx.ul_auth_size_bytes + SIGFOX_EP_BITSTREAM_UL_CRC_SIZE_BYTES); +#endif + // Init buffers. + for (idx=0; idx>=1) { + if (initial_bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + idx] & mask) { + sigfox_ep_bitstream_ctx.bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + idx] |= mask * ((SIGFOX_EP_BITSTREAM_UL_CONVOLUTION_LUT_IN_OUT[ul_frame_rank][state] == 0) ? 1 : 0); + state = SIGFOX_EP_BITSTREAM_UL_CONVOLUTION_LUT_IN[state] + 2; + } + else { + sigfox_ep_bitstream_ctx.bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + idx] |= mask * SIGFOX_EP_BITSTREAM_UL_CONVOLUTION_LUT_IN_OUT[ul_frame_rank][state]; + state = SIGFOX_EP_BITSTREAM_UL_CONVOLUTION_LUT_IN[state]; + } + } + } +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +static sfx_u16 _dewhitening_pn(sfx_u16 pn_value) { + // Local variables. + sfx_u8 msb = 0; + sfx_u8 roll = 0; + // Compute algorithm. + for (roll=8 ; roll>0 ; roll--) { + msb = (sfx_u8) (pn_value & 0x0021); + pn_value >>= 1; + pn_value |= (msb == 0x20 || msb == 0x01) ? 0x100 : 0x000; + } + return pn_value; +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +static void _dewhitening(SIGFOX_EP_BITSTREAM_dl_frame_t *input, sfx_u8 *local_bitstream) { + // Local variables. + sfx_u8 idx = 0; + sfx_u32 ep_id_32bits = 0; + sfx_u32 pn = 0; + // Convert EP ID array to 32-bits value. + for (idx=0 ; idx ep_id[SIGFOX_EP_ID_SIZE_BYTES - 1 - idx]) << (8 * idx); + } + // Set initial value as device ID * message counter. + pn = ep_id_32bits * ((sfx_u32) (input-> message_counter)); + // Apply 9-bits mask. + pn &= SIGFOX_EP_BITSTREAM_DL_DEWHITENING_MASK; + if (pn == 0) { + pn = SIGFOX_EP_BITSTREAM_DL_DEWHITENING_MASK; + } + // Perform dewhitening algorithm. + for (idx=0 ; idx<8; idx++) { + pn = _dewhitening_pn((sfx_u16) pn); + local_bitstream[idx + 0] ^= pn >> (idx + 1); + local_bitstream[idx + 1] ^= (pn & ((1 << (idx + 1)) - 1)) << (7 - idx); + } + for (idx=0; idx<5; idx++) { + pn = _dewhitening_pn((sfx_u16) pn); + local_bitstream[idx + 9] ^= pn >> (idx + 1); + local_bitstream[idx + 10] ^= (pn & ((1 << (idx + 1)) - 1)) << (7 - idx); + } + pn = _dewhitening_pn((sfx_u16) pn); + local_bitstream[14] ^= pn >> (idx + 1); +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +static void _decode_bch(sfx_u8* local_bitstream) { + // Local variables. + sfx_u8 i = 0; + sfx_u8 j = 0; + sfx_u8 syndrome = 0; + // Perform ECC algorithm. + for(i=0 ; i<8; i++) { + // Compute code syndrome. + syndrome = 0; + for(j=0 ; j<15 ; j++) { + syndrome ^= SIGFOX_EP_BITSTREAM_DL_POW_ALPHA_LUT[j] * ((local_bitstream[j] >> i) & 1); + } + // The BCH(15,11) code can only correct a single error. + // If the syndrome is not zero, it indicates the bit in error. + // If the syndrome is zero, there is no error. To simplify the code, word 16 is changed. + // Word 16 is actually a dummy word. + local_bitstream[SIGFOX_EP_BITSTREAM_DL_LOG_ALPHA_LUT[syndrome]] ^= 1 << i; + } +} +#endif + +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +/*******************************************************************/ +static SIGFOX_EP_BITSTREAM_status_t _check_common_parameters(SIGFOX_EP_BITSTREAM_common_t *common_params) { + // Local variables. + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; + // Check parameter. + if (common_params == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER); + } + // Check ID. + if ((common_params -> ep_id) == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER); + } +#ifndef SINGLE_FRAME + // Check frame rank. + if ((common_params -> ul_frame_rank) >= SIGFOX_UL_FRAME_RANK_LAST) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_FRAME_RANK); + } +#endif + // Check message counter. +#ifdef MESSAGE_COUNTER_ROLLOVER + if ((common_params -> message_counter) >= MESSAGE_COUNTER_ROLLOVER) { +#else + if ((common_params -> message_counter) >= (common_params -> message_counter_rollover)) { +#endif + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_MESSAGE_COUNTER); + } +#ifdef PUBLIC_KEY_CAPABLE + // Check key type. + if ((common_params -> ep_key_type) >= SIGFOX_EP_KEY_LAST) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_KEY_TYPE); + } +#endif +errors: + return status; +} +#endif + +#if (defined APPLICATION_MESSAGES) && (defined PARAMETERS_CHECK) && (defined ERROR_CODES) + /*******************************************************************/ +static SIGFOX_EP_BITSTREAM_status_t _check_application_parameters(SIGFOX_EP_BITSTREAM_application_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes) { + // Local variables. + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; + // Check parameters. + if ((input == SFX_NULL) || (bitstream == SFX_NULL) || (bitstream_size_bytes == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER); + } + // Check common parameters. + status = _check_common_parameters(&(input -> common_parameters)); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + if ((input -> message_type) == SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY) { + // Payload is required. + if (((input -> ul_payload) == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER); + } + } +#endif +#ifndef UL_PAYLOAD_SIZE + if ((input -> message_type) == SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY) { + // Length is required. + if (((input -> ul_payload_size_bytes) == 0) || ((input -> ul_payload_size_bytes) > SIGFOX_UL_PAYLOAD_MAX_SIZE_BYTES)) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_PAYLOAD_SIZE); + } + } +#endif +errors: + return status; +} +#endif + +#if ((defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL)) && (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +/*******************************************************************/ +static SIGFOX_EP_BITSTREAM_status_t _check_control_parameters(SIGFOX_EP_BITSTREAM_control_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes) { + // Local variables. + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; + // Check parameters. + if ((input == SFX_NULL) || (bitstream == SFX_NULL) || (bitstream_size_bytes == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER); + } + // Check common parameters. + status = _check_common_parameters(&(input -> common_parameters)); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +errors: + return status; +} +#endif + +#if (defined BIDIRECTIONAL) && (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +/*******************************************************************/ +static SIGFOX_EP_BITSTREAM_status_t _check_dl_parameters(SIGFOX_EP_BITSTREAM_dl_frame_t *input, sfx_u8 *dl_payload) { + // Local variables. + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; + // Check parameters. + if ((input == SFX_NULL) || ((input-> dl_phy_content) == SFX_NULL) || ((input -> ep_id) == SFX_NULL) || (dl_payload == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_NULL_PARAMETER); + } +errors: + return status; +} +#endif + +/*** SIGFOX EP BITSTREAM functions ***/ + +#ifdef APPLICATION_MESSAGES +/*******************************************************************/ +SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_build_application_frame(SIGFOX_EP_BITSTREAM_application_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes) { + // Local variables. + sfx_u8 idx = 0; +#ifdef ERROR_CODES + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; +#endif +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) + status = _check_application_parameters(input, bitstream, bitstream_size_bytes); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#endif + // Default values. + sigfox_ep_bitstream_ctx.ul_li = 0; + sigfox_ep_bitstream_ctx.ul_auth_size_bytes = 2; + sigfox_ep_bitstream_ctx.bitstream = bitstream; +#ifdef PUBLIC_KEY_CAPABLE + sigfox_ep_bitstream_ctx.key = input->common_parameters.ep_key_type; +#endif +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) || !(defined UL_PAYLOAD_SIZE) + // UL payload size. +#ifdef UL_PAYLOAD_SIZE + sigfox_ep_bitstream_ctx.ul_payload_size_bytes = UL_PAYLOAD_SIZE; +#else + sigfox_ep_bitstream_ctx.ul_payload_size_bytes = (input -> ul_payload_size_bytes); +#endif +#endif + // UL-PR. + for (idx=0 ; idx common_parameters).ul_frame_rank)]; +#endif /* SINGLE_FRAME */ +#if (UL_PAYLOAD_SIZE == 0) + switch (input -> message_type) { + case SIGFOX_APPLICATION_MESSAGE_TYPE_BIT0: + sigfox_ep_bitstream_ctx.ul_li = 2; + break; + case SIGFOX_APPLICATION_MESSAGE_TYPE_BIT1: + sigfox_ep_bitstream_ctx.ul_li = 3; + break; + default: + // LI=0 for empty frame. + break; + } +#endif /* UL_PAYLOAD_SIZE = 0 */ +#if (UL_PAYLOAD_SIZE >= 2) + sigfox_ep_bitstream_ctx.ul_li = 3 - ((UL_PAYLOAD_SIZE - 1) % 4); + sigfox_ep_bitstream_ctx.ul_auth_size_bytes = (sigfox_ep_bitstream_ctx.ul_li + 2); +#endif +#else /* UL_PAYLOAD_SIZE */ + switch (input -> message_type) { + case SIGFOX_APPLICATION_MESSAGE_TYPE_EMPTY: + // Empty frame. +#ifdef SINGLE_FRAME + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[0]; +#else + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[((input -> common_parameters).ul_frame_rank)][0]; +#endif + break; + case SIGFOX_APPLICATION_MESSAGE_TYPE_BIT0: + // Empty and bit frames. +#ifdef SINGLE_FRAME + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[0]; +#else + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[((input -> common_parameters).ul_frame_rank)][0]; +#endif + sigfox_ep_bitstream_ctx.ul_li = 2; + break; + case SIGFOX_APPLICATION_MESSAGE_TYPE_BIT1: + // Empty and bit frames. +#ifdef SINGLE_FRAME + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[0]; +#else + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[((input -> common_parameters).ul_frame_rank)][0]; +#endif + sigfox_ep_bitstream_ctx.ul_li = 3; + break; + case SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY: + if (sigfox_ep_bitstream_ctx.ul_payload_size_bytes == 1) { + // 1-byte frame. +#ifdef SINGLE_FRAME + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[1]; +#else + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[((input -> common_parameters).ul_frame_rank)][1]; +#endif + } + else { + // 2 to 12-bytes frames. +#ifdef SINGLE_FRAME + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[((sigfox_ep_bitstream_ctx.ul_payload_size_bytes - 1) / 4) + 2]; +#else + sigfox_ep_bitstream_ctx.ul_ft = SIGFOX_EP_BITSTREAM_UL_FT_APPLICATION_TABLE[((input -> common_parameters).ul_frame_rank)][((sigfox_ep_bitstream_ctx.ul_payload_size_bytes - 1) / 4) + 2]; +#endif + sigfox_ep_bitstream_ctx.ul_li = 3 - ((sigfox_ep_bitstream_ctx.ul_payload_size_bytes - 1) % 4); + sigfox_ep_bitstream_ctx.ul_auth_size_bytes = (sigfox_ep_bitstream_ctx.ul_li + 2); + } + break; + default: +#ifdef ERROR_CODES + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_MESSAGE_TYPE); +#else + goto errors; +#endif + break; + } +#endif /* UL_PAYLOAD_SIZE */ + bitstream[SIGFOX_EP_BITSTREAM_UL_FT_INDEX + 0] = (sfx_u8) ((sigfox_ep_bitstream_ctx.ul_ft & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_FT_INDEX + 1] = (sfx_u8) ((sigfox_ep_bitstream_ctx.ul_ft & 0x00FF) >> 0); + // LI and BF. + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX] = 0x00; + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX] |= (sigfox_ep_bitstream_ctx.ul_li << SIGFOX_EP_BITSTREAM_LI_BIT_INDEX); +#ifdef BIDIRECTIONAL + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX] |= (((input -> bidirectional_flag) & 0x01) << SIGFOX_EP_BITSTREAM_BF_BIT_INDEX); +#endif + // Message counter. + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + 0] |= (sfx_u8) ((((input -> common_parameters).message_counter) & 0x0F00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + 1] = (sfx_u8) ((((input -> common_parameters).message_counter) & 0x00FF) >> 0); + // EP-ID (LSByte first). + for (idx=0 ; idx common_parameters).ep_id)[SIGFOX_EP_ID_SIZE_BYTES - 1 - idx]; + } + (*bitstream_size_bytes) = (SIGFOX_EP_BITSTREAM_EP_ID_INDEX + SIGFOX_EP_ID_SIZE_BYTES); +#ifdef UL_PAYLOAD_SIZE +#if (UL_PAYLOAD_SIZE > 0) + // UL-PAYLOAD (MSByte first). + for (idx=0 ; idx ul_payload)[idx]; + } + (*bitstream_size_bytes) += UL_PAYLOAD_SIZE; +#endif +#else /* UL_PAYLOAD_SIZE */ + // UL-PAYLOAD (MSByte first). + if ((input -> message_type) == SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY) { + for (idx=0 ; idx ul_payload)[idx]; + } + } + else { + sigfox_ep_bitstream_ctx.ul_payload_size_bytes = 0; // No payload field for EMPTY and BIT message types. + } + (*bitstream_size_bytes) += sigfox_ep_bitstream_ctx.ul_payload_size_bytes; +#endif /* UL_PAYLOAD_SIZE */ + // UL_AUTH. +#ifdef ERROR_CODES + status = _aes_encrypt(); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#else + _aes_encrypt(); +#endif + (*bitstream_size_bytes) += sigfox_ep_bitstream_ctx.ul_auth_size_bytes; + // CRC. +#ifdef ERROR_CODES + status = _add_crc16(); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#else + _add_crc16(); +#endif + (*bitstream_size_bytes) += SIGFOX_EP_BITSTREAM_UL_CRC_SIZE_BYTES; +#ifndef SINGLE_FRAME + // Convolution. + _convolve((input -> common_parameters).ul_frame_rank); +#endif +#if (defined ERROR_CODES) || !(defined UL_PAYLOAD_SIZE) +errors: +#endif + RETURN(); +} +#endif + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*******************************************************************/ +SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_build_control_frame(SIGFOX_EP_BITSTREAM_control_frame_t *input, sfx_u8 *bitstream, sfx_u8 *bitstream_size_bytes) { + // Local variables. + sfx_u8 idx = 0; +#ifdef ERROR_CODES + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; +#endif +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) + status = _check_control_parameters(input, bitstream, bitstream_size_bytes); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#endif + // Default values + sigfox_ep_bitstream_ctx.ul_li = 0; + sigfox_ep_bitstream_ctx.ul_auth_size_bytes = 2; + sigfox_ep_bitstream_ctx.bitstream = bitstream; +#ifdef PUBLIC_KEY_CAPABLE + sigfox_ep_bitstream_ctx.key = (input -> common_parameters).ep_key_type; +#endif +#ifdef BIDIRECTIONAL + sfx_s8 rssi_plus_100 = (sfx_s8) ((input -> rssi_dbm) + 100); +#endif + // UL-PR. + for (idx=0 ; idx common_parameters).ul_frame_rank)]; +#endif + bitstream[SIGFOX_EP_BITSTREAM_UL_FT_INDEX + 0] = (sfx_u8) ((sigfox_ep_bitstream_ctx.ul_ft & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_FT_INDEX + 1] = (sfx_u8) ((sigfox_ep_bitstream_ctx.ul_ft & 0x00FF) >> 0); + // Payload size. + switch (input -> message_type) { +#ifdef CONTROL_KEEP_ALIVE_MESSAGE + case SIGFOX_CONTROL_MESSAGE_TYPE_KEEP_ALIVE: + sigfox_ep_bitstream_ctx.ul_payload_size_bytes = SIGFOX_EP_BITSTREAM_CONTROL_KEEP_ALIVE_PAYLOAD_SIZE_BYTES; + break; +#endif +#ifdef BIDIRECTIONAL + case SIGFOX_CONTROL_MESSAGE_TYPE_DL_CONFIRMATION: + sigfox_ep_bitstream_ctx.ul_payload_size_bytes = SIGFOX_EP_BITSTREAM_CONTROL_DL_CONFIRMATION_PAYLOAD_SIZE_BYTES; + break; +#endif + default: + EXIT_ERROR(SIGFOX_EP_BITSTREAM_ERROR_MESSAGE_TYPE); + break; + } + sigfox_ep_bitstream_ctx.ul_li = 3 - ((sigfox_ep_bitstream_ctx.ul_payload_size_bytes - 1) % 4); + sigfox_ep_bitstream_ctx.ul_auth_size_bytes = (sigfox_ep_bitstream_ctx.ul_li + 2); + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX] = 0x00; + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX] |= (sigfox_ep_bitstream_ctx.ul_li << SIGFOX_EP_BITSTREAM_LI_BIT_INDEX); + // Message counter. + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + 0] |= (sfx_u8) ((((input -> common_parameters).message_counter) & 0x0F00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_LI_BF_REP_MC_INDEX + 1] = (sfx_u8) ((((input -> common_parameters).message_counter) & 0x00FF) >> 0); + // EP-ID (LSByte first). + for (idx=0 ; idx common_parameters).ep_id)[SIGFOX_EP_ID_SIZE_BYTES - 1 - idx]; + } + (*bitstream_size_bytes) = (SIGFOX_EP_BITSTREAM_EP_ID_INDEX + SIGFOX_EP_ID_SIZE_BYTES); + // UL-PAYLOAD (MSByte first). + switch (input -> message_type) { +#ifdef CONTROL_KEEP_ALIVE_MESSAGE + case SIGFOX_CONTROL_MESSAGE_TYPE_KEEP_ALIVE: + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 0] = SIGFOX_EP_BITSTREAM_CONTROL_KEEP_ALIVE_CT; + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 1] = (sfx_u8) (((input -> voltage_idle_mv) & 0x00FF) >> 0); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 2] = (sfx_u8) (((input -> voltage_idle_mv) & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 3] = (sfx_u8) (((input -> voltage_tx_mv) & 0x00FF) >> 0); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 4] = (sfx_u8) (((input -> voltage_tx_mv) & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 5] = (sfx_u8) (((input -> temperature_tenth_degrees) & 0x00FF) >> 0); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 6] = (sfx_u8) (((input -> temperature_tenth_degrees) & 0xFF00) >> 8); + break; +#endif +#ifdef BIDIRECTIONAL + case SIGFOX_CONTROL_MESSAGE_TYPE_DL_CONFIRMATION: + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 0] = SIGFOX_EP_BITSTREAM_CONTROL_DL_CONFIRMATION_CT; + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 1] = (sfx_u8) (((input -> voltage_idle_mv) & 0x00FF) >> 0); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 2] = (sfx_u8) (((input -> voltage_idle_mv) & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 3] = (sfx_u8) (((input -> voltage_tx_mv) & 0x00FF) >> 0); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 4] = (sfx_u8) (((input -> voltage_tx_mv) & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 5] = (sfx_u8) (((input -> temperature_tenth_degrees) & 0x00FF) >> 0); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 6] = (sfx_u8) (((input -> temperature_tenth_degrees) & 0xFF00) >> 8); + bitstream[SIGFOX_EP_BITSTREAM_UL_PAYLOAD_INDEX + 7] = (sfx_u8) (rssi_plus_100); + break; +#endif + default: + break; + } + (*bitstream_size_bytes) += sigfox_ep_bitstream_ctx.ul_payload_size_bytes; + // UL_AUTH. +#ifdef ERROR_CODES + status = _aes_encrypt(); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#else + _aes_encrypt(); +#endif + (*bitstream_size_bytes) += sigfox_ep_bitstream_ctx.ul_auth_size_bytes; + // CRC. +#ifdef ERROR_CODES + status = _add_crc16(); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#else + _add_crc16(); +#endif + (*bitstream_size_bytes) += SIGFOX_EP_BITSTREAM_UL_CRC_SIZE_BYTES; +#ifndef SINGLE_FRAME + // Convolution. + _convolve((input -> common_parameters).ul_frame_rank); +#endif +errors: + RETURN(); +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +SIGFOX_EP_BITSTREAM_status_t SIGFOX_EP_BITSTREAM_decode_downlink_frame(SIGFOX_EP_BITSTREAM_dl_frame_t *input, sfx_bool *dl_frame_valid, sfx_u8 *dl_payload) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_EP_BITSTREAM_status_t status = SIGFOX_EP_BITSTREAM_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#ifndef CRC_HW + SIGFOX_CRC_status_t crc_status = SIGFOX_CRC_SUCCESS; +#endif +#endif + MCU_API_encryption_data_t encryption_data; + sfx_u8 idx = 0; + sfx_u8 byte_idx = 0; + sfx_u8 local_bitstream[SIGFOX_DL_PHY_CONTENT_SIZE_BYTES]; + sfx_u8 dl_crc; + sfx_u8 aes_data[SIGFOX_EP_KEY_SIZE_BYTES]; + // Reset result. + (*dl_frame_valid) = SFX_FALSE; +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) + // Check parameters. + status = _check_dl_parameters(input, dl_payload); + CHECK_STATUS(SIGFOX_EP_BITSTREAM_SUCCESS); +#endif + // Copy bitstream to local buffer. + for (idx=0 ; idx dl_phy_content[idx]; + } + // Step 1: de-whitening. + _dewhitening(input, local_bitstream); + // Step 2: ECC. + _decode_bch(local_bitstream); + // Step 3: CRC check. +#ifdef CRC_HW +#ifdef ERROR_CODES + mcu_status = MCU_API_compute_crc8(&(local_bitstream[SIGFOX_EP_BITSTREAM_DL_PAYLOAD_INDEX]), (SIGFOX_DL_PAYLOAD_SIZE_BYTES + SIGFOX_EP_BITSTREAM_DL_AUTH_SIZE_BYTES), SIGFOX_EP_BITSTREAM_DL_CRC_POLYNOM, &dl_crc); + MCU_API_check_status(SIGFOX_EP_BITSTREAM_ERROR_MCU); +#else + MCU_API_compute_crc8(&(local_bitstream[SIGFOX_EP_BITSTREAM_DL_PAYLOAD_INDEX]), (SIGFOX_DL_PAYLOAD_SIZE_BYTES + SIGFOX_EP_BITSTREAM_DL_AUTH_SIZE_BYTES), SIGFOX_EP_BITSTREAM_DL_CRC_POLYNOM, &dl_crc); +#endif +#else +#ifdef ERROR_CODES + crc_status = SIGFOX_CRC_compute_crc8(&(local_bitstream[SIGFOX_EP_BITSTREAM_DL_PAYLOAD_INDEX]), (SIGFOX_DL_PAYLOAD_SIZE_BYTES + SIGFOX_EP_BITSTREAM_DL_AUTH_SIZE_BYTES), SIGFOX_EP_BITSTREAM_DL_CRC_POLYNOM, &dl_crc); + SIGFOX_CRC_check_status(SIGFOX_EP_BITSTREAM_ERROR_CRC); +#else + SIGFOX_CRC_compute_crc8(&(local_bitstream[SIGFOX_EP_BITSTREAM_DL_PAYLOAD_INDEX]), (SIGFOX_DL_PAYLOAD_SIZE_BYTES + SIGFOX_EP_BITSTREAM_DL_AUTH_SIZE_BYTES), SIGFOX_EP_BITSTREAM_DL_CRC_POLYNOM, &dl_crc); +#endif +#endif + if (dl_crc != local_bitstream[SIGFOX_EP_BITSTREAM_DL_CRC_INDEX]) goto errors; + // Step 4: authentication check. + // Build input data. + // EP-ID (LSByte first). + for (idx=0 ; idx ep_id[SIGFOX_EP_ID_SIZE_BYTES - 1 - idx]; + } + // Message counter. + aes_data[byte_idx++] = (sfx_u8) (((input -> message_counter) >> 0) & 0xFF); + aes_data[byte_idx++] = (sfx_u8) (((input -> message_counter) >> 8) & 0x0F); + // DL-PAYLOAD. + for (idx=0 ; idx ep_id[3]; + aes_data[byte_idx++] = input -> ep_id[2]; + // Build input structure. + encryption_data.data = aes_data; + encryption_data.data_size_bytes = SIGFOX_EP_KEY_SIZE_BYTES; +#ifdef PUBLIC_KEY_CAPABLE + encryption_data.key = (input -> ep_key_type); +#endif + // Perform encryption. +#ifdef ERROR_CODES + mcu_status = MCU_API_aes_128_cbc_encrypt(&encryption_data); + MCU_API_check_status(SIGFOX_EP_BITSTREAM_ERROR_MCU); +#else + MCU_API_aes_128_cbc_encrypt(&encryption_data); +#endif + // Compare received and computed DL-AUTH fields. + if ((local_bitstream[SIGFOX_EP_BITSTREAM_DL_AUTH_INDEX] != aes_data[0]) || (local_bitstream[SIGFOX_EP_BITSTREAM_DL_AUTH_INDEX + 1] != aes_data[1])) { + goto errors; + } + // Valid frame received: extract DL payload. + for (idx=0 ; idx macro_channel_guard_band_hz); + sigfox_ep_frequency_ctx.baseband_frequency_max_hz = SIGFOX_MACRO_CHANNEL_WIDTH_HZ - ((sigfox_ep_frequency_ctx.rc) -> macro_channel_guard_band_hz); +#if (defined BIDIRECTIONAL) && !(defined SINGLE_FRAME) + // Add offset in case of bidirectional procedure. + sigfox_ep_frequency_ctx.baseband_frequency_min_hz += (((sigfox_ep_frequency_ctx.rc) -> spectrum_access) -> delta_f_mf_hz) * ((sigfox_ep_frequency_ctx.input) -> bidirectional_flag); + sigfox_ep_frequency_ctx.baseband_frequency_max_hz -= (((sigfox_ep_frequency_ctx.rc) -> spectrum_access) -> delta_f_mf_hz) * ((sigfox_ep_frequency_ctx.input) -> bidirectional_flag); +#endif + // Compute bandwidth. + sigfox_ep_frequency_ctx.baseband_bandwidth_hz = (sigfox_ep_frequency_ctx.baseband_frequency_max_hz - sigfox_ep_frequency_ctx.baseband_frequency_min_hz); +} + +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) && !(defined SINGLE_FRAME) +/*******************************************************************/ +static sfx_bool _is_micro_channel_free(sfx_u8 micro_channel_index) { + // Thanks to the FH timer, a micro-channel is free when all frames of the message have been sent. + sfx_bool micro_channel_free = (sigfox_ep_frequency_ctx.micro_channel_frame_count[micro_channel_index] >= SIGFOX_UL_FRAME_RANK_LAST) ? SFX_TRUE : SFX_FALSE; + return micro_channel_free; +} +#endif + +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) +/*******************************************************************/ +static sfx_u8 _get_micro_channel_index(sfx_u32 baseband_frequency_hz) { + // Local variables. + sfx_u8 micro_channel_index = 0; + // Compute index. + micro_channel_index = ((baseband_frequency_hz + (SIGFOX_FH_MACRO_CHANNEL_DELTA / 2)) / SIGFOX_FH_MICRO_CHANNEL_WIDTH_HZ); + micro_channel_index %= SIGFOX_FH_MICRO_CHANNEL_NUMBER; + // Check micro-channels mask. + if (((SIGFOX_FH_MICRO_CHANNEL_MASK >> micro_channel_index) & 0x01) == 0) { + micro_channel_index = SIGFOX_EP_FREQUENCY_FH_MICRO_CHANNEL_ERROR; + goto errors; + } + // Check low side micro-channel guard band. + if ((baseband_frequency_hz - (SIGFOX_FH_MACRO_CHANNEL_GUARD_BAND_HZ + (SIGFOX_FH_MICRO_CHANNEL_WIDTH_HZ * (micro_channel_index - 1)))) < SIGFOX_FH_MICRO_CHANNEL_GUARD_BAND_HZ) { + micro_channel_index = SIGFOX_EP_FREQUENCY_FH_MICRO_CHANNEL_ERROR; + goto errors; + } + // Check high side micro-channel guard band. + if (((SIGFOX_FH_MACRO_CHANNEL_GUARD_BAND_HZ + (SIGFOX_FH_MICRO_CHANNEL_WIDTH_HZ * micro_channel_index)) - baseband_frequency_hz) < SIGFOX_FH_MICRO_CHANNEL_GUARD_BAND_HZ) { + micro_channel_index = SIGFOX_EP_FREQUENCY_FH_MICRO_CHANNEL_ERROR; + goto errors; + } +errors: + return micro_channel_index; +} +#endif + +/*******************************************************************/ +static SIGFOX_EP_FREQUENCY_status_t _compute_new_random_frequency(sfx_u32 *frequency_hz) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_EP_FREQUENCY_status_t status = SIGFOX_EP_FREQUENCY_SUCCESS; +#endif + sfx_u32 baseband_frequency_hz = 0; + sfx_u32 random_generation_count = 0; + sfx_bool baseband_frequency_allowed = SFX_FALSE; +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sfx_u8 micro_channel_index = 0; +#endif + // Call the random algorithm until a valid frequency is computed. + do { + // Generate new random value. + sigfox_ep_frequency_ctx.random_value = (SIGFOX_EP_FREQUENCY_RANDOM_MULTIPLIER * sigfox_ep_frequency_ctx.random_value) + sigfox_ep_frequency_ctx.random_offset; + sigfox_ep_frequency_ctx.random_value &= SIGFOX_EP_FREQUENCY_RANDOM_VALUE_MASK; + random_generation_count++; + // Convert to baseband frequency. + baseband_frequency_hz = ((sfx_u32) sigfox_ep_frequency_ctx.baseband_frequency_min_hz); + baseband_frequency_hz += (((sfx_u32) sigfox_ep_frequency_ctx.random_value) * ((sfx_u32) (sigfox_ep_frequency_ctx.baseband_bandwidth_hz))) / (SIGFOX_EP_FREQUENCY_RANDOM_VALUE_MAX); +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + // Additional check on micro-channel in case of FCC + if (((sigfox_ep_frequency_ctx.rc) -> spectrum_access -> type) == SIGFOX_SPECTRUM_ACCESS_TYPE_FH) { + // Get micro channel index. + micro_channel_index = _get_micro_channel_index(baseband_frequency_hz); + if (micro_channel_index != SIGFOX_EP_FREQUENCY_FH_MICRO_CHANNEL_ERROR) { +#ifdef SINGLE_FRAME + // Thanks to the FH timer, a given micro-channels is always free in single frame mode. + baseband_frequency_allowed = SFX_TRUE; +#else + // Micro-channel index is valid, check if it is free. + baseband_frequency_allowed = _is_micro_channel_free(micro_channel_index); +#endif + } + else { + // Frequency is in guard band. + baseband_frequency_allowed = SFX_FALSE; + } + } + else { + // Frequency is valid. + baseband_frequency_allowed = SFX_TRUE; + } +#else + baseband_frequency_allowed = SFX_TRUE; +#endif + // Check request count. + if (random_generation_count > SIGFOX_EP_FREQUENCY_RANDOM_GENERATION_LIMIT) { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_RANDOM_GENERATION); + } + } + while (baseband_frequency_allowed == SFX_FALSE); + // Convert to absolute frequency. + (*frequency_hz) = ((sigfox_ep_frequency_ctx.rc) -> f_ul_hz) - (SIGFOX_MACRO_CHANNEL_WIDTH_HZ / 2) + baseband_frequency_hz; +#ifdef BIDIRECTIONAL + // Store frame 1 frequency for future computation if bidirectional. +#ifdef SINGLE_FRAME + sigfox_ep_frequency_ctx.frame_1_frequency_hz = (*frequency_hz); +#else + if (((sigfox_ep_frequency_ctx.input) -> ul_frame_rank) == SIGFOX_UL_FRAME_RANK_1) { + sigfox_ep_frequency_ctx.frame_1_frequency_hz = (*frequency_hz); + } +#endif /* SINGLE_FRAME */ +#endif /* BIDIRECTIONAL */ +errors: + RETURN(); +} + +/*** SIGFOX EP FREQUENCY functions ***/ + +/*******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_init(const SIGFOX_rc_t *rc, sfx_u8 *ep_id, sfx_u16 last_random_value) { + // Local variables. + sfx_u32 ep_id_16bits = 0; +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sfx_u8 idx = 0; +#endif +#ifdef ERROR_CODES + SIGFOX_EP_FREQUENCY_status_t status = SIGFOX_EP_FREQUENCY_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + // Check parameter. + if ((rc == SFX_NULL) || (ep_id == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_NULL_PARAMETER); + } +#endif /* PARAMETERS_CHECK */ + // Store RC and last random value. + sigfox_ep_frequency_ctx.rc = rc; + sigfox_ep_frequency_ctx.random_value = last_random_value; + // Compute random offset with EP-ID. + ep_id_16bits = ((((sfx_u32) ep_id[2]) << 8) & 0xFF00) | (((sfx_u32) ep_id[3]) & 0x00FF); + sigfox_ep_frequency_ctx.random_offset = (SIGFOX_EP_FREQUENCY_RANDOM_MULTIPLIER * (ep_id_16bits + 1)) & SIGFOX_EP_FREQUENCY_RANDOM_VALUE_MASK; + if (((sigfox_ep_frequency_ctx.random_offset) % 2) == 0) { + sigfox_ep_frequency_ctx.random_offset++; + } +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + // Init micro-channels frame count (only once). + if (sigfox_ep_frequency_ctx.micro_channel_table_initialized == SFX_FALSE) { + for (idx=0 ; idx> idx) & 0x01); + } + sigfox_ep_frequency_ctx.micro_channel_table_initialized = SFX_TRUE; + } +#endif +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +#ifdef SINGLE_FRAME +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_uplink(sfx_u32 *ul_frequency_hz) { +#else +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_compute_uplink(SIGFOX_EP_FREQUENCY_uplink_signal_t *input, sfx_u32 *ul_frequency_hz) { +#endif +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_FREQUENCY_status_t status = SIGFOX_EP_FREQUENCY_SUCCESS; +#endif +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sfx_u32 baseband_frequency_hz = 0; + sfx_u8 micro_channel_index = 0; +#endif +#ifdef PARAMETERS_CHECK + // Check parameters. +#ifndef SINGLE_FRAME + if (input == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_NULL_PARAMETER); + } +#endif + if (ul_frequency_hz == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_NULL_PARAMETER); + } +#ifndef SINGLE_FRAME + if ((input -> ul_frame_rank) >= SIGFOX_UL_FRAME_RANK_LAST) { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_FRAME_RANK); + } +#endif +#endif /* PARAMETERS_CHECK */ +#ifndef SINGLE_FRAME + // Update local pointers. + sigfox_ep_frequency_ctx.input = input; +#endif + // Update frequency range. + _compute_baseband_frequency_range(); + // Compute frequency. +#ifdef SINGLE_FRAME + // Single frame is always random. + _COMPUTE_NEW_RANDOM_FREQUENCY(); +#else /* SINGLE_FRAME */ + switch (input -> ul_frame_rank) { + case SIGFOX_UL_FRAME_RANK_1: +#ifdef BIDIRECTIONAL + // Reset frame 1 frequency (for error management on frame 2 and 3). + sigfox_ep_frequency_ctx.frame_1_frequency_hz = 0; +#endif + // First frame is always random. + _COMPUTE_NEW_RANDOM_FREQUENCY(); + break; + case SIGFOX_UL_FRAME_RANK_2: +#ifdef BIDIRECTIONAL + // Check bidirectional flag. + if ((input -> bidirectional_flag) == SFX_TRUE) { + if (sigfox_ep_frequency_ctx.frame_1_frequency_hz != 0) { + // Add fixed frequency offset. + (*ul_frequency_hz) = sigfox_ep_frequency_ctx.frame_1_frequency_hz + (((sigfox_ep_frequency_ctx.rc) -> spectrum_access) -> delta_f_mf_hz); + } + else { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_FRAME_1_FREQUENCY); + } + } + else { + // Frequency is random. + _COMPUTE_NEW_RANDOM_FREQUENCY(); + } +#else /* BIDIRECTIONAL */ + // Frequency is random. + _COMPUTE_NEW_RANDOM_FREQUENCY(); +#endif + break; + case SIGFOX_UL_FRAME_RANK_3: +#ifdef BIDIRECTIONAL + // Check bidirectional flag. + if ((input -> bidirectional_flag) == SFX_TRUE) { + // Check if frame 1 frequency was correctly computed. + if (sigfox_ep_frequency_ctx.frame_1_frequency_hz != 0) { + // Add fixed frequency offset. + (*ul_frequency_hz) = sigfox_ep_frequency_ctx.frame_1_frequency_hz - (((sigfox_ep_frequency_ctx.rc) -> spectrum_access) -> delta_f_mf_hz); + } + else { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_FRAME_1_FREQUENCY); + } + } + else { + // Frequency is random. + _COMPUTE_NEW_RANDOM_FREQUENCY(); + } +#else /* BIDIRECTIONAL */ + // Frequency is random. + _COMPUTE_NEW_RANDOM_FREQUENCY(); +#endif + break; + default: + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_FRAME_RANK); + } +#endif /* SINGLE_FRAME */ +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + // Reset selected micro-channel frame count. + baseband_frequency_hz = (*ul_frequency_hz) + (SIGFOX_MACRO_CHANNEL_WIDTH_HZ / 2); + baseband_frequency_hz -= ((sigfox_ep_frequency_ctx.rc) -> f_ul_hz); + micro_channel_index = _get_micro_channel_index(baseband_frequency_hz); + sigfox_ep_frequency_ctx.micro_channel_frame_count[micro_channel_index] = 0; + // Increment all micro channel frame count. + for (micro_channel_index=0 ; micro_channel_index f_dl_hz)) - ((sfx_s32) ((sigfox_ep_frequency_ctx.rc) -> f_ul_hz)); + // Compute downlink frequency. + (*dl_frequency_hz) = (sfx_u32) (((sfx_s32) sigfox_ep_frequency_ctx.frame_1_frequency_hz) + ul_dl_offset_hz); +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} +#endif + +/*******************************************************************/ +SIGFOX_EP_FREQUENCY_status_t SIGFOX_EP_FREQUENCY_get_random_value(sfx_u16 *random_value) { +#ifdef ERROR_CODES + SIGFOX_EP_FREQUENCY_status_t status = SIGFOX_EP_FREQUENCY_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if (random_value == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_FREQUENCY_ERROR_NULL_PARAMETER); + } +#endif /* PARAMETERS_CHECK */ + // Update random value. + (*random_value) = sigfox_ep_frequency_ctx.random_value; +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} + diff --git a/src/core/sigfox_tx_control.c b/src/core/sigfox_tx_control.c new file mode 100644 index 0000000..cc9a119 --- /dev/null +++ b/src/core/sigfox_tx_control.c @@ -0,0 +1,532 @@ +/*!***************************************************************** + * \file sigfox_tx_control.c + * \brief Sigfox TX control driver for regulatory operations. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#include "core/sigfox_tx_control.h" + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" +#include "manuf/mcu_api.h" +#ifdef SPECTRUM_ACCESS_LBT +#include "manuf/rf_api.h" +#endif +#include "sigfox_error.h" + +#ifdef REGULATORY + +/*** SIGFOX TX CONTROL local macros ***/ + +#if (defined SPECTRUM_ACCESS_FH) || (defined SPECTRUM_ACCESS_LBT) +#define SIGFOX_TX_CONTROL_TIMER_INSTANCE MCU_API_TIMER_1 +#endif +#ifdef SPECTRUM_ACCESS_FH +#define SIGFOX_TX_CONTROL_FH_TIMER_MS 20000 +#endif +#ifdef UL_BIT_RATE_BPS +#define SIGFOX_TX_CONTROL_FRAME_DURATION_MS ((sigfox_tx_control_ctx.params.bitstream_length_bytes * 8 * 1000) / (UL_BIT_RATE_BPS)) +#else +#define SIGFOX_TX_CONTROL_FRAME_DURATION_MS ((sigfox_tx_control_ctx.params.bitstream_length_bytes * 8 * 1000) / (sigfox_tx_control_ctx.params.ul_bit_rate_bps)) +#endif + +/*** SIGFOX TX CONTROL local structures ***/ + +/*******************************************************************/ +typedef union { + struct { + unsigned pre_check_running : 1; + unsigned post_check_running : 1; + unsigned mcu_timer1_cplt : 1; + unsigned rf_channel_free : 1; + }; + sfx_u8 all; +} SIGFOX_TX_CONTROL_flags_t; + +/*******************************************************************/ +typedef struct { + const SIGFOX_rc_t *rc; + volatile SIGFOX_TX_CONTROL_flags_t flags; + volatile SIGFOX_TX_CONTROL_result_t result; + SIGFOX_TX_CONTROL_parameters_t params; +#ifdef ASYNCHRONOUS + // Process callback for asynchronous mode. + SIGFOX_TX_CONTROL_process_cb_t process_cb; +#endif +} SIGFOX_TX_CONTROL_context_t; + +/*** SIGFOX TX CONTROL local global variables ***/ + +static SIGFOX_TX_CONTROL_context_t sigfox_tx_control_ctx = { + .flags.all = 0, +}; + +/*** SIGFOX TX CONTROL local functions ***/ + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +#define _PROCESS_CALLBACK(void) { \ + if (sigfox_tx_control_ctx.process_cb != SFX_NULL) { \ + sigfox_tx_control_ctx.process_cb(); \ + } \ +} +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +#define _CHECK_CPLT_CALLBACK(void) { \ + if (sigfox_tx_control_ctx.params.cplt_cb != SFX_NULL) { \ + sigfox_tx_control_ctx.params.cplt_cb(); \ + } \ +} +#endif + +#if (defined ASYNCHRONOUS) && ((defined SPECTRUM_ACCESS_LBT) || (defined SPECTRUM_ACCESS_FH)) +/*******************************************************************/ +static void _MCU_API_timer1_cplt_cb(void) { + // Set local flag. + sigfox_tx_control_ctx.flags.mcu_timer1_cplt = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined ASYNCHRONOUS) && (defined SPECTRUM_ACCESS_LBT) +/*******************************************************************/ +static void _RF_API_channel_free_cb(void) { + // Set local flag. + sigfox_tx_control_ctx.flags.rf_channel_free = 1; + _PROCESS_CALLBACK(); +} +#endif + +/*******************************************************************/ +SIGFOX_TX_CONTROL_status_t _store_parameters(SIGFOX_TX_CONTROL_parameters_t *params) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_TX_CONTROL_status_t status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + // Check parameters. + if (params == SFX_NULL) { + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_NULL_PARAMETER); + } +#endif /* PARAMETERS_CHECK */ + sigfox_tx_control_ctx.params.type = (params -> type); + sigfox_tx_control_ctx.params.bitstream_length_bytes = (params -> bitstream_length_bytes); + sigfox_tx_control_ctx.params.last_message_frame = (params -> last_message_frame); +#ifndef SINGLE_FRAME + sigfox_tx_control_ctx.params.ul_frame_rank = (params -> ul_frame_rank); + sigfox_tx_control_ctx.params.number_of_frames = (params -> number_of_frames); +#endif +#ifndef UL_BTT_RATE + sigfox_tx_control_ctx.params.ul_bit_rate_bps = (params -> ul_bit_rate_bps); +#endif +#ifdef BIDIRECTIONAL + sigfox_tx_control_ctx.params.ack_message = (params -> ack_message); +#endif +#if !(defined SINGLE_FRAME) || (defined BIDIRECTIONAL) + sigfox_tx_control_ctx.params.interframe_ms = (params -> interframe_ms); +#endif +#ifdef ASYNCHRONOUS + sigfox_tx_control_ctx.params.cplt_cb = (params -> cplt_cb); +#endif +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} + +/*** SIGFOX TX CONTROL functions ***/ + +/*******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_open(SIGFOX_TX_CONTROL_config_t *config) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_TX_CONTROL_status_t status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + // Check parameters. + if (config == SFX_NULL) { + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_NULL_PARAMETER); + } + if ((config -> rc) == SFX_NULL) { + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_NULL_PARAMETER); + } +#ifdef ASYNCHRONOUS + if ((config -> process_cb) == SFX_NULL) { + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_NULL_PARAMETER); + } +#endif +#endif /* PARAMETERS_CHECK */ + // Reset flags. + sigfox_tx_control_ctx.flags.all = 0; + // Store RC pointer. + sigfox_tx_control_ctx.rc = (config -> rc); +#ifdef ASYNCHRONOUS + sigfox_tx_control_ctx.process_cb = (config -> process_cb); +#endif +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_check(SIGFOX_TX_CONTROL_parameters_t *params) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_TX_CONTROL_status_t status = SIGFOX_TX_CONTROL_SUCCESS; +#if (defined SPECTRUM_ACCESS_FH) || (defined SPECTRUM_ACCESS_LBT) + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif +#ifdef SPECTRUM_ACCESS_LBT + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif +#endif /* ERROR_CODES */ +#if (defined SPECTRUM_ACCESS_FH) || (defined SPECTRUM_ACCESS_LBT) + MCU_API_timer_t mcu_timer; +#endif +#ifdef SPECTRUM_ACCESS_LBT + RF_API_radio_parameters_t radio_params; + RF_API_carrier_sense_parameters_t cs_params; + sfx_u32 cs_max_duration_ms = 0; +#ifndef SINGLE_FRAME + sfx_u8 number_of_repeated_frames = (sigfox_tx_control_ctx.params.number_of_frames - 1); +#endif +#ifndef ASYNCHRONOUS + sfx_bool channel_free = SFX_FALSE; +#endif +#endif + // Store and check parameters. +#ifdef ERROR_CODES + status = _store_parameters(params); + CHECK_STATUS(SIGFOX_TX_CONTROL_SUCCESS); +#else + _store_parameters(params); +#endif + // Reset flags. + sigfox_tx_control_ctx.flags.all = 0; + // Reset result. + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_ALLOWED; + // Perform required check. + switch (((sigfox_tx_control_ctx.rc) -> spectrum_access) -> type) { +#ifdef SPECTRUM_ACCESS_DC + case SIGFOX_SPECTRUM_ACCESS_TYPE_DC: + // TODO: DC check. + break; +#endif +#ifdef SPECTRUM_ACCESS_LDC + case SIGFOX_SPECTRUM_ACCESS_TYPE_LDC: + // TODO: LDC check. + break; +#endif +#ifdef SPECTRUM_ACCESS_FH + case SIGFOX_SPECTRUM_ACCESS_TYPE_FH: +#ifdef CERTIFICATION + // Bypass check if required. + if ((params -> fh_timer_enable) == SFX_FALSE) break; +#endif + // Start FH timer in case of post-check. + if ((sigfox_tx_control_ctx.params.type) == SIGFOX_TX_CONTROL_TYPE_POST_CHECK) { + // Only start timer on the last frame of the message sequence. + if (sigfox_tx_control_ctx.params.last_message_frame == SFX_TRUE) { + mcu_timer.instance = MCU_API_TIMER_1; + mcu_timer.duration_ms = SIGFOX_TX_CONTROL_FH_TIMER_MS; +#ifdef ASYNCHRONOUS + mcu_timer.cplt_cb = (MCU_API_timer_cplt_cb_t) &_MCU_API_timer1_cplt_cb; +#endif +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_start(&mcu_timer); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_start(&mcu_timer); +#endif +#ifdef ASYNCHRONOUS + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_PENDING; +#else + // Wait FH timer completion. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_wait_cplt(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_wait_cplt(MCU_API_TIMER_1); +#endif + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_ALLOWED; +#endif + } + } + break; +#endif +#ifdef SPECTRUM_ACCESS_LBT + case SIGFOX_SPECTRUM_ACCESS_TYPE_LBT: +#ifdef CERTIFICATION + // Bypass check if required. + if ((params -> lbt_enable) == SFX_FALSE) break; +#endif + // Execute LBT in case of pre-check. + if ((sigfox_tx_control_ctx.params.type) == SIGFOX_TX_CONTROL_TYPE_PRE_CHECK) { + // Compute carrier sense maximum duration. +#ifdef SINGLE_FRAME + // Use user-defined timeout for first frame. + cs_max_duration_ms = (sigfox_tx_control_ctx.rc -> spectrum_access) -> cs_max_duration_first_frame_ms; +#else + // Uplink user message. + if (sigfox_tx_control_ctx.params.ul_frame_rank == SIGFOX_UL_FRAME_RANK_1) { + // Use user-defined timeout for first frame. + cs_max_duration_ms = (sigfox_tx_control_ctx.rc -> spectrum_access) -> cs_max_duration_first_frame_ms; + } + else { + // Use T_LF. + cs_max_duration_ms = SIGFOX_T_LF_MS; + cs_max_duration_ms -= number_of_repeated_frames * (sigfox_tx_control_ctx.params.interframe_ms); // Remove inter-frame delay(s). + cs_max_duration_ms -= (number_of_repeated_frames - 1) * SIGFOX_TX_CONTROL_FRAME_DURATION_MS; // Remove frame 2 duration. + cs_max_duration_ms /= (number_of_repeated_frames); // Divide remaining time equitably for all repeated frames. + } +#endif +#ifdef BIDIRECTIONAL + // Override in case of DL-ACK frame. + if (sigfox_tx_control_ctx.params.ack_message == SFX_TRUE) { + // DL confirmation message. + cs_max_duration_ms = SIGFOX_T_CONF_MAX_MS - (sigfox_tx_control_ctx.params.interframe_ms); // Tconf. + } +#endif + // Set radio configuration. + radio_params.rf_mode = RF_API_MODE_RX; + radio_params.frequency_hz = ((sigfox_tx_control_ctx.rc) -> f_ul_hz); + radio_params.modulation = RF_API_MODULATION_NONE; + radio_params.bit_rate_bps = 0; +#ifdef BIDIRECTIONAL + radio_params.deviation_hz = 0; +#endif + // Set carrier sense parameters. + cs_params.bandwidth_hz = ((sigfox_tx_control_ctx.rc) -> spectrum_access) -> cs_bandwidth_hz; + cs_params.threshold_dbm = ((sigfox_tx_control_ctx.rc) -> spectrum_access) -> cs_threshold_dbm; + cs_params.min_duration_ms = ((sigfox_tx_control_ctx.rc) -> spectrum_access) -> cs_min_duration_ms; +#ifdef ASYNCHRONOUS + cs_params.channel_free_cb = (RF_API_channel_free_cb_t) &_RF_API_channel_free_cb; +#else + cs_params.channel_free = &channel_free; +#endif + // Init radio for LBT check. +#ifdef ERROR_CODES + rf_status = RF_API_init(&radio_params); + RF_API_check_status(SIGFOX_TX_CONTROL_ERROR_RF); +#else + RF_API_init(&radio_params); +#endif + // Start timer to manage carrier sense timeout. + mcu_timer.instance = MCU_API_TIMER_1; + mcu_timer.duration_ms = cs_max_duration_ms; +#ifdef ASYNCHRONOUS + mcu_timer.cplt_cb = (MCU_API_timer_cplt_cb_t) &_MCU_API_timer1_cplt_cb; +#endif +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_start(&mcu_timer); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_start(&mcu_timer); +#endif + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_PENDING; + // Start carrier sense. +#ifdef ERROR_CODES + status = RF_API_carrier_sense(&cs_params); + RF_API_check_status(SIGFOX_TX_CONTROL_ERROR_RF); +#else + RF_API_carrier_sense(&cs_params); +#endif +#ifdef ASYNCHRONOUS + // Result will be known later after carrier sense. + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_PENDING; +#else /* ASYNCHRONOUS */ + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + // Stop radio. +#ifdef ERROR_CODES + rf_status = RF_API_de_init(); + RF_API_check_status(SIGFOX_TX_CONTROL_ERROR_RF); +#else + RF_API_de_init(); +#endif + // Update result. + sigfox_tx_control_ctx.result = (channel_free == SFX_FALSE) ? SIGFOX_TX_CONTROL_RESULT_FORBIDDEN : SIGFOX_TX_CONTROL_RESULT_ALLOWED; +#endif /* ASYNCHRONOUS */ + } + break; +#endif + default: + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_SPECTRUM_ACCESS); + break; + } +errors: + RETURN(); +} + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_process(void) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_TX_CONTROL_status_t status = SIGFOX_TX_CONTROL_SUCCESS; +#if (defined SPECTRUM_ACCESS_FH) || (defined SPECTRUM_ACCESS_LBT) + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif +#ifdef SPECTRUM_ACCESS_LBT + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif +#endif + // Check flags and update result. + switch (((sigfox_tx_control_ctx.rc) -> spectrum_access) -> type) { +#ifdef SPECTRUM_ACCESS_DC + case SIGFOX_SPECTRUM_ACCESS_TYPE_DC: + // Nothing to do. + break; +#endif +#ifdef SPECTRUM_ACCESS_LDC + case SIGFOX_SPECTRUM_ACCESS_TYPE_LDC: + // Nothing to do. + break; +#endif +#ifdef SPECTRUM_ACCESS_FH + case SIGFOX_SPECTRUM_ACCESS_TYPE_FH: + if ((sigfox_tx_control_ctx.params.type) == SIGFOX_TX_CONTROL_TYPE_POST_CHECK) { + // Check FH timer completion. + if (sigfox_tx_control_ctx.flags.mcu_timer1_cplt != 0) { + // Clear flag. + sigfox_tx_control_ctx.flags.mcu_timer1_cplt = 0; + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + // Update result. + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_ALLOWED; + // Call completion callback. + _CHECK_CPLT_CALLBACK(); + } + } + break; +#endif +#ifdef SPECTRUM_ACCESS_LBT + case SIGFOX_SPECTRUM_ACCESS_TYPE_LBT: + if ((sigfox_tx_control_ctx.params.type) == SIGFOX_TX_CONTROL_TYPE_PRE_CHECK) { + // Check flags. + if ((sigfox_tx_control_ctx.flags.rf_channel_free != 0) || (sigfox_tx_control_ctx.flags.mcu_timer1_cplt != 0)) { + // Update result according to flags. + if (sigfox_tx_control_ctx.flags.mcu_timer1_cplt != 0) { + // Clear flag and update result. + sigfox_tx_control_ctx.flags.mcu_timer1_cplt = 0; + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_FORBIDDEN; + } + if (sigfox_tx_control_ctx.flags.rf_channel_free != 0) { + // Clear flag and update result. + sigfox_tx_control_ctx.flags.rf_channel_free = 0; + sigfox_tx_control_ctx.result = SIGFOX_TX_CONTROL_RESULT_ALLOWED; + } + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_TX_CONTROL_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + // Stop radio. +#ifdef ERROR_CODES + rf_status = RF_API_de_init(); + RF_API_check_status(SIGFOX_TX_CONTROL_ERROR_RF); +#else + RF_API_de_init(); +#endif + // Call completion callback. + _CHECK_CPLT_CALLBACK(); + } + } + break; +#endif + default: + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_SPECTRUM_ACCESS); + break; + } +errors: + RETURN(); +} +#endif + +/*******************************************************************/ +sfx_bool SIGFOX_TX_CONTROL_is_radio_required(SIGFOX_TX_CONTROL_check_type check_type) { + // Local variables. + sfx_bool is_radio_required = SFX_FALSE; +#ifdef SPECTRUM_ACCESS_LBT + // Radio is only required for LBT pre-check. + if (((((sigfox_tx_control_ctx.rc) -> spectrum_access) -> type) == SIGFOX_SPECTRUM_ACCESS_TYPE_LBT) && (check_type == SIGFOX_TX_CONTROL_TYPE_PRE_CHECK)) { + is_radio_required = SFX_TRUE; + } +#endif + return is_radio_required; +} + +/*******************************************************************/ +SIGFOX_TX_CONTROL_status_t SIGFOX_TX_CONTROL_get_result(SIGFOX_TX_CONTROL_result_t *result) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_TX_CONTROL_status_t status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if (result == SFX_NULL) { + EXIT_ERROR(SIGFOX_TX_CONTROL_ERROR_NULL_PARAMETER); + } +#endif /* PARAMETERS_CHECK */ + // Update result. + (*result) = sigfox_tx_control_ctx.result; +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} + +#endif /* REGULATORY */ diff --git a/src/manuf/mcu_api.c b/src/manuf/mcu_api.c new file mode 100644 index 0000000..57ad496 --- /dev/null +++ b/src/manuf/mcu_api.c @@ -0,0 +1,195 @@ +/*!***************************************************************** + * \file mcu_api.c + * \brief MCU drivers. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#include "manuf/mcu_api.h" + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +/*** MCU API functions ***/ + +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) +/*******************************************************************/ +MCU_API_status_t MCU_API_open(MCU_API_config_t *mcu_api_config) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#ifdef LOW_LEVEL_OPEN_CLOSE +/*******************************************************************/ +MCU_API_status_t MCU_API_close(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +MCU_API_status_t MCU_API_process(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +/*******************************************************************/ +MCU_API_status_t MCU_API_timer_start(MCU_API_timer_t *timer) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +/*******************************************************************/ +MCU_API_status_t MCU_API_timer_stop(MCU_API_timer_instance_t timer_instance) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#if (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL) || (defined REGULATORY) || (defined CERTIFICATION) +#ifndef ASYNCHRONOUS +/*******************************************************************/ +MCU_API_status_t MCU_API_timer_wait_cplt(MCU_API_timer_instance_t timer_instance) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif +#endif + +/*******************************************************************/ +MCU_API_status_t MCU_API_aes_128_cbc_encrypt(MCU_API_encryption_data_t *aes_data) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} + +#ifdef CRC_HW +/*******************************************************************/ +MCU_API_status_t MCU_API_compute_crc16(sfx_u8 *data, sfx_u8 data_size, sfx_u16 polynom, sfx_u16 *crc) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#if (defined CRC_HW) && (defined BIDIRECTIONAL) +/*******************************************************************/ +MCU_API_status_t MCU_API_compute_crc8(sfx_u8 *data, sfx_u8 data_size, sfx_u16 polynom, sfx_u8 *crc) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +/*******************************************************************/ +MCU_API_status_t MCU_API_get_ep_id(sfx_u8 *ep_id, sfx_u8 ep_id_size_bytes) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} + +/*******************************************************************/ +MCU_API_status_t MCU_API_get_nvm(sfx_u8 *nvm_data, sfx_u8 nvm_data_size_bytes) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} + +/*******************************************************************/ +MCU_API_status_t MCU_API_set_nvm(sfx_u8 *nvm_data, sfx_u8 nvm_data_size_bytes) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*******************************************************************/ +MCU_API_status_t MCU_API_get_voltage_temperature(sfx_u16 *voltage_idle_mv, sfx_u16 *voltage_tx_mv, sfx_s16 *temperature_tenth_degrees) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#ifdef VERBOSE +/*******************************************************************/ +MCU_API_status_t MCU_API_get_initial_pac(sfx_u8 *initial_pac, sfx_u8 initial_pac_size_bytes) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#ifdef VERBOSE +/*******************************************************************/ +MCU_API_status_t MCU_API_get_version(sfx_u8 **version, sfx_u8 *version_size_char) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return MCU_API_SUCCESS; +#endif +} +#endif + +#ifdef ERROR_CODES +/*******************************************************************/ +void MCU_API_error(void) { + /* To be implemented by the device manufacturer */ +} +#endif diff --git a/src/manuf/rf_api.c b/src/manuf/rf_api.c new file mode 100644 index 0000000..c0d29d8 --- /dev/null +++ b/src/manuf/rf_api.c @@ -0,0 +1,161 @@ +/*!***************************************************************** + * \file rf_api.c + * \brief Radio drivers. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#include "manuf/rf_api.h" + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +/*** RF API functions ***/ + +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) +/*******************************************************************/ +RF_API_status_t RF_API_open(RF_API_config_t *rf_api_config) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +#ifdef LOW_LEVEL_OPEN_CLOSE +/*******************************************************************/ +RF_API_status_t RF_API_close(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +RF_API_status_t RF_API_process(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +/*******************************************************************/ +RF_API_status_t RF_API_wake_up(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} + +/*******************************************************************/ +RF_API_status_t RF_API_sleep(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} + +/*******************************************************************/ +RF_API_status_t RF_API_init(RF_API_radio_parameters_t *radio_parameters) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} + +/*******************************************************************/ +RF_API_status_t RF_API_de_init(void) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} + +/*******************************************************************/ +RF_API_status_t RF_API_send(RF_API_tx_data_t *tx_data) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +RF_API_status_t RF_API_receive(RF_API_rx_data_t *rx_data) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +RF_API_status_t RF_API_get_dl_phy_content_and_rssi(sfx_u8 *dl_phy_content, sfx_u8 dl_phy_content_size, sfx_s16 *dl_rssi_dbm) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) +/*******************************************************************/ +RF_API_status_t RF_API_carrier_sense(RF_API_carrier_sense_parameters_t *carrier_sense_params) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +#ifdef VERBOSE +/*******************************************************************/ +RF_API_status_t RF_API_get_version(sfx_u8 **version, sfx_u8 *version_size_char) { + /* To be implemented by the device manufacturer */ +#ifdef ERROR_CODES + return RF_API_SUCCESS; +#endif +} +#endif + +#ifdef ERROR_CODES +/*******************************************************************/ +void RF_API_error(void) { + /* To be implemented by the device manufacturer */ +} +#endif diff --git a/src/sigfox_ep_api.c b/src/sigfox_ep_api.c new file mode 100644 index 0000000..4623f9a --- /dev/null +++ b/src/sigfox_ep_api.c @@ -0,0 +1,3020 @@ +/*!***************************************************************** + * \file sigfox_ep_api.c + * \brief Sigfox End-Point library API. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#include "sigfox_ep_api.h" + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "manuf/mcu_api.h" +#include "manuf/rf_api.h" +#include "core/sigfox_ep_bitstream.h" +#include "core/sigfox_ep_frequency.h" +#include "sigfox_rc.h" +#ifdef CERTIFICATION +#include "sigfox_ep_api_test.h" +#endif +#ifdef REGULATORY +#include "core/sigfox_tx_control.h" +#endif +#ifdef VERBOSE +#include "sigfox_ep_version.h" +#endif +#include "sigfox_types.h" +#include "sigfox_error.h" + +/*** SIGFOX EP API local macros ***/ + +#ifdef APPLICATION_MESSAGES +#ifdef UL_PAYLOAD_SIZE +#define SIGFOX_EP_API_UL_PAYLOAD_SIZE UL_PAYLOAD_SIZE +#else +#define SIGFOX_EP_API_UL_PAYLOAD_SIZE SIGFOX_UL_PAYLOAD_MAX_SIZE_BYTES +#endif +#endif + +/*** SIGFOX EP API local structures ***/ + +#ifndef ASYNCHRONOUS +/*******************************************************************/ +typedef enum { + SIGFOX_EP_API_STATE_CLOSED, + SIGFOX_EP_API_STATE_READY, +#ifdef REGULATORY + SIGFOX_EP_API_STATE_REGULATORY, +#endif + SIGFOX_EP_API_STATE_UL_MODULATION_PENDING, +#if !(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0) || (defined BIDIRECTIONAL)) + SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER, +#endif +#ifdef BIDIRECTIONAL + SIGFOX_EP_API_STATE_DL_TIMER, + SIGFOX_EP_API_STATE_DL_LISTENING, + SIGFOX_EP_API_STATE_DL_CONFIRMATION_TIMER, + SIGFOX_EP_API_STATE_DL_CONFIRMATION, +#endif + SIGFOX_EP_API_STATE_LAST +} SIGFOX_EP_API_state_t; +#endif + +/*******************************************************************/ +typedef union { + struct { + unsigned error_stack_initialized : 1; + unsigned synchronous : 1; + unsigned send_message_request : 1; + unsigned radio_woken_up : 1; + unsigned ack_message : 1; + unsigned control_message : 1; + unsigned tx_control_pre_check_running : 1; + unsigned tx_control_post_check_running : 1; + unsigned tx_forbidden : 1; + unsigned frame_success : 1; + unsigned nvm_write_pending : 1; + unsigned process_running : 1; + }; + sfx_u16 all; +} SIGFOX_EP_API_internal_flags_t; + +/*******************************************************************/ +typedef union { + struct { + unsigned mcu_process : 1; + unsigned mcu_timer1_cplt : 1; + unsigned mcu_timer2_cplt : 1; + unsigned rf_process : 1; + unsigned rf_tx_cplt : 1; + unsigned rf_rx_data_received : 1; + unsigned tx_control_process : 1; + unsigned tx_control_pre_check_cplt : 1; + unsigned tx_control_post_check_cplt : 1; + unsigned low_level_error : 1; + }; + sfx_u16 all; +} SIGFOX_EP_API_irq_flags_t; + +/*******************************************************************/ +typedef struct { + const SIGFOX_rc_t *rc_ptr; + sfx_u8 ep_id[SIGFOX_EP_ID_SIZE_BYTES]; + SIGFOX_EP_API_state_t state; + SIGFOX_EP_API_message_status_t message_status; + SIGFOX_EP_API_internal_flags_t internal_flags; + volatile SIGFOX_EP_API_irq_flags_t irq_flags; + sfx_u16 message_counter; + sfx_u16 random_value; + sfx_u32 ul_frequency_hz; +#ifndef MESSAGE_COUNTER_ROLLOVER + sfx_u16 message_counter_rollover; +#endif +#ifdef ASYNCHRONOUS + SIGFOX_EP_API_process_cb_t process_cb; + SIGFOX_EP_API_uplink_cplt_cb_t uplink_cplt_cb; +#ifdef BIDIRECTIONAL + SIGFOX_EP_API_downlink_cplt_cb downlink_cplt_cb; +#endif + SIGFOX_EP_API_message_cplt_cb message_cplt_cb; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status_from_callback; +#endif +#endif + // Message data. + SIGFOX_EP_API_status_t (*sending_function_ptr)(void); +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + SIGFOX_EP_API_common_t *common_parameters_ptr; +#endif +#ifdef APPLICATION_MESSAGES + SIGFOX_EP_API_application_message_t *application_message_ptr; +#ifdef ASYNCHRONOUS + SIGFOX_EP_API_application_message_t local_application_message; +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + sfx_u8 local_ul_payload[SIGFOX_EP_API_UL_PAYLOAD_SIZE]; +#endif +#endif /* ASYNCHRONOUS */ +#endif /* APPLICATION_MESSAGES */ +#ifdef BIDIRECTIONAL + // Downlink variables. + sfx_bool dl_status; + sfx_u8 dl_payload[SIGFOX_DL_PAYLOAD_SIZE_BYTES]; + sfx_s16 dl_rssi_dbm; +#endif /* BIDIRECTIONAL */ +#ifdef CONTROL_KEEP_ALIVE_MESSAGE + SIGFOX_EP_API_control_message_t *control_message_ptr; +#ifdef ASYNCHRONOUS + SIGFOX_EP_API_control_message_t local_control_message; +#endif +#endif +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) + sfx_s16 temperature_tenth_degrees; + sfx_u16 voltage_tx_mv; + sfx_u16 voltage_idle_mv; +#endif +#ifndef SINGLE_FRAME + SIGFOX_ul_frame_rank_t ul_frame_rank; + sfx_u8 frame_success_count; +#endif +#if !(defined SINGLE_FRAME) || (defined BIDIRECTIONAL) + sfx_u32 interframe_ms; // Tifu, Tifb or Tconf. +#endif +#ifdef CERTIFICATION + SIGFOX_EP_API_TEST_parameters_t test_parameters; +#endif +} SIGFOX_EP_API_context_t; + +/*** SIGFOX EP API local global variables ***/ + +static SIGFOX_EP_API_context_t sigfox_ep_api_ctx = { + .rc_ptr = SFX_NULL, + .state = SIGFOX_EP_API_STATE_CLOSED, + .internal_flags.all = 0, + .irq_flags.all = 0, + .message_status.all = 0, +#ifndef MESSAGE_COUNTER_ROLLOVER + .message_counter_rollover = 0, +#endif +#ifdef ASYNCHRONOUS +#ifdef ERROR_CODES + .status_from_callback = SIGFOX_EP_API_SUCCESS, +#endif /* ERROR_CODES */ +#endif /* ASYNCHRONOUS */ + .sending_function_ptr = SFX_NULL, +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) + .common_parameters_ptr = SFX_NULL, +#endif +#ifdef APPLICATION_MESSAGES + .application_message_ptr = SFX_NULL, +#ifdef BIDIRECTIONAL + .dl_status = SFX_FALSE, + .dl_rssi_dbm = 0, +#endif /* BIDIRECTIONAL */ +#endif /* APPLICATION_MESSAGES */ +#ifdef CONTROL_KEEP_ALIVE_MESSAGE + .control_message_ptr = SFX_NULL, +#endif +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) + .temperature_tenth_degrees = 0, + .voltage_tx_mv = 0, + .voltage_idle_mv = 0, +#endif +#ifndef SINGLE_FRAME + .ul_frame_rank = SIGFOX_UL_FRAME_RANK_1, + .frame_success_count = 0, +#endif +}; +#ifdef VERBOSE +static const sfx_u8 SIGFOX_EP_API_VERSION[] = SIGFOX_EP_VERSION; +static const sfx_u8 SIGFOX_EP_API_FLAGS[] = SIGFOX_EP_FLAGS; +#endif + +/*** SIGFOX EP API local functions ***/ + +/*******************************************************************/ +#ifdef ERROR_CODES +#define _CHECK_LIBRARY_STATE(state_condition) { if (sigfox_ep_api_ctx.state state_condition) { status = SIGFOX_EP_API_ERROR_STATE; goto error_state; } } +#else +#define _CHECK_LIBRARY_STATE(state_condition) { if (sigfox_ep_api_ctx.state state_condition) { goto error_state; } } +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +#define _PROCESS_CALLBACK(void) { \ + if ((sigfox_ep_api_ctx.process_cb != SFX_NULL) && (sigfox_ep_api_ctx.internal_flags.process_running == 0)) { \ + sigfox_ep_api_ctx.process_cb(); \ + } \ +} +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +#define _UPLINK_CPLT_CALLBACK(void) { \ + if ((sigfox_ep_api_ctx.uplink_cplt_cb != SFX_NULL) && (sigfox_ep_api_ctx.state != SIGFOX_EP_API_STATE_READY)) { \ + sigfox_ep_api_ctx.uplink_cplt_cb(); \ + } \ +} +#endif + +#if (defined ASYNCHRONOUS) && (defined BIDIRECTIONAL) +/*******************************************************************/ +#define _DOWNLINK_CPLT_CALLBACK(void) { \ + if ((sigfox_ep_api_ctx.downlink_cplt_cb != SFX_NULL) && (sigfox_ep_api_ctx.state != SIGFOX_EP_API_STATE_READY)) { \ + sigfox_ep_api_ctx.downlink_cplt_cb(); \ + } \ +} +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +#define _MESSAGE_CPLT_CALLBACK(void) { \ + if ((sigfox_ep_api_ctx.message_cplt_cb != SFX_NULL) && (sigfox_ep_api_ctx.state != SIGFOX_EP_API_STATE_READY)) { \ + sigfox_ep_api_ctx.message_cplt_cb(); \ + } \ +} +#endif + +#ifdef ASYNCHRONOUS +/*******************************************************************/ +static void _MCU_API_process_cb(void) { + // Set local flag. + sigfox_ep_api_ctx.irq_flags.mcu_process = 1; + _PROCESS_CALLBACK(); +} + +#ifdef ASYNCHRONOUS +#ifdef ERROR_CODES +/*******************************************************************/ +static void _MCU_API_error_cb(MCU_API_status_t mcu_status) { + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + // Set local error code. + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); + // Do not call the process if the given status is not an error. + return; +errors: + sigfox_ep_api_ctx.status_from_callback = status; + sigfox_ep_api_ctx.irq_flags.low_level_error = 1; + _PROCESS_CALLBACK(); +} +#else +/*******************************************************************/ +static void _MCU_API_error_cb(void) { + sigfox_ep_api_ctx.irq_flags.low_level_error = 1; + _PROCESS_CALLBACK(); +} +#endif +#endif + +#if (defined ASYNCHRONOUS) && ((!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) || (defined BIDIRECTIONAL)) +/*******************************************************************/ +static void _MCU_API_timer1_cplt_cb(void) { + // Set local flag. + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined ASYNCHRONOUS) && (defined BIDIRECTIONAL) +/*******************************************************************/ +static void _MCU_API_timer2_cplt_cb(void) { + // Set local flag. + sigfox_ep_api_ctx.irq_flags.mcu_timer2_cplt = 1; + _PROCESS_CALLBACK(); +} +#endif + +/*******************************************************************/ +static void _RF_API_process_cb(void) { + // Set local flag. + sigfox_ep_api_ctx.irq_flags.rf_process = 1; + _PROCESS_CALLBACK(); +} + +#ifdef ASYNCHRONOUS +#ifdef ERROR_CODES +/*******************************************************************/ +static void _RF_API_error_cb(RF_API_status_t rf_status) { + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + // Set local error code. + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); + // Do not call the process if the given status is not an error. + return; +errors: + sigfox_ep_api_ctx.status_from_callback = status; + sigfox_ep_api_ctx.irq_flags.low_level_error = 1; + _PROCESS_CALLBACK(); +} +#else +/*******************************************************************/ +static void _RF_API_error_cb(void) { + sigfox_ep_api_ctx.irq_flags.low_level_error = 1; + _PROCESS_CALLBACK(); +} +#endif +#endif + +/*******************************************************************/ +static void _RF_API_tx_cplt_cb(void) { + // Set local flag. + sigfox_ep_api_ctx.irq_flags.rf_tx_cplt = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined ASYNCHRONOUS) && (defined BIDIRECTIONAL) +/*******************************************************************/ +static void _RF_API_rx_data_received_cb(void) { + // Set local flag. + sigfox_ep_api_ctx.irq_flags.rf_rx_data_received = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined ASYNCHRONOUS) && (defined REGULATORY) +/*******************************************************************/ +static void _SIGFOX_TX_CONTROL_process_cb(void) { + // Set local flag and result. + sigfox_ep_api_ctx.irq_flags.tx_control_process = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined ASYNCHRONOUS) && (defined REGULATORY) +/*******************************************************************/ +static void _SIGFOX_TX_CONTROL_pre_check_cplt_cb(void) { + // Set local flag and result. + sigfox_ep_api_ctx.irq_flags.tx_control_pre_check_cplt = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined ASYNCHRONOUS) && (defined REGULATORY) +/*******************************************************************/ +static void _SIGFOX_TX_CONTROL_post_check_cplt_cb(void) { + // Set local flag and result. + sigfox_ep_api_ctx.irq_flags.tx_control_post_check_cplt = 1; + _PROCESS_CALLBACK(); +} +#endif + +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) && (!(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE)) +/*******************************************************************/ +static SIGFOX_EP_API_status_t _check_common_parameters(SIGFOX_EP_API_common_t *common_params) { + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + // Check parameter. + if (common_params == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } + // Check bit rate. +#ifdef UL_BIT_RATE_BPS + sfx_u8 idx = 0; + sfx_bool bit_rate_valid = SFX_FALSE; + // Check if the given value is allowed. + for (idx=0 ; idx uplink_bit_rate_capability) >> idx) & 0x01) == 0) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_BIT_RATE); + } +#else /* UL_BIT_RATE */ + // Check if the given bit rate exists. + if ((common_params -> ul_bit_rate) >= SIGFOX_UL_BIT_RATE_LAST) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_BIT_RATE); + } + // Check RC capability. + if ((((sigfox_ep_api_ctx.rc_ptr -> uplink_bit_rate_capability) >> (common_params -> ul_bit_rate)) & 0x01) == 0) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_BIT_RATE); + } +#endif /* UL_BIT_RATE */ + // Check TX power regarding RC rule. +#ifdef TX_POWER_DBM_EIRP + if (TX_POWER_DBM_EIRP > ((sigfox_ep_api_ctx.rc_ptr) -> tx_power_dbm_eirp_max)) { +#else + if (((common_params -> tx_power_dbm_eirp)) > ((sigfox_ep_api_ctx.rc_ptr) -> tx_power_dbm_eirp_max)) { +#endif + EXIT_ERROR(SIGFOX_EP_API_ERROR_TX_POWER); + } +#ifndef SINGLE_FRAME + // Check number of frames. + if ((common_params -> number_of_frames) > SIGFOX_UL_FRAME_RANK_LAST) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NUMBER_OF_FRAMES); + } +#ifndef T_IFU_MS + // Check interframe delay. + if ((common_params -> t_ifu_ms) > SIGFOX_T_IFU_MAX_MS) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_T_IFU); + } +#endif +#endif /* MULTIPLE_FRAMES */ +#ifdef PUBLIC_KEY_CAPABLE + // Check key type. + if ((common_params -> ep_key_type) >= SIGFOX_EP_KEY_LAST) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_EP_KEY); + } +#endif +errors: + return status; +} +#endif + +#if (defined APPLICATION_MESSAGES) && (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +/*******************************************************************/ +static SIGFOX_EP_API_status_t _check_application_message(SIGFOX_EP_API_application_message_t *app_msg) { + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + // Check parameter. + if (app_msg == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + // Check payload. + if ((app_msg -> type) == SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY) { + // Payload is required. + if (((app_msg -> ul_payload) == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } + } +#endif + // Check message type. + if ((app_msg -> type) >= SIGFOX_APPLICATION_MESSAGE_TYPE_LAST) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_MESSAGE_TYPE); + } +#ifndef UL_PAYLOAD_SIZE + if ((app_msg -> type) == SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY) { + // Length is required. + if (((app_msg -> ul_payload_size_bytes) == 0) || ((app_msg -> ul_payload_size_bytes) > SIGFOX_UL_PAYLOAD_MAX_SIZE_BYTES)) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_UL_PAYLOAD_SIZE); + } + } +#endif +#if (defined BIDIRECTIONAL) && !(defined T_CONF_MS) + // Check downlink parameters. + if ((app_msg -> bidirectional_flag) != 0) { + // Check DL confirmation delay. + if (((app_msg -> t_conf_ms) < SIGFOX_T_CONF_MIN_MS) || ((app_msg -> t_conf_ms) > SIGFOX_T_CONF_MAX_MS)) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_T_CONF); + } + } +#endif +errors: + return status; +} +#endif + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) && (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +/*******************************************************************/ +static SIGFOX_EP_API_status_t _check_control_message(SIGFOX_EP_API_control_message_t *ctrl_msg) { + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + // Check parameter. + if (ctrl_msg == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } + // Check message type. + if ((ctrl_msg -> type) >= SIGFOX_CONTROL_MESSAGE_TYPE_LAST) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_MESSAGE_TYPE); + } +errors: + return status; +} +#endif + +#ifdef APPLICATION_MESSAGES +/*******************************************************************/ +static SIGFOX_EP_API_status_t _store_application_message(SIGFOX_EP_API_application_message_t *application_message) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif +#if (defined ASYNCHRONOUS) && (((defined UL_PAYLOAD_SIZE) && (UL_PAYLOAD_SIZE > 0)) || !(defined UL_PAYLOAD_SIZE)) + sfx_u8 idx = 0; +#endif +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) + // Check parameters. + status = _check_application_message(application_message); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + status = _check_common_parameters(&(application_message -> common_parameters)); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#endif +#endif /* PARAMETERS_CHECK and ERROR_CODES*/ +#ifdef ASYNCHRONOUS + // In asynchronous mode, all the data has to be stored locally since the client pointer could be removed. + // Common parameters. +#ifndef UL_BIT_RATE_BPS + sigfox_ep_api_ctx.local_application_message.common_parameters.ul_bit_rate = ((application_message -> common_parameters).ul_bit_rate); +#endif +#ifndef TX_POWER_DBM_EIRP + sigfox_ep_api_ctx.local_application_message.common_parameters.tx_power_dbm_eirp = ((application_message -> common_parameters).tx_power_dbm_eirp); +#endif +#ifndef SINGLE_FRAME + // Number of frames and inter frame delay. + sigfox_ep_api_ctx.local_application_message.common_parameters.number_of_frames = ((application_message -> common_parameters).number_of_frames); +#ifndef T_IFU_MS + sigfox_ep_api_ctx.local_application_message.common_parameters.t_ifu_ms = ((application_message -> common_parameters).t_ifu_ms); + sigfox_ep_api_ctx.interframe_ms = sigfox_ep_api_ctx.local_application_message.common_parameters.t_ifu_ms; +#else + sigfox_ep_api_ctx.interframe_ms = T_IFU_MS; +#endif +#ifdef BIDIRECTIONAL + // Force Tifb in case of bidirectional. + if ((application_message -> bidirectional_flag) != 0) { + sigfox_ep_api_ctx.interframe_ms = SIGFOX_T_IFB_MS; + } +#endif +#endif /* SINGLE_FRAME */ +#ifdef PUBLIC_KEY_CAPABLE + sigfox_ep_api_ctx.local_application_message.common_parameters.ep_key_type = (application_message -> common_parameters).ep_key_type; +#endif + // Message type. + sigfox_ep_api_ctx.local_application_message.type = (application_message -> type); + // Store callbacks (even if NULL). + sigfox_ep_api_ctx.uplink_cplt_cb = (application_message -> uplink_cplt_cb); + sigfox_ep_api_ctx.message_cplt_cb = (application_message -> message_cplt_cb); +#ifdef BIDIRECTIONAL + sigfox_ep_api_ctx.downlink_cplt_cb = (application_message -> downlink_cplt_cb); +#endif + // UL payload. +#ifdef UL_PAYLOAD_SIZE +#if (UL_PAYLOAD_SIZE > 0) + for (idx=0 ; idx ul_payload)[idx]; + } +#endif +#else /* UL_PAYLOAD_SIZE */ + if ((application_message -> type) == SIGFOX_APPLICATION_MESSAGE_TYPE_BYTE_ARRAY) { + for (idx=0 ; idx<(application_message -> ul_payload_size_bytes) ; idx++) { + sigfox_ep_api_ctx.local_ul_payload[idx] = (application_message -> ul_payload)[idx]; + } + sigfox_ep_api_ctx.local_application_message.ul_payload_size_bytes = (application_message -> ul_payload_size_bytes); + } + else { + sigfox_ep_api_ctx.local_application_message.ul_payload_size_bytes = 0; + } +#endif +#ifdef BIDIRECTIONAL + // Downlink parameters. + sigfox_ep_api_ctx.local_application_message.bidirectional_flag = (application_message -> bidirectional_flag); +#ifndef T_CONF_MS + sigfox_ep_api_ctx.local_application_message.t_conf_ms = (application_message -> t_conf_ms); +#endif +#endif + // Update pointers to local data. +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + sigfox_ep_api_ctx.common_parameters_ptr = &(sigfox_ep_api_ctx.local_application_message.common_parameters); +#endif + sigfox_ep_api_ctx.application_message_ptr = &(sigfox_ep_api_ctx.local_application_message); +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + (sigfox_ep_api_ctx.application_message_ptr) -> ul_payload = (sfx_u8*) sigfox_ep_api_ctx.local_ul_payload; +#endif +#else /* ASYNCHRONOUS */ + // In blocking mode, the message pointer will directly address the client data since it will be kept during processing. + sigfox_ep_api_ctx.application_message_ptr = application_message; +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + sigfox_ep_api_ctx.common_parameters_ptr = &(application_message -> common_parameters); +#endif +#endif /* ASYNCHRONOUS */ +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +errors: +#endif + RETURN(); +} +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*******************************************************************/ +static SIGFOX_EP_API_status_t _store_control_message(SIGFOX_EP_API_control_message_t *control_message) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) + // Check parameters. + status = _check_control_message(control_message); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + status = _check_common_parameters(&(control_message -> common_parameters)); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#endif +#endif /* PARAMETERS_CHECK and ERROR_CODES */ +#ifdef ASYNCHRONOUS + // In asynchronous mode, all the data has to be stored locally since the client pointer could be removed, and the message pointer will address the local data. + // Common parameters. +#ifndef UL_BIT_RATE_BPS + sigfox_ep_api_ctx.local_control_message.common_parameters.ul_bit_rate = ((control_message -> common_parameters).ul_bit_rate); +#endif +#ifndef TX_POWER_DBM_EIRP + sigfox_ep_api_ctx.local_control_message.common_parameters.tx_power_dbm_eirp = ((control_message -> common_parameters).tx_power_dbm_eirp); +#endif +#ifndef SINGLE_FRAME + // Number of frames and inter frame delay. + sigfox_ep_api_ctx.local_control_message.common_parameters.number_of_frames = ((control_message -> common_parameters).number_of_frames); +#ifndef T_IFU_MS + sigfox_ep_api_ctx.local_control_message.common_parameters.t_ifu_ms = ((control_message -> common_parameters).t_ifu_ms); + sigfox_ep_api_ctx.interframe_ms = sigfox_ep_api_ctx.local_control_message.common_parameters.t_ifu_ms; +#else + sigfox_ep_api_ctx.interframe_ms = T_IFU_MS; +#endif +#endif /* SINGLE_FRAME */ +#ifdef PUBLIC_KEY_CAPABLE + sigfox_ep_api_ctx.local_application_message.common_parameters.ep_key_type = (control_message -> common_parameters).ep_key_type; +#endif + // Message type. + sigfox_ep_api_ctx.local_control_message.type = (control_message -> type); + // Store callbacks (even if NULL). + sigfox_ep_api_ctx.uplink_cplt_cb = (control_message -> uplink_cplt_cb); + sigfox_ep_api_ctx.message_cplt_cb = (control_message -> message_cplt_cb); + // Update pointer to local data. +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + sigfox_ep_api_ctx.common_parameters_ptr = &(sigfox_ep_api_ctx.local_control_message.common_parameters); +#endif + sigfox_ep_api_ctx.control_message_ptr = &(sigfox_ep_api_ctx.local_control_message); +#else /* ASYNCHRONOUS */ + // In blocking mode, the message pointer will directly address the client data since it will be kept during processing. + sigfox_ep_api_ctx.control_message_ptr = control_message; +#if !(defined SINGLE_FRAME) || !(defined UL_BIT_RATE_BPS) || !(defined TX_POWER_DBM_EIRP) || (defined PUBLIC_KEY_CAPABLE) + sigfox_ep_api_ctx.common_parameters_ptr = &(control_message -> common_parameters); +#endif +#endif /* ASYNCHRONOUS */ +#if (defined PARAMETERS_CHECK) && (defined ERROR_CODES) +errors: +#endif + RETURN(); +} +#endif + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _compute_next_ul_frequency(void) { + // Local variables. + sfx_u32 ul_frequency_hz = 0; + sfx_u16 random_value = 0; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + SIGFOX_EP_FREQUENCY_status_t frequency_status = SIGFOX_EP_FREQUENCY_SUCCESS; +#endif +#ifndef SINGLE_FRAME + SIGFOX_EP_FREQUENCY_uplink_signal_t frequency_parameters; +#endif + // Prepare frequency parameters. +#ifndef SINGLE_FRAME + frequency_parameters.ul_frame_rank = sigfox_ep_api_ctx.ul_frame_rank; +#ifdef BIDIRECTIONAL +#ifdef APPLICATION_MESSAGES + if (sigfox_ep_api_ctx.application_message_ptr == SFX_NULL) { + frequency_parameters.bidirectional_flag = 0; + } + else { + frequency_parameters.bidirectional_flag = (sigfox_ep_api_ctx.internal_flags.control_message != 0) ? 0 : ((sigfox_ep_api_ctx.application_message_ptr) -> bidirectional_flag); + } +#else + frequency_parameters.bidirectional_flag = 0; +#endif +#endif +#endif + // Compute frequency. +#ifndef SINGLE_FRAME +#ifdef ERROR_CODES + // Compute frequency. + frequency_status = SIGFOX_EP_FREQUENCY_compute_uplink(&frequency_parameters, &ul_frequency_hz); + SIGFOX_EP_FREQUENCY_check_status(SIGFOX_EP_API_ERROR_FREQUENCY); +#else + SIGFOX_EP_FREQUENCY_compute_uplink(&frequency_parameters, &ul_frequency_hz); +#endif +#else /* MULTIPLE_FRAMES */ +#ifdef ERROR_CODES + // Compute frequency. + frequency_status = SIGFOX_EP_FREQUENCY_compute_uplink(&ul_frequency_hz); + SIGFOX_EP_FREQUENCY_check_status(SIGFOX_EP_API_ERROR_FREQUENCY); +#else + SIGFOX_EP_FREQUENCY_compute_uplink(&ul_frequency_hz); +#endif +#endif /* MULTIPLE_FRAMES */ + // Update random value. +#ifdef ERROR_CODES + frequency_status = SIGFOX_EP_FREQUENCY_get_random_value(&random_value); + SIGFOX_EP_FREQUENCY_check_status(SIGFOX_EP_API_ERROR_FREQUENCY); +#else + SIGFOX_EP_FREQUENCY_get_random_value(&random_value); +#endif + sigfox_ep_api_ctx.random_value = random_value; +#ifdef CERTIFICATION + // Bypass frequency if needed. + if ((sigfox_ep_api_ctx.test_parameters.tx_frequency_hz) != 0) { + ul_frequency_hz = sigfox_ep_api_ctx.test_parameters.tx_frequency_hz; + } +#endif + // Update global variables. + sigfox_ep_api_ctx.ul_frequency_hz = ul_frequency_hz; +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +static sfx_bool _is_downlink_required(void) { + // Local variables. + sfx_bool downlink_required = SFX_FALSE; +#ifdef APPLICATION_MESSAGES + // Check message pointer. + if (sigfox_ep_api_ctx.application_message_ptr == SFX_NULL) goto errors; + // Check bidirectional flag. + if (((sigfox_ep_api_ctx.application_message_ptr -> bidirectional_flag) != 0) && (sigfox_ep_api_ctx.internal_flags.control_message == 0)) { + downlink_required = SFX_TRUE; + } +errors: +#endif + return downlink_required; +} +#endif + +/*******************************************************************/ +static sfx_bool _is_last_frame_of_uplink_sequence(void) { + // Local variables. + sfx_bool last_uplink_frame = SFX_FALSE; +#ifdef SINGLE_FRAME + last_uplink_frame = SFX_TRUE; +#else + if (sigfox_ep_api_ctx.ul_frame_rank >= (((sigfox_ep_api_ctx.common_parameters_ptr) -> number_of_frames) - 1)) { + last_uplink_frame = SFX_TRUE; + } +#endif + return last_uplink_frame; +} + +#if (defined REGULATORY) || (defined ASYNCHRONOUS) +/*******************************************************************/ +static sfx_bool _is_last_frame_of_message_sequence(void) { + // Local variables. + sfx_bool last_message_frame = SFX_FALSE; + // Check flags. +#ifdef BIDIRECTIONAL +#ifdef APPLICATION_MESSAGES + if ((sigfox_ep_api_ctx.application_message_ptr) == SFX_NULL) { + // Do not check bidirectional flag. + if ((sigfox_ep_api_ctx.internal_flags.ack_message != 0) || (_is_last_frame_of_uplink_sequence() == SFX_TRUE)) { + last_message_frame = SFX_TRUE; + } + } + else { + // Check bidirectional flag. + if ((sigfox_ep_api_ctx.internal_flags.ack_message != 0) || ((_is_last_frame_of_uplink_sequence() == SFX_TRUE) && (((sigfox_ep_api_ctx.application_message_ptr) -> bidirectional_flag) == 0))) { + last_message_frame = SFX_TRUE; + } + } +#endif +#else + last_message_frame = _is_last_frame_of_uplink_sequence(); +#endif + return last_message_frame; +} +#endif + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _radio_wake_up(void) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif + // Wake-up radio if in sleep. + if (sigfox_ep_api_ctx.internal_flags.radio_woken_up == 0) { +#ifdef ERROR_CODES + rf_status = RF_API_wake_up(); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_wake_up(); +#endif + // Update flag. + sigfox_ep_api_ctx.internal_flags.radio_woken_up = 1; + } +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _radio_sleep(void) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif + // Turn radio off if active. + if (sigfox_ep_api_ctx.internal_flags.radio_woken_up != 0) { +#ifdef ERROR_CODES + rf_status = RF_API_sleep(); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_sleep(); +#endif + // Update flag. + sigfox_ep_api_ctx.internal_flags.radio_woken_up = 0; + } +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +static void _set_common_bitstream_parameters(SIGFOX_EP_BITSTREAM_common_t *bitsteam_common_parameter_ptr, sfx_u8 *ep_id) { + // EP ID and key. + bitsteam_common_parameter_ptr -> ep_id = ep_id; + // Message counter. + bitsteam_common_parameter_ptr -> message_counter = sigfox_ep_api_ctx.message_counter; +#ifndef MESSAGE_COUNTER_ROLLOVER + // Message counter rollover. + bitsteam_common_parameter_ptr -> message_counter_rollover = sigfox_ep_api_ctx.message_counter_rollover; +#endif +#ifndef SINGLE_FRAME + // Frame rank. + bitsteam_common_parameter_ptr -> ul_frame_rank = sigfox_ep_api_ctx.ul_frame_rank; +#endif +#ifdef PUBLIC_KEY_CAPABLE + bitsteam_common_parameter_ptr -> ep_key_type = (sigfox_ep_api_ctx.common_parameters_ptr) -> ep_key_type; +#endif +} + +#ifdef REGULATORY +/*******************************************************************/ +static void _set_tx_control_parameters(SIGFOX_TX_CONTROL_check_type check_type, SIGFOX_TX_CONTROL_parameters_t *tx_control_params) { + // Update TX control parameters. + tx_control_params -> type = check_type; + tx_control_params -> bitstream_length_bytes = SIGFOX_EP_BITSTREAM_SIZE_BYTES; // TODO dynamic computation. + tx_control_params -> last_message_frame = _is_last_frame_of_message_sequence(); +#ifndef UL_BIT_RATE_BPS + tx_control_params -> ul_bit_rate_bps = SIGFOX_UL_BIT_RATE_BPS_LIST[(sigfox_ep_api_ctx.common_parameters_ptr) -> ul_bit_rate]; +#endif +#ifndef SINGLE_FRAME + tx_control_params -> ul_frame_rank = sigfox_ep_api_ctx.ul_frame_rank; + tx_control_params -> number_of_frames = (sigfox_ep_api_ctx.common_parameters_ptr) -> number_of_frames; +#endif +#ifdef BIDIRECTIONAL + tx_control_params -> ack_message = sigfox_ep_api_ctx.internal_flags.ack_message; +#endif +#if !(defined SINGLE_FRAME) || (defined BIDIRECTIONAL) + tx_control_params -> interframe_ms = sigfox_ep_api_ctx.interframe_ms; // Tifu, Tifb or Tconf. +#endif +#ifdef CERTIFICATION +#ifdef SPECTRUM_ACCESS_FH + tx_control_params -> fh_timer_enable = sigfox_ep_api_ctx.test_parameters.fh_timer_enable; +#endif +#ifdef SPECTRUM_ACCESS_LBT + tx_control_params -> lbt_enable = sigfox_ep_api_ctx.test_parameters.lbt_enable; +#endif +#endif +#ifdef ASYNCHRONOUS + tx_control_params -> cplt_cb = (SIGFOX_TX_CONTROL_check_cplt_cb_t) ((check_type == SIGFOX_TX_CONTROL_TYPE_PRE_CHECK) ? &_SIGFOX_TX_CONTROL_pre_check_cplt_cb : &_SIGFOX_TX_CONTROL_post_check_cplt_cb); +#endif +} +#endif + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _send_frame(sfx_u8 *bitstream, sfx_u8 bitstream_size) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif + RF_API_radio_parameters_t radio_params; + RF_API_tx_data_t tx_data; + // Build radio parameters. + radio_params.rf_mode = RF_API_MODE_TX; + radio_params.modulation = RF_API_MODULATION_DBPSK; + radio_params.frequency_hz = sigfox_ep_api_ctx.ul_frequency_hz; +#ifdef UL_BIT_RATE_BPS + radio_params.bit_rate_bps = UL_BIT_RATE_BPS; +#else + radio_params.bit_rate_bps = SIGFOX_UL_BIT_RATE_BPS_LIST[(sigfox_ep_api_ctx.common_parameters_ptr) -> ul_bit_rate]; +#endif +#ifdef TX_POWER_DBM_EIRP + radio_params.tx_power_dbm_eirp = TX_POWER_DBM_EIRP; +#else + radio_params.tx_power_dbm_eirp = (sigfox_ep_api_ctx.common_parameters_ptr) -> tx_power_dbm_eirp; +#endif +#ifdef BIDIRECTIONAL + radio_params.deviation_hz = 0; +#endif + // Wake-up radio. +#ifdef ERROR_CODES + status = _radio_wake_up(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _radio_wake_up(); +#endif + // Start radio. +#ifdef ERROR_CODES + rf_status = RF_API_init(&radio_params); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_init(&radio_params); +#endif + // Send frame. + tx_data.bitstream = (sfx_u8*) bitstream; + tx_data.bitstream_size_bytes = bitstream_size; +#ifdef ASYNCHRONOUS + tx_data.cplt_cb = (RF_API_tx_cplt_cb_t) &_RF_API_tx_cplt_cb; +#endif +#ifdef ERROR_CODES + rf_status = RF_API_send(&tx_data); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_send(&tx_data); +#endif +#ifndef ASYNCHRONOUS + // Note: thanks to the RF_API_check_status the next lines are not executed in case of RF API error. + // Increment success count. + sigfox_ep_api_ctx.internal_flags.frame_success = 1; +#ifndef SINGLE_FRAME + sigfox_ep_api_ctx.frame_success_count++; +#endif +#endif /* BLOCKING */ +#ifdef ERROR_CODES +errors: +#endif +#ifndef ASYNCHRONOUS + sigfox_ep_api_ctx.irq_flags.rf_tx_cplt = 1; // Set flag manually in blocking mode. +#endif + RETURN(); +} + +#ifdef APPLICATION_MESSAGES +/*******************************************************************/ +static SIGFOX_EP_API_status_t _send_application_frame(void) { + // Local variables. + sfx_u8 idx = 0; + sfx_u8 ep_id[SIGFOX_EP_ID_SIZE_BYTES]; + SIGFOX_EP_BITSTREAM_application_frame_t bitstream_parameters; + sfx_u8 bitstream[SIGFOX_EP_BITSTREAM_SIZE_BYTES]; + sfx_u8 bitstream_size; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + SIGFOX_EP_BITSTREAM_status_t bitstream_status = SIGFOX_EP_BITSTREAM_SUCCESS; +#endif + // Create local EP-ID. + for (idx=0 ; idx type); +#if !(defined UL_PAYLOAD_SIZE) || (UL_PAYLOAD_SIZE > 0) + bitstream_parameters.ul_payload = ((sigfox_ep_api_ctx.application_message_ptr) -> ul_payload); +#endif +#ifndef UL_PAYLOAD_SIZE + bitstream_parameters.ul_payload_size_bytes = ((sigfox_ep_api_ctx.application_message_ptr) -> ul_payload_size_bytes); +#endif +#ifdef BIDIRECTIONAL + bitstream_parameters.bidirectional_flag = ((sigfox_ep_api_ctx.application_message_ptr) -> bidirectional_flag); +#endif + // Build frame. +#ifdef ERROR_CODES + bitstream_status = SIGFOX_EP_BITSTREAM_build_application_frame(&bitstream_parameters, bitstream, &bitstream_size); + SIGFOX_EP_BITSTREAM_check_status(SIGFOX_EP_API_ERROR_BITSTREAM); +#else + SIGFOX_EP_BITSTREAM_build_application_frame(&bitstream_parameters, bitstream, &bitstream_size); +#endif + // Send frame. +#ifdef ERROR_CODES + status = _send_frame(bitstream, bitstream_size); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _send_frame(bitstream, bitstream_size); +#endif +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} +#endif + +#if (defined CONTROL_KEEP_ALIVE_MESSAGE) || (defined BIDIRECTIONAL) +/*******************************************************************/ +static SIGFOX_EP_API_status_t _read_mcu_voltage_temperature(void) { + // Local variables. + sfx_s16 temperature_tenth_degrees = 0; + sfx_u16 voltage_tx_mv = 0; + sfx_u16 voltage_idle_mv = 0; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif +#ifdef SINGLE_FRAME + // Read MCU data. +#ifdef ERROR_CODES + mcu_status = MCU_API_get_voltage_temperature(&voltage_idle_mv, &voltage_tx_mv, &temperature_tenth_degrees); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_voltage_temperature(&voltage_idle_mv, &voltage_tx_mv, &temperature_tenth_degrees); +#endif + // Update global variables. + sigfox_ep_api_ctx.voltage_idle_mv = voltage_idle_mv; + sigfox_ep_api_ctx.voltage_tx_mv = voltage_tx_mv; + sigfox_ep_api_ctx.temperature_tenth_degrees = temperature_tenth_degrees; +#else /* SINGLE_FRAME */ + if (sigfox_ep_api_ctx.ul_frame_rank == SIGFOX_UL_FRAME_RANK_1) { + // Read MCU data. +#ifdef ERROR_CODES + mcu_status = MCU_API_get_voltage_temperature(&voltage_idle_mv, &voltage_tx_mv, &temperature_tenth_degrees); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_voltage_temperature(&voltage_idle_mv, &voltage_tx_mv, &temperature_tenth_degrees); +#endif + // Update global variables. + sigfox_ep_api_ctx.voltage_idle_mv = voltage_idle_mv; + sigfox_ep_api_ctx.voltage_tx_mv = voltage_tx_mv; + sigfox_ep_api_ctx.temperature_tenth_degrees = temperature_tenth_degrees; + } +#endif /* SINGLE_FRAME */ +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*******************************************************************/ +static SIGFOX_EP_API_status_t _send_control_keep_alive_frame(void) { + // Local variables. + sfx_u8 idx = 0; + sfx_u8 ep_id[SIGFOX_EP_ID_SIZE_BYTES]; + SIGFOX_EP_BITSTREAM_control_frame_t bitstream_parameters; + sfx_u8 bitstream[SIGFOX_EP_BITSTREAM_SIZE_BYTES]; + sfx_u8 bitstream_size; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + SIGFOX_EP_BITSTREAM_status_t bitstream_status = SIGFOX_EP_BITSTREAM_SUCCESS; +#endif + // Create local EP-ID. + for (idx=0 ; idx ep_key_type; +#endif + // Check DL frame. +#ifdef ERROR_CODES + bitstream_status = SIGFOX_EP_BITSTREAM_decode_downlink_frame(&bitstream_parameters, &dl_status, (sfx_u8*) dl_payload); + SIGFOX_EP_BITSTREAM_check_status(SIGFOX_EP_API_ERROR_BITSTREAM); +#else + SIGFOX_EP_BITSTREAM_decode_downlink_frame(&bitstream_parameters, &dl_status, (sfx_u8*) dl_payload); +#endif + // Update data in global context. + if (dl_status == SFX_TRUE) { + for (idx=0 ; idx 0))) || (defined BIDIRECTIONAL) +/*******************************************************************/ +static SIGFOX_EP_API_status_t _start_timer1(sfx_u16 duration_ms) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif + MCU_API_timer_t mcu_timer; + // Start timer. + mcu_timer.instance = MCU_API_TIMER_1; + mcu_timer.duration_ms = duration_ms; +#ifdef ASYNCHRONOUS + mcu_timer.cplt_cb = (MCU_API_timer_cplt_cb_t) &_MCU_API_timer1_cplt_cb; +#endif +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_start(&mcu_timer); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_start(&mcu_timer); +#endif +#ifdef ERROR_CODES +errors: + return status; +#endif + RETURN(); +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +static SIGFOX_EP_API_status_t _start_timer2(sfx_u16 duration_ms) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif + MCU_API_timer_t mcu_timer; + // Start timer. + mcu_timer.instance = MCU_API_TIMER_2; + mcu_timer.duration_ms = duration_ms; +#ifdef ASYNCHRONOUS + mcu_timer.cplt_cb = (MCU_API_timer_cplt_cb_t) &_MCU_API_timer2_cplt_cb; +#endif + // Start timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_start(&mcu_timer); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_start(&mcu_timer); +#endif +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} +#endif + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _end_transmission(void); + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _start_transmission(void) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#ifdef REGULATORY + SIGFOX_TX_CONTROL_status_t tx_control_status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#endif +#ifdef REGULATORY + SIGFOX_TX_CONTROL_parameters_t tx_control_params; + SIGFOX_TX_CONTROL_result_t tx_control_pre_check_result = SIGFOX_TX_CONTROL_RESULT_FORBIDDEN; +#endif + // Reset TX success flag. + sigfox_ep_api_ctx.internal_flags.frame_success = 0; + // Compute frequency. + // This must be done here since the frame 1 frequency has to be known for eventual bidirectional procedure, even if the frame itself is not sent (due to error or TX control). +#ifdef ERROR_CODES + status = _compute_next_ul_frequency(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _compute_next_ul_frequency(); +#endif +#ifdef REGULATORY + // Check if radio is required for pre-check. + if (SIGFOX_TX_CONTROL_is_radio_required(SIGFOX_TX_CONTROL_TYPE_PRE_CHECK) == SFX_TRUE) { +#ifdef ERROR_CODES + status = _radio_wake_up(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _radio_wake_up(); +#endif + } + _set_tx_control_parameters(SIGFOX_TX_CONTROL_TYPE_PRE_CHECK, &tx_control_params); + // Start TX control. +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_check(&tx_control_params); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_check(&tx_control_params); +#endif + sigfox_ep_api_ctx.internal_flags.tx_control_pre_check_running = 1; +#ifndef ASYNCHRONOUS + sigfox_ep_api_ctx.irq_flags.tx_control_pre_check_cplt = 1; // Set flag manually in blocking mode. +#endif + // Read result. +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_get_result(&tx_control_pre_check_result); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_get_result(&tx_control_pre_check_result); +#endif + // Update state according to result. + switch (tx_control_pre_check_result) { + case SIGFOX_TX_CONTROL_RESULT_ALLOWED: + // Send frame. +#ifdef ERROR_CODES + status = sigfox_ep_api_ctx.sending_function_ptr(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + sigfox_ep_api_ctx.sending_function_ptr(); +#endif + // Update state. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_UL_MODULATION_PENDING; + break; + case SIGFOX_TX_CONTROL_RESULT_FORBIDDEN: + // Set error flags. + sigfox_ep_api_ctx.message_status.error = 1; + sigfox_ep_api_ctx.internal_flags.tx_forbidden = 1; +#ifdef ERROR_STACK + // Add error to stack. + SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_EP_LIBRARY, SIGFOX_EP_API_ERROR_TX_FORBIDDEN); +#endif + // Try next frame. +#ifdef ERROR_CODES + status = _end_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _end_transmission(); +#endif + break; + case SIGFOX_TX_CONTROL_RESULT_PENDING: + // Wait for completion. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_REGULATORY; + break; + default: + EXIT_ERROR(SIGFOX_EP_API_ERROR_TX_CONTROL); + break; + } +#else /* REGULATORY */ + // Send frame. +#ifdef ERROR_CODES + status = sigfox_ep_api_ctx.sending_function_ptr(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + sigfox_ep_api_ctx.sending_function_ptr(); +#endif + // Update state. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_UL_MODULATION_PENDING; +#endif /* REGULATORY */ +#if (defined ERROR_CODES) || (defined REGULATORY) +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +static void _update_message_status(void) { +#ifdef SINGLE_FRAME +#ifdef BIDIRECTIONAL + // Update message status. + if (sigfox_ep_api_ctx.internal_flags.ack_message != 0) { + sigfox_ep_api_ctx.message_status.ack_frame = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + } + else { + sigfox_ep_api_ctx.message_status.app_frame_1 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + } +#else /* BIDIRECTIONAL */ + // Update message status. + sigfox_ep_api_ctx.message_status.app_frame_1 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; +#endif /* BIDIRECTIONAL */ +#else /* SINGLE_FRAME */ +#ifdef BIDIRECTIONAL + // Update message status. + if (sigfox_ep_api_ctx.internal_flags.ack_message != 0) { + sigfox_ep_api_ctx.message_status.ack_frame = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + } + else { + switch (sigfox_ep_api_ctx.ul_frame_rank) { + case SIGFOX_UL_FRAME_RANK_1: + sigfox_ep_api_ctx.message_status.app_frame_1 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + break; + case SIGFOX_UL_FRAME_RANK_2: + sigfox_ep_api_ctx.message_status.app_frame_2 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + break; + case SIGFOX_UL_FRAME_RANK_3: + sigfox_ep_api_ctx.message_status.app_frame_3 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + break; + default: + break; + } + } +#else /* BIDIRECTIONAL */ + switch (sigfox_ep_api_ctx.ul_frame_rank) { + case SIGFOX_UL_FRAME_RANK_1: + sigfox_ep_api_ctx.message_status.app_frame_1 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + break; + case SIGFOX_UL_FRAME_RANK_2: + sigfox_ep_api_ctx.message_status.app_frame_2 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + break; + case SIGFOX_UL_FRAME_RANK_3: + sigfox_ep_api_ctx.message_status.app_frame_3 = (sigfox_ep_api_ctx.internal_flags.frame_success != 0) ? 1 : 0; + break; + default: + break; + } +#endif /* BIDIRECTIONAL */ +#endif /* SINGLE_FRAME */ +} + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _write_nvm(void) { + // Local variable. + sfx_u8 nvm_data[SIGFOX_NVM_DATA_SIZE_BYTES]; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif + // Write message counter and random value in NVM when at least one frame has been successfully transmitted. +#ifdef SINGLE_FRAME + if (sigfox_ep_api_ctx.internal_flags.frame_success != 0) { +#else + if (sigfox_ep_api_ctx.frame_success_count > 0) { +#endif + // Build local NVM array. + nvm_data[SIGFOX_NVM_DATA_INDEX_MESSAGE_COUNTER_MSB] = (sfx_u8) ((sigfox_ep_api_ctx.message_counter >> 8) & 0x00FF); + nvm_data[SIGFOX_NVM_DATA_INDEX_MESSAGE_COUNTER_LSB] = (sfx_u8) ((sigfox_ep_api_ctx.message_counter >> 0) & 0x00FF); + nvm_data[SIGFOX_NVM_DATA_INDEX_RANDOM_VALUE_MSB] = (sfx_u8) ((sigfox_ep_api_ctx.random_value >> 8) & 0x00FF); + nvm_data[SIGFOX_NVM_DATA_INDEX_RANDOM_VALUE_LSB] = (sfx_u8) ((sigfox_ep_api_ctx.random_value >> 0) & 0x00FF); + // Write NVM. +#ifdef ERROR_CODES + mcu_status = MCU_API_set_nvm(nvm_data, SIGFOX_NVM_DATA_SIZE_BYTES); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_set_nvm(nvm_data, SIGFOX_NVM_DATA_SIZE_BYTES); +#endif + // Update flags. + sigfox_ep_api_ctx.internal_flags.nvm_write_pending = 0; + } +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _compute_state_after_transmission(void) { + // Local variables. + SIGFOX_EP_API_state_t state = SIGFOX_EP_API_STATE_READY; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#if (defined BIDIRECTIONAL) && !(defined SINGLE_FRAME) + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif +#endif +#ifdef SINGLE_FRAME +#ifdef BIDIRECTIONAL + // Compute next state. + if (_is_downlink_required() == SFX_TRUE) { + // Abort downlink sequence if the frame has not been sent due to error or TX control. + if (sigfox_ep_api_ctx.internal_flags.frame_success == 0) { + // Force bidirectional to 0 in order to call the message completion callback. + if (sigfox_ep_api_ctx.application_message_ptr != SFX_NULL) { + (sigfox_ep_api_ctx.application_message_ptr) -> bidirectional_flag = 0; + } + // Force state to ready. + state = SIGFOX_EP_API_STATE_READY; + } + else { + // Start DL_T_W timer. +#ifdef ERROR_CODES + status = _start_timer2(((sigfox_ep_api_ctx.rc_ptr) -> spectrum_access) -> dl_t_w_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer2(((sigfox_ep_api_ctx.rc_ptr) -> spectrum_access) -> dl_t_w_ms); +#endif + state = SIGFOX_EP_API_STATE_DL_TIMER; + } + } + else { + state = SIGFOX_EP_API_STATE_READY; + } +#else /* BIDIRECTIONAL */ + // Compute next state. + state = SIGFOX_EP_API_STATE_READY; +#endif /* BIDIRECTIONAL */ +#else /* SINGLE_FRAME */ +#ifdef BIDIRECTIONAL + // Check bidirectional flag. + if ((sigfox_ep_api_ctx.ul_frame_rank == SIGFOX_UL_FRAME_RANK_1) && (_is_downlink_required() == SFX_TRUE)) { + // Start DL_T_W timer. +#ifdef ERROR_CODES + status = _start_timer2(((sigfox_ep_api_ctx.rc_ptr) -> spectrum_access) -> dl_t_w_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer2(((sigfox_ep_api_ctx.rc_ptr) -> spectrum_access) -> dl_t_w_ms); +#endif + } + // Compute next state. + if (_is_last_frame_of_uplink_sequence() == SFX_TRUE) { + // Check bidirectional condition. + if (_is_downlink_required() == SFX_TRUE) { + // Abort downlink sequence if none frame has been sent due to error or TX control. + if (sigfox_ep_api_ctx.frame_success_count == 0) { + // Stop DL_T_W timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_2); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_2); +#endif + // Force bidirectional to 0 in order to call the message completion callback. + if (sigfox_ep_api_ctx.application_message_ptr != SFX_NULL) { + (sigfox_ep_api_ctx.application_message_ptr) -> bidirectional_flag = 0; + } + // Force state to ready. + state = SIGFOX_EP_API_STATE_READY; + } + else { + state = SIGFOX_EP_API_STATE_DL_TIMER; + } + } + else { + state = SIGFOX_EP_API_STATE_READY; + } + } + else { + // Compute next state. + if (_is_downlink_required() == SFX_TRUE) { + sigfox_ep_api_ctx.interframe_ms = SIGFOX_T_IFB_MS; + state = SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER; + } + else { + // Compute inter-frame duration. +#ifdef T_IFU_MS + sigfox_ep_api_ctx.interframe_ms = T_IFU_MS; +#else + sigfox_ep_api_ctx.interframe_ms = ((sigfox_ep_api_ctx.common_parameters_ptr) -> t_ifu_ms); +#endif + } + // Start inter-frame timer if required. + if ((sigfox_ep_api_ctx.interframe_ms) != 0) { +#ifdef ERROR_CODES + status = _start_timer1(sigfox_ep_api_ctx.interframe_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer1(sigfox_ep_api_ctx.interframe_ms); +#endif + // Update state. + state = SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER; + } + else { + // Inter-frame delay set to 0, directly start next frame. +#ifdef ERROR_CODES + status = _start_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_transmission(); +#endif + } + } +#else /* BIDIRECTIONAL */ + // Compute next state. + if (_is_last_frame_of_uplink_sequence() == SFX_TRUE) { + state = SIGFOX_EP_API_STATE_READY; + } + else { + // Compute inter-frame duration. +#ifdef T_IFU_MS + sigfox_ep_api_ctx.interframe_ms = T_IFU_MS; +#if (T_IFU_MS > 0) + // Start inter-frame timer. +#ifdef ERROR_CODES + status = _start_timer1(sigfox_ep_api_ctx.interframe_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer1(sigfox_ep_api_ctx.interframe_ms); +#endif + // Update state. + state = SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER; +#else /* T_IFU_MS > 0 */ + // Inter-frame delay set to 0, directly start next frame. +#ifdef ERROR_CODES + status = _start_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_transmission(); +#endif +#endif /* T_IFU_MS > 0 */ +#else /* T_IFU_MS */ + sigfox_ep_api_ctx.interframe_ms = ((sigfox_ep_api_ctx.common_parameters_ptr) -> t_ifu_ms); + // Start inter-frame timer if required. + if ((sigfox_ep_api_ctx.interframe_ms) != 0) { +#ifdef ERROR_CODES + status = _start_timer1(sigfox_ep_api_ctx.interframe_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer1(sigfox_ep_api_ctx.interframe_ms); +#endif + // Update state. + state = SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER; + } + else { + // Inter-frame delay set to 0, directly start next frame. +#ifdef ERROR_CODES + status = _start_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_transmission(); +#endif + } +#endif /* T_IFU_MS */ + } +#endif /* BIDIRECTIONAL */ +#endif /* SINGLE_FRAME */ +#ifdef ASYNCHRONOUS + // Manage API callbacks. + if ((_is_last_frame_of_uplink_sequence() == SFX_TRUE) && (sigfox_ep_api_ctx.internal_flags.ack_message == 0)) { + // Call uplink completion callback (except for ACK message). + _UPLINK_CPLT_CALLBACK(); + } + if (_is_last_frame_of_message_sequence() == SFX_TRUE) { + // Call message completion callback. + _MESSAGE_CPLT_CALLBACK(); + } +#endif /* ASYNCHRONOUS */ +#ifndef SINGLE_FRAME + // Increment frame rank. + sigfox_ep_api_ctx.ul_frame_rank++; +#endif + // Update global state. + sigfox_ep_api_ctx.state = state; +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _end_transmission(void) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + RF_API_status_t rf_status = RF_API_SUCCESS; +#ifdef REGULATORY + SIGFOX_TX_CONTROL_status_t tx_control_status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#endif +#ifdef REGULATORY + SIGFOX_TX_CONTROL_parameters_t tx_control_params; + SIGFOX_TX_CONTROL_result_t tx_control_post_check_result = SIGFOX_TX_CONTROL_RESULT_FORBIDDEN; +#endif + // Update message status. + _update_message_status(); + // Stop RF. + // Note: if TX control returned forbidden result, the RF_API_de_init function was already called by the TX control itself. + if (sigfox_ep_api_ctx.internal_flags.frame_success != 0) { +#ifdef ERROR_CODES + rf_status = RF_API_de_init(); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_de_init(); +#endif + } + // Manage radio state and NVM. + if (_is_last_frame_of_uplink_sequence() == SFX_TRUE) { +#ifdef REGULATORY + if (SIGFOX_TX_CONTROL_is_radio_required(SIGFOX_TX_CONTROL_TYPE_POST_CHECK) == SFX_FALSE) { +#ifdef ERROR_CODES + status = _radio_sleep(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _radio_sleep(); +#endif + } +#else /* REGULATORY */ +#ifdef ERROR_CODES + status = _radio_sleep(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _radio_sleep(); +#endif +#endif /* REGULATORY */ + // Write NVM. +#ifdef ERROR_CODES + status = _write_nvm(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _write_nvm(); +#endif + } +#ifdef REGULATORY + // Set parameters. + _set_tx_control_parameters(SIGFOX_TX_CONTROL_TYPE_POST_CHECK, &tx_control_params); +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_check(&tx_control_params); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_check(&tx_control_params); +#endif + sigfox_ep_api_ctx.internal_flags.tx_control_post_check_running = 1; +#ifndef ASYNCHRONOUS + sigfox_ep_api_ctx.irq_flags.tx_control_post_check_cplt = 1; // Set flag manually in blocking mode. +#endif + // Read result. +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_get_result(&tx_control_post_check_result); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_get_result(&tx_control_post_check_result); +#endif + // Update state according to result. + switch (tx_control_post_check_result) { + case SIGFOX_TX_CONTROL_RESULT_FORBIDDEN: + sigfox_ep_api_ctx.message_status.error = 1; + sigfox_ep_api_ctx.internal_flags.tx_forbidden = 1; +#ifdef ERROR_STACK + // Add error to stack. + SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_EP_LIBRARY, SIGFOX_EP_API_ERROR_TX_FORBIDDEN); +#endif + // Note: no break since "forbidden" and "allowed" cases are treated the same way (except for error flag). + case SIGFOX_TX_CONTROL_RESULT_ALLOWED: + // Compute next state. +#ifdef ERROR_CODES + status = _compute_state_after_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _compute_state_after_transmission(); +#endif + break; + case SIGFOX_TX_CONTROL_RESULT_PENDING: + // Wait for completion. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_REGULATORY; + break; + default: + EXIT_ERROR(SIGFOX_EP_API_ERROR_TX_CONTROL); + break; + } +#else /* REGULATORY */ + // Compute next state. +#ifdef ERROR_CODES + status = _compute_state_after_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _compute_state_after_transmission(); +#endif +#endif /* REGULATORY */ +#if (defined ERROR_CODES) || (defined REGULATORY) +errors: +#endif + RETURN(); +} + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +static SIGFOX_EP_API_status_t _start_reception(RF_API_rx_data_t *rx_data_ptr) { + // Local variables. + RF_API_radio_parameters_t radio_params; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + RF_API_status_t rf_status = RF_API_SUCCESS; + SIGFOX_EP_FREQUENCY_status_t frequency_status = SIGFOX_EP_FREQUENCY_SUCCESS; +#endif + // Set radio configuration for downlink reception. + radio_params.rf_mode = RF_API_MODE_RX; + radio_params.modulation = RF_API_MODULATION_GFSK; + radio_params.bit_rate_bps = SIGFOX_DL_BIT_RATE_BPS; + radio_params.deviation_hz = SIGFOX_DL_GFSK_DEVIATION_HZ; + // Set uplink frequency. +#ifdef ERROR_CODES + frequency_status = SIGFOX_EP_FREQUENCY_compute_downlink(&radio_params.frequency_hz); + SIGFOX_EP_FREQUENCY_check_status(SIGFOX_EP_API_ERROR_FREQUENCY); +#else + SIGFOX_EP_FREQUENCY_compute_downlink(&radio_params.frequency_hz); +#endif +#ifdef ERROR_CODES + rf_status = RF_API_init(&radio_params); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_init(&radio_params); +#endif + // Start DL reception. +#ifdef ERROR_CODES + rf_status = RF_API_receive(rx_data_ptr); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_receive(rx_data_ptr); +#endif +#ifdef ERROR_CODES +errors: +#endif + RETURN(); +} +#endif + +/*******************************************************************/ +static void _message_prepare(void) { + // Increment message counter. + // Note: operation is only performed in RAM first, it will be write in NVM when at least 1 frame has been successfully transmitted. + // Note: the nvm_write_pending flag is checked to prevent multiple increments if the previous value was not written in NVM (due to TX control forbidden or error). + if (sigfox_ep_api_ctx.internal_flags.nvm_write_pending == 0) { +#ifdef MESSAGE_COUNTER_ROLLOVER + sigfox_ep_api_ctx.message_counter = (sigfox_ep_api_ctx.message_counter + 1) % MESSAGE_COUNTER_ROLLOVER; +#else + sigfox_ep_api_ctx.message_counter = (sigfox_ep_api_ctx.message_counter + 1) % (sigfox_ep_api_ctx.message_counter_rollover); +#endif + // Update flag. + sigfox_ep_api_ctx.internal_flags.nvm_write_pending = 1; + } + sigfox_ep_api_ctx.internal_flags.tx_forbidden = 0; +#ifndef SINGLE_FRAME + // Reset frame rank. + sigfox_ep_api_ctx.ul_frame_rank = SIGFOX_UL_FRAME_RANK_1; + sigfox_ep_api_ctx.frame_success_count = 0; +#endif +} + +/*******************************************************************/ +static SIGFOX_EP_API_status_t _internal_process(void) { + // Local variables. +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#if (defined ASYNCHRONOUS) || (defined BIDIRECTIONAL) + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif +#if (defined ASYNCHRONOUS) || (defined BIDIRECTIONAL) || (!(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0))) + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif +#ifdef REGULATORY + SIGFOX_TX_CONTROL_status_t tx_control_status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#endif /* ERROR_CODES */ +#ifdef BIDIRECTIONAL + RF_API_rx_data_t rx_data; +#endif +#ifdef REGULATORY + SIGFOX_TX_CONTROL_result_t tx_control_result = SIGFOX_TX_CONTROL_RESULT_FORBIDDEN; +#endif + // Prepare RX data structure. +#ifdef BIDIRECTIONAL + rx_data.dl_phy_content_size = SIGFOX_DL_PHY_CONTENT_SIZE_BYTES; +#ifdef ASYNCHRONOUS + rx_data.data_received_cb = (RF_API_rx_data_received_cb_t) &_RF_API_rx_data_received_cb; +#else + rx_data.data_received = SFX_FALSE; +#endif +#endif + // Check library is opened. + _CHECK_LIBRARY_STATE(== SIGFOX_EP_API_STATE_CLOSED); +#ifdef ASYNCHRONOUS + // Check error flag in case the process was called after a low level error callback. + if (sigfox_ep_api_ctx.irq_flags.low_level_error != 0) { + // Clear flag. + sigfox_ep_api_ctx.irq_flags.low_level_error = 0; + // Exit. + EXIT_ERROR(sigfox_ep_api_ctx.status_from_callback); + } +#endif + // Check low level process flags. +#ifdef ASYNCHRONOUS + if (sigfox_ep_api_ctx.irq_flags.mcu_process != 0) { +#ifdef ERROR_CODES + mcu_status = MCU_API_process(); + sigfox_ep_api_ctx.irq_flags.mcu_process = 0; + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_process(); + sigfox_ep_api_ctx.irq_flags.mcu_process = 0; +#endif + } + if (sigfox_ep_api_ctx.irq_flags.rf_process != 0) { +#ifdef ERROR_CODES + rf_status = RF_API_process(); + sigfox_ep_api_ctx.irq_flags.rf_process = 0; + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_process(); + sigfox_ep_api_ctx.irq_flags.rf_process = 0; +#endif + } +#ifdef REGULATORY + if (sigfox_ep_api_ctx.irq_flags.tx_control_process != 0) { +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_process(); + sigfox_ep_api_ctx.irq_flags.tx_control_process = 0; + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_process(); + sigfox_ep_api_ctx.irq_flags.tx_control_process = 0; +#endif + } +#endif +#endif + // Perform internal state machine. + switch (sigfox_ep_api_ctx.state) { + case SIGFOX_EP_API_STATE_READY: + // Check pending requests. + if (sigfox_ep_api_ctx.internal_flags.send_message_request != 0) { +#ifdef ERROR_CODES + status = _start_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_transmission(); +#endif + // Clear request. + sigfox_ep_api_ctx.internal_flags.send_message_request = 0; + } + break; +#ifdef REGULATORY + case SIGFOX_EP_API_STATE_REGULATORY: + // Check completion flags. + if ((sigfox_ep_api_ctx.irq_flags.tx_control_post_check_cplt != 0) || (sigfox_ep_api_ctx.irq_flags.tx_control_pre_check_cplt != 0)) { + // Check pre-check flags. + if (sigfox_ep_api_ctx.irq_flags.tx_control_pre_check_cplt != 0) { + // Clear flags. + sigfox_ep_api_ctx.irq_flags.tx_control_pre_check_cplt = 0; + sigfox_ep_api_ctx.internal_flags.tx_control_pre_check_running = 0; + // Read result. +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_get_result(&tx_control_result); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_get_result(&tx_control_result); +#endif + // Check TX control status. + if (tx_control_result == SIGFOX_TX_CONTROL_RESULT_ALLOWED) { + // Send frame. +#ifdef ERROR_CODES + status = sigfox_ep_api_ctx.sending_function_ptr(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + sigfox_ep_api_ctx.sending_function_ptr(); +#endif + // Update state. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_UL_MODULATION_PENDING; + } + else { + // Set error flags. + sigfox_ep_api_ctx.message_status.error = 1; + sigfox_ep_api_ctx.internal_flags.tx_forbidden = 1; +#ifdef ERROR_STACK + // Add error to stack. + SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_EP_LIBRARY, SIGFOX_EP_API_ERROR_TX_FORBIDDEN); +#endif + // Compute next state. +#ifdef ERROR_CODES + status = _end_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _end_transmission(); +#endif + } + } + // Check post-check flag. + if (sigfox_ep_api_ctx.irq_flags.tx_control_post_check_cplt != 0) { + // Clear flags. + sigfox_ep_api_ctx.irq_flags.tx_control_post_check_cplt = 0; + sigfox_ep_api_ctx.internal_flags.tx_control_post_check_running = 0; + // Read result. +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_get_result(&tx_control_result); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_get_result(&tx_control_result); +#endif + // Set error flags if needed. + if (tx_control_result == SIGFOX_TX_CONTROL_RESULT_FORBIDDEN) { + sigfox_ep_api_ctx.message_status.error = 1; + sigfox_ep_api_ctx.internal_flags.tx_forbidden = 1; +#ifdef ERROR_STACK + // Add error to stack. + SIGFOX_ERROR_stack(SIGFOX_ERROR_SOURCE_EP_LIBRARY, SIGFOX_EP_API_ERROR_TX_FORBIDDEN); +#endif + } + // Switch to next state whatever the result. +#ifdef ERROR_CODES + status = _compute_state_after_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _compute_state_after_transmission(); +#endif + } + } + break; +#endif + case SIGFOX_EP_API_STATE_UL_MODULATION_PENDING: + // Check end of transmission flag.. + if (sigfox_ep_api_ctx.irq_flags.rf_tx_cplt != 0) { + // Clear flag. + sigfox_ep_api_ctx.irq_flags.rf_tx_cplt = 0; +#ifdef ASYNCHRONOUS + // Increment success count. + sigfox_ep_api_ctx.internal_flags.frame_success = 1; +#ifndef SINGLE_FRAME + sigfox_ep_api_ctx.frame_success_count++; +#endif +#endif + // End transmission. +#ifdef ERROR_CODES + status = _end_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _end_transmission(); +#endif + } + break; +#if !(defined SINGLE_FRAME) && (!(defined T_IFU_MS) || (T_IFU_MS > 0) || (defined BIDIRECTIONAL)) + case SIGFOX_EP_API_STATE_UL_INTER_FRAME_TIMER: +#ifndef ASYNCHRONOUS + // Wait for timer completion. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_wait_cplt(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_wait_cplt(MCU_API_TIMER_1); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = 1; // Set flag manually in blocking mode. +#endif + // Check timer completion flag. + if (sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt != 0) { + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = 0; + // Start next frame. +#ifdef ERROR_CODES + status = _start_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_transmission(); +#endif + } + break; +#endif +#ifdef BIDIRECTIONAL + case SIGFOX_EP_API_STATE_DL_TIMER: +#ifndef ASYNCHRONOUS + // Wait for timer completion. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_wait_cplt(MCU_API_TIMER_2); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_wait_cplt(MCU_API_TIMER_2); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer2_cplt = 1; // Set flag manually in blocking mode. +#endif /* BLOCKING */ + // Check timer completion flag. + if (sigfox_ep_api_ctx.irq_flags.mcu_timer2_cplt != 0) { + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_2); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_2); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer2_cplt = 0; + // Start DL_T_RX timer. +#ifdef ERROR_CODES + status = _start_timer1(((sigfox_ep_api_ctx.rc_ptr) -> spectrum_access) -> dl_t_rx_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer1(((sigfox_ep_api_ctx.rc_ptr) -> spectrum_access) -> dl_t_rx_ms); +#endif + // Wake-up radio. +#ifdef ERROR_CODES + status = _radio_wake_up(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _radio_wake_up(); +#endif +#ifdef ASYNCHRONOUS + // Start DL reception. +#ifdef ERROR_CODES + status = _start_reception(&rx_data); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_reception(&rx_data); +#endif +#endif /* ASYNCHRONOUS */ + // Update state. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_DL_LISTENING; + } + break; + case SIGFOX_EP_API_STATE_DL_LISTENING: +#ifndef ASYNCHRONOUS + // Wait for incoming DL frame or timeout. +#ifdef ERROR_CODES + status = _start_reception(&rx_data); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_reception(&rx_data); +#endif + // If the function exits with dl_frame_received flag set to 0, it means that the DL window timer has elapsed. + sigfox_ep_api_ctx.irq_flags.rf_rx_data_received = rx_data.data_received; + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = !(rx_data.data_received); +#endif /* BLOCKING */ + if (sigfox_ep_api_ctx.irq_flags.rf_rx_data_received != 0) { + // Clear flag. + sigfox_ep_api_ctx.irq_flags.rf_rx_data_received = 0; + // Decode downlink frame. +#ifdef ERROR_CODES + status = _check_dl_frame(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _check_dl_frame(); +#endif + // Restart reception if the frame authentication failed. + if ((sigfox_ep_api_ctx.dl_status) == SFX_FALSE) { +#ifdef ERROR_CODES + rf_status = RF_API_de_init(); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_de_init(); +#endif +#ifdef ASYNCHRONOUS +#ifdef ERROR_CODES + status = _start_reception(&rx_data); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_reception(&rx_data); +#endif +#endif /* ASYNCHRONOUS */ + } + } + if (((sigfox_ep_api_ctx.dl_status) == SFX_TRUE) || (sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt != 0)) { + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = 0; + // Stop radio. +#ifdef ERROR_CODES + rf_status = RF_API_de_init(); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_de_init(); +#endif + // RX sequence done. +#ifdef ERROR_CODES + status = _radio_sleep(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _radio_sleep(); +#endif + // Update state. + if ((sigfox_ep_api_ctx.dl_status) == SFX_TRUE) { + // Update message status. + sigfox_ep_api_ctx.message_status.downlink_frame = 1; +#ifdef ASYNCHRONOUS + _DOWNLINK_CPLT_CALLBACK(); +#endif + // Start DL confirmation timer. +#ifdef T_CONF_MS + sigfox_ep_api_ctx.interframe_ms = T_CONF_MS; +#else + sigfox_ep_api_ctx.interframe_ms = (sigfox_ep_api_ctx.application_message_ptr) -> t_conf_ms; +#endif +#ifdef ERROR_CODES + status = _start_timer1(sigfox_ep_api_ctx.interframe_ms); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_timer1(sigfox_ep_api_ctx.interframe_ms); +#endif + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_DL_CONFIRMATION_TIMER; + } + else { + // Dowlink timeout: set error flag. + sigfox_ep_api_ctx.message_status.error = 1; +#ifdef ASYNCHRONOUS + _MESSAGE_CPLT_CALLBACK(); +#endif + // Force state to ready. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_READY; + } + } + break; + case SIGFOX_EP_API_STATE_DL_CONFIRMATION_TIMER: +#ifndef ASYNCHRONOUS + // Wait for timer completion. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_wait_cplt(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_wait_cplt(MCU_API_TIMER_1); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = 1; // Set flag manually in blocking mode. +#endif + // Check timer completion flag. + if (sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt != 0) { + // Stop timer. +#ifdef ERROR_CODES + mcu_status = MCU_API_timer_stop(MCU_API_TIMER_1); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_timer_stop(MCU_API_TIMER_1); +#endif + sigfox_ep_api_ctx.irq_flags.mcu_timer1_cplt = 0; + // Configure DL confirmation message. + _message_prepare(); + sigfox_ep_api_ctx.internal_flags.control_message = 1; + sigfox_ep_api_ctx.internal_flags.ack_message = 1; +#ifndef SINGLE_FRAME + (sigfox_ep_api_ctx.common_parameters_ptr) -> number_of_frames = 1; +#endif + // Update send function pointer. + sigfox_ep_api_ctx.sending_function_ptr = &_send_dl_confirmation_frame; + // Start confirmation frame. +#ifdef ERROR_CODES + status = _start_transmission(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _start_transmission(); +#endif + } + break; +#endif + default: + // Unknown state. + EXIT_ERROR(SIGFOX_EP_API_ERROR_STATE); + } + // Return here if no error occurred. + RETURN(); +error_state: +errors: +#ifdef ERROR_CODES + // Notify error to low level drivers. + MCU_API_error(); + RF_API_error(); +#endif + // Do not set the error flag and call the message completion callback on the first process call. + if (sigfox_ep_api_ctx.internal_flags.send_message_request == 0) { + // Set error flag and call completion callback. + sigfox_ep_api_ctx.message_status.error = 1; +#ifdef ASYNCHRONOUS + _MESSAGE_CPLT_CALLBACK(); +#endif + } + // Force state to ready after error. + sigfox_ep_api_ctx.state = SIGFOX_EP_API_STATE_READY; + RETURN(); +} + +#ifdef APPLICATION_MESSAGES +/*******************************************************************/ +SIGFOX_EP_API_status_t _send_application_message(SIGFOX_EP_API_application_message_t *application_message) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif + // Check library state. + _CHECK_LIBRARY_STATE(!= SIGFOX_EP_API_STATE_READY); + // Reset message status. + sigfox_ep_api_ctx.message_status.all = 0; + // Reset IRQ flags. + sigfox_ep_api_ctx.irq_flags.all = 0; + // Store application message parameters locally. +#ifdef ERROR_CODES + status = _store_application_message(application_message); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _store_application_message(application_message); +#endif + // Reset context. + _message_prepare(); + // Set internal flags. + sigfox_ep_api_ctx.internal_flags.send_message_request = 1; + sigfox_ep_api_ctx.internal_flags.control_message = 0; + sigfox_ep_api_ctx.internal_flags.ack_message = 0; + // Set sending function pointer. + sigfox_ep_api_ctx.sending_function_ptr = &_send_application_frame; + // Trigger TX. +#ifdef ERROR_CODES + status = _internal_process(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _internal_process(); +#endif +#ifdef ASYNCHRONOUS + if (sigfox_ep_api_ctx.internal_flags.synchronous != 0) { +#endif + // Block until library goes back to READY state. + while (sigfox_ep_api_ctx.state != SIGFOX_EP_API_STATE_READY) { +#ifdef ERROR_CODES + status = _internal_process(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _internal_process(); +#endif + } +#ifdef ASYNCHRONOUS + } +#endif +#if !(defined ASYNCHRONOUS) && (defined REGULATORY) && (defined ERROR_CODES) + // Force status to error if any frame has not been sent due to TX control. + // Note: other errors are caught in the errors label. + if (sigfox_ep_api_ctx.internal_flags.tx_forbidden != 0) { + status = SIGFOX_EP_API_ERROR_TX_FORBIDDEN; + } +#endif /* REGULATORY and BLOCKING */ + // Return here if no error occurred. + sigfox_ep_api_ctx.internal_flags.send_message_request = 0; + RETURN(); +#ifdef ERROR_CODES +errors: + // Set error flag except for state error (in order to keep the message status if a message sequence is ongoing). + sigfox_ep_api_ctx.message_status.error = 1; +#endif +error_state: + // Clear request. + sigfox_ep_api_ctx.internal_flags.send_message_request = 0; + RETURN(); +} +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*******************************************************************/ +SIGFOX_EP_API_status_t _send_control_message(SIGFOX_EP_API_control_message_t *control_message) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif + // Check library state. + _CHECK_LIBRARY_STATE(!= SIGFOX_EP_API_STATE_READY); + // Reset message status. + sigfox_ep_api_ctx.message_status.all = 0; + // Reset IRQ flags. + sigfox_ep_api_ctx.irq_flags.all = 0; + // Store control message parameters locally. +#ifdef ERROR_CODES + status = _store_control_message(control_message); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _store_control_message(control_message); +#endif + // Reset context. + _message_prepare(); + /// Set internal flags. + sigfox_ep_api_ctx.internal_flags.send_message_request = 1; + sigfox_ep_api_ctx.internal_flags.control_message = 1; + sigfox_ep_api_ctx.internal_flags.ack_message = 0; + // Set sending function pointer. + switch (control_message -> type) { +#ifdef CONTROL_KEEP_ALIVE_MESSAGE + case SIGFOX_CONTROL_MESSAGE_TYPE_KEEP_ALIVE: + sigfox_ep_api_ctx.sending_function_ptr = &_send_control_keep_alive_frame; + break; +#endif + default: + // Downlink confirmation is not allowed. + EXIT_ERROR(SIGFOX_EP_API_ERROR_MESSAGE_TYPE); + } + // Trigger TX. +#ifdef ERROR_CODES + status = _internal_process(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _internal_process(); +#endif +#ifdef ASYNCHRONOUS + if (sigfox_ep_api_ctx.internal_flags.synchronous != 0) { +#endif + // Block until library goes back to READY state. + while (sigfox_ep_api_ctx.state != SIGFOX_EP_API_STATE_READY) { +#ifdef ERROR_CODES + status = _internal_process(); + CHECK_STATUS(SIGFOX_EP_API_SUCCESS); +#else + _internal_process(); +#endif + } +#ifdef ASYNCHRONOUS + } +#endif +#if !(defined ASYNCHRONOUS) && (defined REGULATORY) && (defined ERROR_CODES) + // Force status to error if any frame has not been sent due to TX control. + // Note: other errors are caught in the errors label. + if (sigfox_ep_api_ctx.internal_flags.tx_forbidden != 0) { + status = SIGFOX_EP_API_ERROR_TX_FORBIDDEN; + } +#endif /* REGULATORY and BLOCKING */ + // Return here if no error occurred. + sigfox_ep_api_ctx.internal_flags.send_message_request = 0; + RETURN(); +errors: + // Set error flag except for state error (in order to keep the message status if a message sequence is ongoing). + sigfox_ep_api_ctx.message_status.error = 1; +error_state: + // Clear request. + sigfox_ep_api_ctx.internal_flags.send_message_request = 0; + RETURN(); +} +#endif + +/*** SIGFOX EP API functions ***/ + +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_open(SIGFOX_EP_API_config_t *config) { + // Local variables. + sfx_u8 idx = 0; + sfx_u8 ep_id[SIGFOX_EP_ID_SIZE_BYTES]; + sfx_u8 nvm_data[SIGFOX_NVM_DATA_SIZE_BYTES]; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; + SIGFOX_EP_FREQUENCY_status_t frequency_status = SIGFOX_EP_FREQUENCY_SUCCESS; +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif +#ifdef REGULATORY + SIGFOX_TX_CONTROL_status_t tx_control_status = SIGFOX_TX_CONTROL_SUCCESS; +#endif +#endif /* ERROR_CODES */ +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) + MCU_API_config_t mcu_config; + RF_API_config_t rf_config; +#endif +#ifdef REGULATORY + SIGFOX_TX_CONTROL_config_t tx_control_config; +#endif +#if (defined MESSAGE_COUNTER_ROLLOVER) && (defined PARAMETERS_CHECK) + sfx_bool message_counter_rollover_valid = SFX_FALSE; +#endif +#ifdef ERROR_STACK + // Init error stack. + SIGFOX_ERROR_init(); + sigfox_ep_api_ctx.internal_flags.error_stack_initialized = 1; +#endif + // Check state. + _CHECK_LIBRARY_STATE(!= SIGFOX_EP_API_STATE_CLOSED); +#ifdef PARAMETERS_CHECK + // Check parameter. + if (config == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } +#endif + // Check (even if PARAMETERS_CHECK flag is disabled) and store RC. + if ((config -> rc) == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_RC); + } + sigfox_ep_api_ctx.rc_ptr = (config -> rc); +#ifdef MESSAGE_COUNTER_ROLLOVER +#ifdef PARAMETERS_CHECK + // Check message counter macro value. + for (idx=0 ; idx message_counter_rollover) >= SIGFOX_MESSAGE_COUNTER_ROLLOVER_LAST) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_MESSAGE_COUNTER_ROLLOVER); + } +#endif /* PARAMETERS_CHECK */ + // Store message counter rollover. + sigfox_ep_api_ctx.message_counter_rollover = SIGFOX_MESSAGE_COUNTER_ROLLOVER_LIST[config -> message_counter_rollover]; +#endif /* MESSAGE_COUNTER_ROLLOVER */ + // Init MCU API. +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) + mcu_config.rc = sigfox_ep_api_ctx.rc_ptr; +#ifdef ASYNCHRONOUS + mcu_config.process_cb = (MCU_API_process_cb_t) &_MCU_API_process_cb; + mcu_config.error_cb = (MCU_API_error_cb_t) &_MCU_API_error_cb; +#endif +#ifdef ERROR_CODES + mcu_status = MCU_API_open(&mcu_config); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_open(&mcu_config); +#endif +#endif + // Init RF API. +#if (defined ASYNCHRONOUS) || (defined LOW_LEVEL_OPEN_CLOSE) + rf_config.rc = sigfox_ep_api_ctx.rc_ptr; +#ifdef ASYNCHRONOUS + rf_config.process_cb = (RF_API_process_cb_t) &_RF_API_process_cb; + rf_config.error_cb = &_RF_API_error_cb; +#endif +#ifdef ERROR_CODES + rf_status = RF_API_open(&rf_config); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_open(&rf_config); +#endif +#endif +#ifdef REGULATORY + // Init TX CONTROL driver. + tx_control_config.rc = sigfox_ep_api_ctx.rc_ptr; +#ifdef ASYNCHRONOUS + tx_control_config.process_cb = &_SIGFOX_TX_CONTROL_process_cb; +#endif +#ifdef ERROR_CODES + tx_control_status = SIGFOX_TX_CONTROL_open(&tx_control_config); + SIGFOX_TX_CONTROL_check_status(SIGFOX_EP_API_ERROR_TX_CONTROL); +#else + SIGFOX_TX_CONTROL_open(&tx_control_config); +#endif +#endif /* REGULATORY */ +#ifdef ASYNCHRONOUS + // Store process callback (even if NULL). + sigfox_ep_api_ctx.process_cb = (config -> process_cb); + // Update library behavior. + sigfox_ep_api_ctx.internal_flags.synchronous = (sigfox_ep_api_ctx.process_cb == SFX_NULL) ? 1 : 0; +#endif + // Read last message counter and last random value value in NVM. +#ifdef ERROR_CODES + mcu_status = MCU_API_get_nvm(nvm_data, SIGFOX_NVM_DATA_SIZE_BYTES); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_nvm(nvm_data, SIGFOX_NVM_DATA_SIZE_BYTES); +#endif + sigfox_ep_api_ctx.message_counter = 0; + sigfox_ep_api_ctx.message_counter |= ((((sfx_u16) (nvm_data[SIGFOX_NVM_DATA_INDEX_MESSAGE_COUNTER_MSB])) << 8) & 0xFF00); + sigfox_ep_api_ctx.message_counter |= ((((sfx_u16) (nvm_data[SIGFOX_NVM_DATA_INDEX_MESSAGE_COUNTER_LSB])) << 0) & 0x00FF); + sigfox_ep_api_ctx.random_value = 0; + sigfox_ep_api_ctx.random_value |= ((((sfx_u16) (nvm_data[SIGFOX_NVM_DATA_INDEX_RANDOM_VALUE_MSB])) << 8) & 0xFF00); + sigfox_ep_api_ctx.random_value |= ((((sfx_u16) (nvm_data[SIGFOX_NVM_DATA_INDEX_RANDOM_VALUE_LSB])) << 0) & 0x00FF); + // Read device ID. +#ifdef ERROR_CODES + mcu_status = MCU_API_get_ep_id(ep_id, SIGFOX_EP_ID_SIZE_BYTES); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_ep_id(ep_id, SIGFOX_EP_ID_SIZE_BYTES); +#endif + for (idx=0 ; idx tx_frequency_hz); +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sigfox_ep_api_ctx.test_parameters.fh_timer_enable = (test_parameters -> fh_timer_enable); +#endif +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) + sigfox_ep_api_ctx.test_parameters.lbt_enable = (test_parameters -> lbt_enable); +#endif + // Send message. +#ifdef ERROR_CODES + status = _send_application_message(application_message); +#else + _send_application_message(application_message); +#endif +errors: + RETURN(); +} +#endif + +#ifdef CONTROL_KEEP_ALIVE_MESSAGE +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_send_control_message(SIGFOX_EP_API_control_message_t *control_message) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif +#ifdef CERTIFICATION + // Disable all test parameters. + sigfox_ep_api_ctx.test_parameters.tx_frequency_hz = 0; +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sigfox_ep_api_ctx.test_parameters.fh_timer_enable = SFX_TRUE; +#endif +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) + sigfox_ep_api_ctx.test_parameters.lbt_enable = SFX_TRUE; +#endif +#endif + // Send message. +#ifdef ERROR_CODES + status = _send_control_message(control_message); +#else + _send_control_message(control_message); +#endif + RETURN(); +} +#endif + +#if (defined CERTIFICATION) && (defined CONTROL_KEEP_ALIVE_MESSAGE) +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_TEST_send_control_message(SIGFOX_EP_API_control_message_t *control_message, SIGFOX_EP_API_TEST_parameters_t *test_parameters) { + // Local variables. + sfx_u8 idx = 0; +#ifdef ERROR_CODES + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + // Check parameters. + if (test_parameters == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } +#endif + // Check EP-ID. + for (idx=0 ; idx tx_frequency_hz); +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_FH) + sigfox_ep_api_ctx.test_parameters.fh_timer_enable = (test_parameters -> fh_timer_enable); +#endif +#if (defined REGULATORY) && (defined SPECTRUM_ACCESS_LBT) + sigfox_ep_api_ctx.test_parameters.lbt_enable = (test_parameters -> lbt_enable); +#endif + // Send message. +#ifdef ERROR_CODES + status = _send_control_message(control_message); +#else + _send_control_message(control_message); +#endif +errors: + RETURN(); +} +#endif + +#ifdef BIDIRECTIONAL +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_dl_payload(sfx_u8 *dl_payload, sfx_u8 dl_payload_size, sfx_s16 *dl_rssi_dbm) { + // Local variables. + sfx_u8 idx = 0; +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif + // Check library is opened. + _CHECK_LIBRARY_STATE(== SIGFOX_EP_API_STATE_CLOSED); +#ifdef PARAMETERS_CHECK + if ((dl_payload == SFX_NULL) || (dl_rssi_dbm == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } + if (dl_payload_size > SIGFOX_DL_PAYLOAD_SIZE_BYTES) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_DL_PAYLOAD_SIZE); + } +#endif + // Check downlink status. + if (sigfox_ep_api_ctx.message_status.downlink_frame == 0) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_DL_PAYLOAD_UNAVAILABLE); + } + // Copy local bytes into given buffer. + for (idx=0 ; idx SIGFOX_EP_ID_SIZE_BYTES) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_EP_ID); + } +#endif + // Check library is opened. + _CHECK_LIBRARY_STATE(== SIGFOX_EP_API_STATE_CLOSED); + // Read ID directly from MCU driver. +#ifdef ERROR_CODES + mcu_status = MCU_API_get_ep_id(ep_id, ep_id_size_bytes); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_ep_id(ep_id, ep_id_size_bytes); +#endif +error_state: +#if (defined PARAMETERS_CHECK) || (defined ERROR_CODES) +errors: +#endif + RETURN(); +} +#endif + +#ifdef VERBOSE +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_initial_pac(sfx_u8 *initial_pac, sfx_u8 initial_pac_size_bytes) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if (initial_pac == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } + if (initial_pac_size_bytes > SIGFOX_EP_PAC_SIZE_BYTES) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_EP_PAC); + } +#endif + // Check library is opened. + _CHECK_LIBRARY_STATE(== SIGFOX_EP_API_STATE_CLOSED); + // Read PAC directly from MCU driver. +#ifdef ERROR_CODES + mcu_status = MCU_API_get_initial_pac(initial_pac, initial_pac_size_bytes); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_initial_pac(initial_pac, initial_pac_size_bytes); +#endif +error_state: +#if (defined PARAMETERS_CHECK) || (defined ERROR_CODES) +errors: +#endif + RETURN(); +} +#endif + +#ifdef VERBOSE +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_version(SIGFOX_version_t version_type, sfx_u8 **version, sfx_u8 *version_size_char) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; + MCU_API_status_t mcu_status = MCU_API_SUCCESS; + RF_API_status_t rf_status = RF_API_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if ((version == SFX_NULL) || (version_size_char == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } +#endif + // Check library is opened. + _CHECK_LIBRARY_STATE(== SIGFOX_EP_API_STATE_CLOSED); + // Check version type. + switch (version_type) { + case SIGFOX_VERSION_EP_LIBRARY: + (*version) = (sfx_u8*) SIGFOX_EP_API_VERSION; + (*version_size_char) = (sfx_u8) sizeof(SIGFOX_EP_API_VERSION); + break; + case SIGFOX_VERSION_MCU_DRIVER: +#ifdef ERROR_CODES + mcu_status = MCU_API_get_version(version, version_size_char); + MCU_API_check_status(SIGFOX_EP_API_ERROR_MCU); +#else + MCU_API_get_version(version, version_size_char); +#endif + break; + case SIGFOX_VERSION_RF_DRIVER: +#ifdef ERROR_CODES + rf_status = RF_API_get_version(version, version_size_char); + RF_API_check_status(SIGFOX_EP_API_ERROR_RF); +#else + RF_API_get_version(version, version_size_char); +#endif + break; + default: + EXIT_ERROR(SIGFOX_EP_API_ERROR_VERSION); + break; + } +error_state: +errors: + RETURN(); +} +#endif + +#ifdef VERBOSE +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_get_flags(sfx_u8 **ep_flags, sfx_u8 *ep_flags_size_char) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if ((ep_flags == SFX_NULL) || (ep_flags_size_char == SFX_NULL)) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } +#endif + (*ep_flags) = (sfx_u8*) SIGFOX_EP_API_FLAGS; + (*ep_flags_size_char) = (sfx_u8) sizeof(SIGFOX_EP_API_FLAGS); +#ifdef PARAMETERS_CHECK +errors: +#endif + RETURN(); +} +#endif + +#ifdef ERROR_STACK +/*******************************************************************/ +SIGFOX_EP_API_status_t SIGFOX_EP_API_unstack_error(SIGFOX_ERROR_t *error_ptr) { +#ifdef ERROR_CODES + // Local variables. + SIGFOX_EP_API_status_t status = SIGFOX_EP_API_SUCCESS; +#endif +#ifdef PARAMETERS_CHECK + if (error_ptr == SFX_NULL) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_NULL_PARAMETER); + } +#endif + // Check error stack has been initialized. + if (sigfox_ep_api_ctx.internal_flags.error_stack_initialized == 0) { + EXIT_ERROR(SIGFOX_EP_API_ERROR_STATE); + } + // Directly call error stack driver. + SIGFOX_ERROR_unstack(error_ptr); +errors: + RETURN(); +} +#endif diff --git a/src/sigfox_error.c b/src/sigfox_error.c new file mode 100644 index 0000000..b165919 --- /dev/null +++ b/src/sigfox_error.c @@ -0,0 +1,106 @@ +/*!***************************************************************** + * \file sigfox_error.c + * \brief Sigfox error driver. + ******************************************************************* + * \copyright + * + * Copyright (c) 2022, UnaBiz SAS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2 Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3 Neither the name of UnaBiz SAS nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY + * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************/ + +#include "sigfox_error.h" + +#ifdef USE_SIGFOX_EP_FLAGS_H +#include "sigfox_ep_flags.h" +#endif +#include "sigfox_types.h" + +#ifdef ERROR_STACK +/*** SIGFOX EP API local structures ***/ + +/*******************************************************************/ +typedef struct { + SIGFOX_ERROR_t error_stack[ERROR_STACK]; + sfx_u32 error_stack_idx; +} SIGFOX_ERROR_context_t; +#endif + +#ifdef ERROR_STACK +/*** SIGFOX EP API local global variables ***/ + +static SIGFOX_ERROR_context_t sigfox_error_ctx; +#endif + +/*** SIGFOX ERROR functions ***/ + +#ifdef ERROR_STACK +/*******************************************************************/ +void SIGFOX_ERROR_init(void) { + // Reset all errors. + for (sigfox_error_ctx.error_stack_idx=0 ; sigfox_error_ctx.error_stack_idx= ERROR_STACK) { + sigfox_error_ctx.error_stack_idx = 0; + } +} +#endif + +#ifdef ERROR_STACK +/*******************************************************************/ +void SIGFOX_ERROR_unstack(SIGFOX_ERROR_t *error_ptr) { + // Set index to last error. + if (sigfox_error_ctx.error_stack_idx > 0) { + sigfox_error_ctx.error_stack_idx--; + } + else { + sigfox_error_ctx.error_stack_idx = (ERROR_STACK - 1); + } + // Read last error. + (error_ptr -> source) = sigfox_error_ctx.error_stack[sigfox_error_ctx.error_stack_idx].source; + (error_ptr -> code) = sigfox_error_ctx.error_stack[sigfox_error_ctx.error_stack_idx].code; + // Clear error. + sigfox_error_ctx.error_stack[sigfox_error_ctx.error_stack_idx].source = SIGFOX_ERROR_SOURCE_NONE; + sigfox_error_ctx.error_stack[sigfox_error_ctx.error_stack_idx].code = 0; +} +#endif