You can get the libraries from ST or directly from this repository: https://github.com/disk91/itsdk-example-sigfox-sx1276/tree/master/Drivers/LIBS
- libSgfxAddonV020_CM0_GCC.a - contains the additional function for sigfox test. Not mandatory.
- libSgfxCmacV100_CM0_GCC.a - contains some functions used for HMAC & encryption (useful) and wrappers to access the ID, PAC, KEY with Secure Element.
- libSgfxCoreV231_CM0_GCC.a - contains the sigfox core protocol implementation
- libSgfxSTModemSx1276V123_CM0_GCC.a - contains the underlying Sx1276 functions
Some remarks about these libraries:
- libSgfxCore come from Sigfox
- It uses an allocated memory space
- libSgfxSTModem comes from ST
- It have large static memory buffer including
- SpiTxBuffer - 3.12KB
- It have large static memory buffer including
The arduino project needs to include these libraries during compilation time with the following order:
- libSgfxSTModem
- libSgfxCore
- libSgfxCmac
- libSgfxAddon
The libraies have been added in src/cortex-m0. The file library.poperties references them.
From itsdk project Inc/drivers/sx1276
- hw.h - common inclusion limiting the modification of the orignial files
- sfgx_credentials.h - api supporting the encryption / hmac functions
- sgfx_sx1276_drivers.h - sx1276 lowlevel function API
- sigfox_lowlevel.h - sx1276 lowlevel function API
- sigfox_sx1276.h - sx1276 lowlevel function API
- sx1276.h - sx1276 lowlevel API (common with LoRaWan)
- sx1276Regs-Fsk.h - sx1276 driver for FSK communications
- sx1276Regs-LoRa.h - sx1276 driver for LoRa communications Moved in src/drivers/sx1276
The organization of these files is not fully clean. in my implementation I’ve tried to no change the ST organization to be able to follow the future ST modifications if some.
From itsdk project Inc/drivers/sigfox
- mcu_api.h - the sigfox core api with system features like memory allocation, timer use…
- rf_api.h - the sigfox core api with radio layer
- se_api.h - the sigfox core api with secure element (ID, PAC, KEY storage)
- se_nvm.h - the sigfox core api with non volatile storage (for Sequence ID…)
- sigfox_api.h - the sigfox end-user API (what the sigfox core is exposing)
- sigfox_types.h - type abstraction
- st_sigfox_api.h - rest of the st api simplified a lot Moved in src/drivers/sigfox
Some of the dependencies are common with the lowan stack, even if they are not useful, they wtill exist to limit the modification of the oraginal ST and Semtech file to be able to track the future modifications. from itsdk project Inc/drivers/lorawan
- phy/radio.h - some needed structure
- systime.h - time function
- timeServer.h - timer function
- trace.h - log function
- util_console.h - log function
- utilities.h - some macro
- utilities_conf.h - some defines / nothing really interesting
- vcom.h - noting really interesting
- murata_cmwx1zzabz.c - low level board integration for ABZ
- sigfox_credentials.c - integration with the encryption layer
- sigfox_lib_api.c - implement the sigfox mcu_api
- sigfox_lowlevel.c - low level radio api implementation
- sigfox_sx1276.c - sx1276 api implementation
- sx1276.c - sx1276 low level driver
- timeServer.c - Semtech API for software timer
- sigfox.c - high level API for end-user
- logger.c - implement the logging level control
- aes128ctr.c - aes wrapper to tiny-AES-c library
- timer.c - implement software timers with callback
- gpio_wrapper.c - Gpio driver
- spi.c - SPI driver
To simplify the IT_SDK integration I also add the compatibility file in src/it_sdk:
- config.h - configure IdSdk - here we have some constant for the ABZ and Sigfox to configure the sifox / murata driver and the it_sdk files
- configSigfox.h - contains the configuration related to Sx1276, somes depends on the board, let see later how to manage it TODO
- config_defines.h - Itsdk list of constant values associated with configuration
- itsdk.h - main sdk header, include some of the other and contains some generic defines
- wrappers.h - low level mcu api (i2c, time, spi, gpio headers)
-
time
- in src/it_sdk/time
- time management functions
- time.h - manage time
- time.c - implementation
- timer.h - manage software timer
- timer.c - implementation
-
eeprom
- in src/it_sdk/eeprom
- The implementation for this module will have to be made in the Arduino library - See arduino wrapper
- manage state & configurations
- eeprom.h - basic eeprom access functions
- sdk_config.h - manage the NVM configuration storage
- sdk_state.h - manage the volatile configuration (device state)
-
logger
- in src/it_sdk/logger
- The implementation for this module will have to be made in the Arduino library - See arduino wrapper
- error.h - list of driver error for tracing
- logger.h - primitive to trace debug / info / warn / error
-
encrypt
- in src/it_sdk/encrypt
- manage the AES encryption for HMAC
- It uses a external lib tiny-AES-c and wrap the function of this lib with itsdk
-
lowpower
- src/it_sdk/lowpower
- header for power management - just used for a lowpower delay (can be normal delay)
- The implementation for this module will have to be made in the Arduino library - See arduino wrapper
-
sigfox
- src/it_sdk/sigfox
- High level API for sigfox
- This file have been modified and simplified to fit with the Arduino implementation
-
stm32
-
Implement the harwdare interface with STM32, contains the GPIO and SPI drivers used by the driver I've prefered to use SPI driver from itsdk instead of making a wrapper with the Wire lib on arduino as the SPI, running with DMA for murata/sigfox is complex to make working and including this in a standard Arduinon driver sounds complicated. from itsdk project Inc/stm32l_sdk/spi, moved in src/drivers/stm32
- spi.c - spi driver header SPI reserve TIM2. So this timer can't be used by the Arduino sketch The SPI driver override the HAL_SPI_TXCpltCallback and HAL_SPI_TxHalfCpltCallback functions it means the following interrupt must be set and handled by Arduino layer
void DMA1_Channel2_3_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_spi1_tx); }
The GPIO driver could be more easy to port but, it was more conveniant to reuse it directly as the Interrupt mechanism is really different than Ardunio one.
-
Here is how the GPIO integartion has been made
-
GPIO
- We need to have the Interrupt handler called by Arduino
void gpio_Callback(uint16_t GPIO_Pin)
The different needed IRQ Handler are:
void EXTI0_1_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); // DIO2 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1); // DIO1 } void EXTI4_15_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); // DIO0 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); // DIO3 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_??); // DIO4 }
I've manage this by creating interrupt handler dedicated for each of the DIO Interrupts and register it with the Arduino Interrupt handler in arduino_wrapper.c. This indirection is required because the ItSDK irq handler needs a Pin Id as a handler can match multiple Pins. These dedicated IRQ handler calls the ItSDK generic handler. The GPIO are initialized by the SX1276InitLowPower() function. Init init all the pins and setup sx1276 to be low power mode.
- To ba able to call the stm32_interrupt_enable function from the C code in arduino_wrapper.c, I had to add a new C to C++ wrapper: in interrupt.h:
#ifdef __cplusplus extern "C" #endif void stm32_interrupt_enable_forC(GPIO_TypeDef *port, uint16_t pin, void (*callback)(void), uint32_t mode);
in interrupt.cpp:
#ifdef __cplusplus extern "C" #endif void stm32_interrupt_enable_forC(GPIO_TypeDef *port, uint16_t pin, void (*callback)(void), uint32_t mode) { std::function<void(void)> _c = callback; stm32_interrupt_enable(port,pin,_c,mode); }
Adding the extern "C" alone would have been working but I was not sure of the side effect on other existing code.
- TODO : We need to inject the correct GPIO setup by setting the right configuration when it can change from a board to another. Currently this is Hardcoded fro Catena-4618 in arduino_wrapper.h.
#define ITSDK_SX1276_TCXO_VCC_BANK __BANK_A // SX1276 GPIO FOR Activating TCXO #define ITSDK_SX1276_TCXO_VCC_PIN __LP_GPIO_8 #define ITSDK_SX1276_DIO_4_BANK __BANK_? // SX1276 GPIO 4 => CAD Detected / Pll lock #define ITSDK_SX1276_DIO_4_PIN __LP_GPIO_?
-
- I've made a src/arduino_wrapper.c file to implement the Arduino version of the ItSDK modules not imported. In this file, some of the implementation is finalyzed, some has been mocked to be able to compile but need to be rewritten.
- from module time.h
void itsdk_delayMs(uint32_t ms); // implemented
uint64_t itsdk_time_get_ms(); // implemented
- from module lowpower.h
uint32_t lowPower_delayMs(uint32_t duration); // implemented full-power (acceptable) no significative saving expected
- from module encrypt.h
void itsdk_encrypt_cifferKey(uint8_t * key, int len); // implemented as doing nothing
void itsdk_encrypt_unCifferKey(uint8_t * key, int len); // implemented as doing nothing
- from wrappers.h
uint16_t adc_getVdd(); // Mocked - Todo
int16_t adc_getTemperature(); // Mocked - Todo
uint32_t itsdk_getIrqMask(); // implemented
void itsdk_setIrqMask(uint32_t mask); // implemented
void itsdk_enterCriticalSection(); // implemented
void itsdk_leaveCriticalSection(); // implemented
- from module eeprom.h
itsdk_sigfox_init_t itsdk_sigfox_getSeNvmOffset(uint32_t * offset); // implemented
itsdk_sigfox_init_t itsdk_sigfox_getNvmOffset(uint32_t * offset); // implemented
uint32_t itdt_align_32b(uint32_t v); // implemented
bool _eeprom_read(uint8_t bank, uint32_t offset, void * data, int len); // Mocked - Todo
bool _eeprom_write(uint8_t bank, uint32_t offset, void * data, int len); // Mocked - Todo
- from module errors.h
itsdk_error_ret_e itsdk_error_noreport(uint32_t error); // Currently do nothing - Todo
- from module logger.h
void serial1_print(char * msg); // implemented - do nothing
void serial2_print(char * msg); // implemented - do nothing
void debug_print(debug_print_type_e lvl, char * msg); // implemented - call the function given on sigfox driver setup
-
When the Sigfox setup is call, some parameters are needed
- deviceID - unique device ID (32b)
- devicePAC - device PAC initially assigned to the device ID
- deviceKEY - device secret KEY, to be protected
- currentRegion - current radio configuration (zone)
- txPower - transmission power
- printLog - print a Log line function, NULL if no log expected
- eepromBase - eeprom offset for the sigfox lib
Currently a structure with the following API is pass to the driver to inject these parameters
// Function wrapper typedef struct { // Get the current REGION (based on LoRaWan region) - see config_defines.h uint8_t (*getCurrentRegion)(uint32_t * region); // Return the deviceId into the given parameter uint8_t (*getDeviceId)(uint32_t * devId); // Return the PAC parameter: a 8 Bytes array uint8_t (*getInitialPac)(uint8_t * pac); // Return the KEY parameter: a 16 Bytes array uint8_t (*getDeviceKey)(uint8_t * kyy); // Return the Tx power (-127 for zone default) uint8_t (*getTxPower)(int8_t * power); // Method to print a log void (*printLog)(char * msg); // Eeprom offset for sigfox lib uint32_t eepromBase; } sigfox_api_t;