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