sexta-feira, 15 de dezembro de 2023

LSM110A - CONEXÃO LoRaWAN - SDK STM32 - SLEEP, WAKE UP

  

Objetivo

Este documento é um guia básico (resumo) sobre instalação do STM32CubeIDE para a módulo LoRa/SigFox LSM110A LoRa/Sigfox da Seongji então gerar o APP EndNode, bem como os primeiros acessos à rede LoRaWAN e envio de pacotes. Também é mostrado como configurar para trabalhar em uma faixa de frequências e região.

Baseado no Software do oficial da STM, modificado para rodar no LSM110A, também faz a conexão com o servidor CHIRPSTACK ao pressionar o botão e permanece enviando a temperatura para o servidor a cada 30 segundos.

Há também funções de SLEEP , WAKE UP,  BAIXO CONSUMO.

Utiliza uma STATE MACHINE.

Colaboração de um cliente SmartCore


PS: tive que criar a pasta

C:/STM32Cube/Repository/STM32Cube_FW_WL_V1.3.0/Drivers/STM32WLxx_HAL_Driver/Src/stm32wlxx_hal_i2c.c \

C:/STM32Cube/Repository/STM32Cube_FW_WL_V1.3.0/Drivers/STM32WLxx_HAL_Driver/Src/stm32wlxx_hal_i2c_ex.c \

e copiar os drivers do SDK STM32 para lá.
PS: drivers podem ser copiados daqui
C:\STM32CubeWL-smartcore\Drivers\STM32WLxx_HAL_Driver

e comentar linhas do main.c

//#include "declareFunctions.h"



O projeto é

C:\STM32CubeWL-smartcore\Projects\NUCLEO-WL55JC\Applications\LoRaWAN\LoRaWAN_End_Node\STM32CubeIDE


LSM110A Starter KIT
Módulo

O LSM110A é um módulo de última geração que integra o STMicroelectronics STM32WL. 

Baixando o SDK


PS: no caso, baixe o ZIP acima, STM32CubeWL-smartcore .7z

No caso, foi realizado via Prompt de Comando, com o GIT já instalado no Windows, mas você pode baixar em ZIP do repositório e descompactar.



C:\>git clone https://github.com/STMicroelectronics/STM32CubeWL.git

PS: no caso, baixe o ZIP acima, STM32CubeWL-smartcore .7z

Compilação do Firmware 

Para gerar o firmware para o LSM1x0A, será necessário que você instale o STM32CubeIDE em sua máquina.


SDK Build

Ferramentas de desenvolvimento de software ST STM32CubeIDE
Compilando

Este aplicativo conectará o LSM110A com CHIRSTACK e enviará dados após a conexão com um gateway LoRaWAN®.

pir

  • Etapa 2. Extraia o arquivo ZIP e navegue até C:\STM32CubeWL\Projects\NUCLEO-WL55JC\Applications\LoRaWAN\LoRaWAN_End_Node\STM32CubeIDE

  • Etapa 3. Clique duas vezes no arquivo .project


  • Etapa 4. Clique com o botão direito do mouse no projeto e clique em Properties

pir

  • Etapa 5. Navegue até C/C++ Build > Settings > MCU Post build outputs, marque Convert to Intel Hex (-O ihex) e clique em Apply and Close

pir

  • Etapa 6. Clique em Build 'Debug' e ele deve compilar sem erros

construir

pir

  • Etapa 7. A região LoRaWAN® padrão é EU868, você pode modificá-la, definindo a definição de macro ACTIVE_REGIONemLoRaWAN/App/lora_app.h
// LoRaWAN/App/lora_app.h
/* LoraWAN application configuration (Mw is configured by lorawan_conf.h) */
/* Available: LORAMAC_REGION_AS923, LORAMAC_REGION_AU915, LORAMAC_REGION_EU868, LORAMAC_REGION_KR920, LORAMAC_REGION_IN865, LORAMAC_REGION_US915, LORAMAC_REGION_RU864 */
#define ACTIVE_REGION LORAMAC_REGION_AU915 //<=====================
//lorawan_conf.h#define LORAMAC_SPECIFICATION_VERSION 0x01000300 //<=====1.0.3 #define REGION_AU915

pir

  • Passo 8. Após as modificações acima, rebuild o exemplo e programe para o seu LSM110A. Abra STM32CubeProgrammer, conecte o ST-LINK ao seu PC, segure RESET Buttonseu dispositivo, clique Connecte solte RESET Button:
    Conectando S-TLINK V2 no LSM110A Starter KIT, via SWD, Reset antes de gravar

pir

  • Etapa 9. Certifique-se de que a proteção de leitura esteja AA, se for exibida como BB, selecione AAe clique em Apply:

pir

  • Etapa 10. Agora, vá para a Erasing & Programmingpágina, selecione o caminho do arquivo hexadecimal (por exemplo: C:\STM32CubeWL-smartcore\Projects\NUCLEO-WL55JC\Applications\LoRaWAN\LoRaWAN_End_Node\STM32CubeIDE\Debug\LoRaWAN_End_Node.hex), selecione as opções de programação conforme a imagem a seguir e clique em Start Programming!

pir

Você verá a mensagem Download verificado com sucesso , assim que a programação terminar.

  • Etapa 11. Se o seu LoRaWAN® Gateway e CHIRPSTACK estiverem configurados, o LSM110A será conectado com sucesso após a reinicialização!
Alterando BAND MASK
  • Em RegionAU915.c, a máscara utilizada para compatibilizar com configuração utilizada no Gateway LoRaWAN



// Initialize channels default mask /* ST_WORKAROUND_BEGIN: Hybrid mode */ .

. . #else RegionNvmGroup2->ChannelsDefaultMask[0] = 0xFF00; RegionNvmGroup2->ChannelsDefaultMask[1] = 0x0000; RegionNvmGroup2->ChannelsDefaultMask[2] = 0x0000; RegionNvmGroup2->ChannelsDefaultMask[3] = 0x0000; RegionNvmGroup2->ChannelsDefaultMask[4] = 0x0000; RegionNvmGroup2->ChannelsDefaultMask[5] = 0x0000;













Carta de Apresentação

stm32wlxx_nucleo_radio.h

#define RF_SW_CTRL1_PIN GPIO_PIN_12 #define RF_SW_CTRL1_GPIO_PORT GPIOB #define RF_SW_CTRL1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define RF_SW_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() #define RF_SW_CTRL2_PIN GPIO_PIN_13 #define RF_SW_CTRL2_GPIO_PORT GPIOC #define RF_SW_CTRL2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() #define RF_SW_CTRL2_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()

stm32wlxx_nucleo_radio.c

/** * @brief Configure Radio Switch. * @param Config: Specifies the Radio RF switch path to be set. * This parameter can be one of following parameters: * @arg RADIO_SWITCH_OFF * @arg RADIO_SWITCH_RX * @arg RADIO_SWITCH_RFO_LP * @arg RADIO_SWITCH_RFO_HP * @retval BSP status */ int32_t BSP_RADIO_ConfigRFSwitch(BSP_RADIO_Switch_TypeDef Config) { switch (Config) { case RADIO_SWITCH_OFF: { /* Turn off switch */ HAL_GPIO_WritePin(RF_SW_CTRL3_GPIO_PORT, RF_SW_CTRL3_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_PORT, RF_SW_CTRL1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_PORT, RF_SW_CTRL2_PIN, GPIO_PIN_RESET); break; } case RADIO_SWITCH_RX: { /*Turns On in Rx Mode the RF Switch */ HAL_GPIO_WritePin(RF_SW_CTRL3_GPIO_PORT, RF_SW_CTRL3_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_PORT, RF_SW_CTRL1_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_PORT, RF_SW_CTRL2_PIN, GPIO_PIN_RESET); break; } case RADIO_SWITCH_RFO_LP: { /*Turns On in Tx Low Power the RF Switch */ HAL_GPIO_WritePin(RF_SW_CTRL3_GPIO_PORT, RF_SW_CTRL3_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_PORT, RF_SW_CTRL1_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_PORT, RF_SW_CTRL2_PIN, GPIO_PIN_SET); break; } case RADIO_SWITCH_RFO_HP: { /*Turns On in Tx High Power the RF Switch */ HAL_GPIO_WritePin(RF_SW_CTRL3_GPIO_PORT, RF_SW_CTRL3_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_PORT, RF_SW_CTRL1_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_PORT, RF_SW_CTRL2_PIN, GPIO_PIN_SET); break; } default: break; } return BSP_ERROR_NONE; }




































ChirpStack -Revision Mac 1.0.3

Testando o APP endNode

main.c

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2021 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "i2c.h" #include "app_lorawan.h" #include "tim.h" #include "gpio.h" #include "aplicacao.h" //#include "LinearAlgebra/declareFunctions.h" //#include "declareFunctions.h" #include "sys_app.h" #include "app_version.h" #include "stm32_lpm.h" //Include para a função "UTIL_LPM_EnterLowPower()" (Tiago) #include "utilities_conf.h" #include "stm32_lpm_if.h" //Include para a Função "PWR_EnterSleepMode()" (Tiago) #include "app_lorawan.h" #include "lora_app.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ static void OnUserTimerEvent(void *context); static UTIL_TIMER_Object_t UserTimer; /* USER CODE END Includes */ extern void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin); /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ struct ST_TIME St_Timer; uint8_t tx_buffer[TX_BUF_DIM]; unsigned char temp_ok=0; unsigned char join=0; unsigned char trava_envio=0; unsigned int cont_wakeup=0; unsigned int cont_tempo_uplink=0; unsigned int tempo_uplink=300; extern unsigned char movimento_uplink; /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ extern UART_HandleTypeDef huart2; /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); extern void Func_Mag_Power_Down (void); extern void Algoritimo (void); extern void SendTxData(void); unsigned char Maq_Est_Status_Join=0; /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ LmHandlerAppData_t appData2 = { .Buffer = "10", .BufferSize = 5, .Port = 0 }; /** * @brief The application entry point. * @retval int */ int main(void) { /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ //MX_LoRaWAN_Init(); SystemApp_Init(); //Tiago: Aqui inicia o Hall MX_GPIO_Init(); MX_I2C1_Init(); MX_TIM16_Init(); HAL_TIM_Base_Start_IT(&htim16); /* Infinite loop */ /* USER CODE BEGIN WHILE */ uint8_t RxTx_1[100]; uint8_t recebe; //HAL_UART_Receive_IT(&huart2, myRxData, 1); HAL_UART_DeInit(&huart2); while (1) { if(DEF_BOTAO_OPEN == DEF_ON) //Botão para solicitar a conexão (join) { Maq_Est_Status_Join = DEF_INICIA_CONEXAO; join=0; } switch (Maq_Est_Status_Join) { case DEF_INICIA_CONEXAO: LoRaWAN_Init(); Maq_Est_Status_Join = DEF_PROCESSO_LORAWAN; break; case DEF_PROCESSO_LORAWAN: MX_LoRaWAN_Process(); break; case DEF_FINALIZA_PROCESSO: movimento_uplink=DEF_UPLINK_ON; MX_LoRaWAN_Process(); Maq_Est_Status_Join = DEF_RESET; break; } if(join==1) //Definido em "OnJoinRequest" em lora_app.c { Wakeup_Long_Timer(1000); //Aqui eu defino o tempo para acordar MX_LoRaWAN_Process(); cont_tempo_uplink++; if(cont_tempo_uplink == tempo_uplink) //tempo_uplink = 300 (equivale a 30 segundos) { cont_tempo_uplink=0; DEF_LED_BLUE_CONF_ON; HAL_Delay(1000); DEF_LED_BLUE_CONF_OFF; movimento_uplink=DEF_UPLINK_ON; MX_LoRaWAN_Process(); } } } } void Func_Modo_Sleep (int tempo_sleep) { /*Create a UserTimer toggling every 5 seconds*/ UTIL_TIMER_Create(&UserTimer, tempo_sleep, UTIL_TIMER_PERIODIC, OnUserTimerEvent, NULL); /* Starts UserTimer*/ UTIL_TIMER_Start(&UserTimer); cont_wakeup++; //UTIL_LPM_EnterLowPower(); //Entra em modo Low Power (Tiago) } static void OnUserTimerEvent(void *context) { if(cont_wakeup==1) { DEF_LED_ORANGE_CLOSED_BLINK; cont_wakeup=0; } //if(DEF_BOTAO_OPEN == DEF_ON) //{ //BSP_LED_Toggle(DEF_LED_BLUE_CONF_ON) ; //DEF_LED_BLUE_CONF_BLINK; //} } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure LSE Drive Capability */ HAL_PWR_EnableBkUpAccess(); __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); /** Configure the main internal regulator output voltage */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the CPU, AHB and APB buses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;//RCC_MSIRANGE_8 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK |RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1 |RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; // RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV10;//DIV10 = 4,8MHz //RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV16; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim16) { //HAL_GPIO_TogglePin(DEF_LED_BLUE_GPIO_Port, DEF_LED_BLUE); if(St_Timer.t_200ms)St_Timer.t_200ms--; if(St_Timer.t_1s)St_Timer.t_1s--; if(St_Timer.t_3s)St_Timer.t_3s--; if(St_Timer.t_5s)St_Timer.t_5s--; if(St_Timer.t_6s)St_Timer.t_6s--; if(St_Timer.t_10s)St_Timer.t_10s--; if(St_Timer.t_out)St_Timer.t_out--; } } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ while (1) { } /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */

lora_app.c

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file lora_app.c * @author MCD Application Team * @brief Application of the LRWAN Middleware ****************************************************************************** * @attention * * Copyright (c) 2021 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "platform.h" #include "sys_app.h" #include "lora_app.h" #include "stm32_seq.h" #include "stm32_timer.h" #include "utilities_def.h" #include "app_version.h" #include "lorawan_version.h" #include "subghz_phy_version.h" #include "lora_info.h" #include "LmHandler.h" #include "adc_if.h" #include "CayenneLpp.h" #include "sys_sensors.h" #include "flash_if.h" #include "aplicacao.h" #include <stdio.h> unsigned char movimento_uplink=0; extern UART_HandleTypeDef huart2; extern char tx_buffer [100]; extern unsigned char join; extern unsigned int nivel_bateria; extern long alarme_posicao; extern unsigned char Get_Bat(void); extern uint8_t Get_Alarms (unsigned char Val); extern union UN_ALM un_ALM; extern union UN_DOWNLINK un_DOWNLINK; extern void Sinaliza_Joined(void); extern unsigned char Maq_Est_Status_Join; extern unsigned char status_monitor; extern unsigned char trava_send_uplink; extern unsigned char monitor_alarme; extern unsigned char histerese_alarme; extern unsigned int tempo_acorda; extern float valor_porcento_anterior; extern float valor_porcento; uint8_t temperatura_celcius; /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* External variables ---------------------------------------------------------*/ /* USER CODE BEGIN EV */ /* USER CODE END EV */ /* Private typedef -----------------------------------------------------------*/ /** * @brief LoRa State Machine states */ typedef enum TxEventType_e { /** * @brief Appdata Transmission issue based on timer every TxDutyCycleTime */ TX_ON_TIMER, /** * @brief Appdata Transmission external event plugged on OnSendEvent( ) */ TX_ON_EVENT /* USER CODE BEGIN TxEventType_t */ /* USER CODE END TxEventType_t */ } TxEventType_t; /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /** * LEDs period value of the timer in ms */ #define LED_PERIOD_TIME 500 /** * Join switch period value of the timer in ms */ #define JOIN_TIME 2000 /*---------------------------------------------------------------------------*/ /* LoRaWAN NVM configuration */ /*---------------------------------------------------------------------------*/ /** * @brief LoRaWAN NVM Flash address * @note last 2 sector of a 128kBytes device */ #define LORAWAN_NVM_BASE_ADDRESS ((void *)0x0803F000UL) /* USER CODE BEGIN PD */ static const char *slotStrings[] = { "1", "2", "C", "C_MC", "P", "P_MC" }; /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private function prototypes -----------------------------------------------*/ /** * @brief LoRa End Node send request */ static void SendTxData(void); /** * @brief TX timer callback function * @param context ptr of timer context */ static void OnTxTimerEvent(void *context); /** * @brief join event callback function * @param joinParams status of join */ static void OnJoinRequest(LmHandlerJoinParams_t *joinParams); /** * @brief callback when LoRaWAN application has sent a frame * @brief tx event callback function * @param params status of last Tx */ static void OnTxData(LmHandlerTxParams_t *params); /** * @brief callback when LoRaWAN application has received a frame * @param appData data received in the last Rx * @param params status of last Rx */ static void OnRxData(LmHandlerAppData_t *appData, LmHandlerRxParams_t *params); /** * @brief callback when LoRaWAN Beacon status is updated * @param params status of Last Beacon */ static void OnBeaconStatusChange(LmHandlerBeaconParams_t *params); /** * @brief callback when system time has been updated */ static void OnSysTimeUpdate(void); /** * @brief callback when LoRaWAN application Class is changed * @param deviceClass new class */ static void OnClassChange(DeviceClass_t deviceClass); /** * @brief LoRa store context in Non Volatile Memory */ static void StoreContext(void); /** * @brief stop current LoRa execution to switch into non default Activation mode */ static void StopJoin(void); /** * @brief Join switch timer callback function * @param context ptr of Join switch context */ static void OnStopJoinTimerEvent(void *context); /** * @brief Notifies the upper layer that the NVM context has changed * @param state Indicates if we are storing (true) or restoring (false) the NVM context */ static void OnNvmDataChange(LmHandlerNvmContextStates_t state); /** * @brief Store the NVM Data context to the Flash * @param nvm ptr on nvm structure * @param nvm_size number of data bytes which were stored */ static void OnStoreContextRequest(void *nvm, uint32_t nvm_size); /** * @brief Restore the NVM Data context from the Flash * @param nvm ptr on nvm structure * @param nvm_size number of data bytes which were restored */ static void OnRestoreContextRequest(void *nvm, uint32_t nvm_size); /** * Will be called each time a Radio IRQ is handled by the MAC layer * */ static void OnMacProcessNotify(void); /** * @brief Change the periodicity of the uplink frames * @param periodicity uplink frames period in ms * @note Compliance test protocol callbacks */ static void OnTxPeriodicityChanged(uint32_t periodicity); /** * @brief Change the confirmation control of the uplink frames * @param isTxConfirmed Indicates if the uplink requires an acknowledgement * @note Compliance test protocol callbacks */ static void OnTxFrameCtrlChanged(LmHandlerMsgTypes_t isTxConfirmed); /** * @brief Change the periodicity of the ping slot frames * @param pingSlotPeriodicity ping slot frames period in ms * @note Compliance test protocol callbacks */ static void OnPingSlotPeriodicityChanged(uint8_t pingSlotPeriodicity); /** * @brief Will be called to reset the system * @note Compliance test protocol callbacks */ static void OnSystemReset(void); /* USER CODE BEGIN PFP */ /** * @brief LED Tx timer callback function * @param context ptr of LED context */ static void OnTxTimerLedEvent(void *context); /** * @brief LED Rx timer callback function * @param context ptr of LED context */ static void OnRxTimerLedEvent(void *context); /** * @brief LED Join timer callback function * @param context ptr of LED context */ static void OnJoinTimerLedEvent(void *context); /* USER CODE END PFP */ /* Private variables ---------------------------------------------------------*/ /** * @brief LoRaWAN default activation type */ static ActivationType_t ActivationType = LORAWAN_DEFAULT_ACTIVATION_TYPE; /** * @brief LoRaWAN force rejoin even if the NVM context is restored */ static bool ForceRejoin = LORAWAN_FORCE_REJOIN_AT_BOOT; /** * @brief LoRaWAN handler Callbacks */ static LmHandlerCallbacks_t LmHandlerCallbacks = { .GetBatteryLevel = GetBatteryLevel, .GetTemperature = GetTemperatureLevel, .GetUniqueId = GetUniqueId, .GetDevAddr = GetDevAddr, .OnRestoreContextRequest = OnRestoreContextRequest, .OnStoreContextRequest = OnStoreContextRequest, .OnMacProcess = OnMacProcessNotify, .OnNvmDataChange = OnNvmDataChange, .OnJoinRequest = OnJoinRequest, .OnTxData = OnTxData, .OnRxData = OnRxData, .OnBeaconStatusChange = OnBeaconStatusChange, .OnSysTimeUpdate = OnSysTimeUpdate, .OnClassChange = OnClassChange, .OnTxPeriodicityChanged = OnTxPeriodicityChanged, .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, .OnSystemReset = OnSystemReset, }; /** * @brief LoRaWAN handler parameters */ static LmHandlerParams_t LmHandlerParams = { .ActiveRegion = ACTIVE_REGION, .DefaultClass = LORAWAN_DEFAULT_CLASS, .AdrEnable = LORAWAN_ADR_STATE, .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, .TxDatarate = LORAWAN_DEFAULT_DATA_RATE, .TxPower = LORAWAN_DEFAULT_TX_POWER, .PingSlotPeriodicity = LORAWAN_DEFAULT_PING_SLOT_PERIODICITY, .RxBCTimeout = LORAWAN_DEFAULT_CLASS_B_C_RESP_TIMEOUT }; /** * @brief Type of Event to generate application Tx */ static TxEventType_t EventType = TX_ON_TIMER; /** * @brief Timer to handle the application Tx */ static UTIL_TIMER_Object_t TxTimer; /** * @brief Tx Timer period */ static UTIL_TIMER_Time_t TxPeriodicity = APP_TX_DUTYCYCLE; /** * @brief Join Timer period */ static UTIL_TIMER_Object_t StopJoinTimer; /* USER CODE BEGIN PV */ /** * @brief User application buffer */ static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; /** * @brief User application data structure */ static LmHandlerAppData_t AppData = { 0, 0, AppDataBuffer }; /** * @brief Specifies the state of the application LED */ static uint8_t AppLedStateOn = RESET; /** * @brief Timer to handle the application Tx Led to toggle */ static UTIL_TIMER_Object_t TxLedTimer; /** * @brief Timer to handle the application Rx Led to toggle */ static UTIL_TIMER_Object_t RxLedTimer; /** * @brief Timer to handle the application Join Led to toggle */ static UTIL_TIMER_Object_t JoinLedTimer; /* USER CODE END PV */ /* Exported functions ---------------------------------------------------------*/ /* USER CODE BEGIN EF */ /* USER CODE END EF */ void LoRaWAN_Init(void) { /* USER CODE BEGIN LoRaWAN_Init_LV */ uint32_t feature_version = 0UL; /* USER CODE END LoRaWAN_Init_LV */ /* USER CODE BEGIN LoRaWAN_Init_1 */ /* Get LoRaWAN APP version*/ APP_LOG(TS_OFF, VLEVEL_M, "APPLICATION_VERSION: V%X.%X.%X\r\n", (uint8_t)(APP_VERSION_MAIN), (uint8_t)(APP_VERSION_SUB1), (uint8_t)(APP_VERSION_SUB2)); /* Get MW LoRaWAN info */ APP_LOG(TS_OFF, VLEVEL_M, "MW_LORAWAN_VERSION: V%X.%X.%X\r\n", (uint8_t)(LORAWAN_VERSION_MAIN), (uint8_t)(LORAWAN_VERSION_SUB1), (uint8_t)(LORAWAN_VERSION_SUB2)); /* Get MW SubGhz_Phy info */ APP_LOG(TS_OFF, VLEVEL_M, "MW_RADIO_VERSION: V%X.%X.%X\r\n", (uint8_t)(SUBGHZ_PHY_VERSION_MAIN), (uint8_t)(SUBGHZ_PHY_VERSION_SUB1), (uint8_t)(SUBGHZ_PHY_VERSION_SUB2)); /* Get LoRaWAN Link Layer info */ LmHandlerGetVersion(LORAMAC_HANDLER_L2_VERSION, &feature_version); APP_LOG(TS_OFF, VLEVEL_M, "L2_SPEC_VERSION: V%X.%X.%X\r\n", (uint8_t)(feature_version >> 24), (uint8_t)(feature_version >> 16), (uint8_t)(feature_version >> 8)); /* Get LoRaWAN Regional Parameters info */ LmHandlerGetVersion(LORAMAC_HANDLER_REGION_VERSION, &feature_version); APP_LOG(TS_OFF, VLEVEL_M, "RP_SPEC_VERSION: V%X-%X.%X.%X\r\n", (uint8_t)(feature_version >> 24), (uint8_t)(feature_version >> 16), (uint8_t)(feature_version >> 8), (uint8_t)(feature_version)); UTIL_TIMER_Create(&TxLedTimer, LED_PERIOD_TIME, UTIL_TIMER_ONESHOT, OnTxTimerLedEvent, NULL); UTIL_TIMER_Create(&RxLedTimer, LED_PERIOD_TIME, UTIL_TIMER_ONESHOT, OnRxTimerLedEvent, NULL); UTIL_TIMER_Create(&JoinLedTimer, LED_PERIOD_TIME, UTIL_TIMER_PERIODIC, OnJoinTimerLedEvent, NULL); if (FLASH_IF_Init(NULL) != FLASH_IF_OK) { Error_Handler(); } /* USER CODE END LoRaWAN_Init_1 */ UTIL_TIMER_Create(&StopJoinTimer, JOIN_TIME, UTIL_TIMER_ONESHOT, OnStopJoinTimerEvent, NULL); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_LmHandlerProcess), UTIL_SEQ_RFU, LmHandlerProcess); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), UTIL_SEQ_RFU, SendTxData); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_LoRaStoreContextEvent), UTIL_SEQ_RFU, StoreContext); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_LoRaStopJoinEvent), UTIL_SEQ_RFU, StopJoin); /* Init Info table used by LmHandler*/ LoraInfo_Init(); /* Init the Lora Stack*/ LmHandlerInit(&LmHandlerCallbacks, APP_VERSION); LmHandlerConfigure(&LmHandlerParams); /* USER CODE BEGIN LoRaWAN_Init_2 */ UTIL_TIMER_Start(&JoinLedTimer); /* USER CODE END LoRaWAN_Init_2 */ LmHandlerJoin(ActivationType, ForceRejoin); if (EventType == TX_ON_TIMER) { /* send every time timer elapses */ UTIL_TIMER_Create(&TxTimer, TxPeriodicity, UTIL_TIMER_ONESHOT, OnTxTimerEvent, NULL); UTIL_TIMER_Start(&TxTimer); } else { /* USER CODE BEGIN LoRaWAN_Init_3 */ /* USER CODE END LoRaWAN_Init_3 */ } /* USER CODE BEGIN LoRaWAN_Init_Last */ /* USER CODE END LoRaWAN_Init_Last */ } /* USER CODE BEGIN PB_Callbacks */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { switch (GPIO_Pin) { case BUT1_Pin: //Note: when "EventType == TX_ON_TIMER" this GPIO is not initialized if (EventType == TX_ON_EVENT) { UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } break; case BUT2_Pin: if (EventType == TX_ON_EVENT) { UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } break; case BUT3_Pin: UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStoreContextEvent), CFG_SEQ_Prio_0); break; default: break; } } /* USER CODE END PB_Callbacks */ /* Private functions ---------------------------------------------------------*/ /* USER CODE BEGIN PrFD */ /* USER CODE END PrFD */ static void OnRxData(LmHandlerAppData_t *appData, LmHandlerRxParams_t *params) { /* USER CODE BEGIN OnRxData_1 */ uint8_t RxPort = 0; if (params != NULL) { HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); /* LED_BLUE */ //DEF_LED_RED_ALARM_ON; UTIL_TIMER_Start(&RxLedTimer); if (params->IsMcpsIndication) { if (appData != NULL) { RxPort = appData->Port; if (appData->Buffer != NULL) { switch (appData->Port) { case LORAWAN_SWITCH_CLASS_PORT: /*this port switches the class*/ if (appData->BufferSize == 1) { switch (appData->Buffer[0]) { case 0: { LmHandlerRequestClass(CLASS_A); break; } case 1: { LmHandlerRequestClass(CLASS_B); break; } case 2: { LmHandlerRequestClass(CLASS_C); break; } default: break; } } break; case LORAWAN_USER_APP_PORT: if (appData->BufferSize == 1) { } break; default: break; } } } } if (params->RxSlot < RX_SLOT_NONE) { APP_LOG(TS_OFF, VLEVEL_H, "###### D/L FRAME:%04d | PORT:%d | DR:%d | SLOT:%s | RSSI:%d | SNR:%d\r\n", params->DownlinkCounter, RxPort, params->Datarate, slotStrings[params->RxSlot], params->Rssi, params->Snr); } } } static void SendTxData(void) { uint16_t bateria; if(movimento_uplink==1) //Tiago: Criei essa função para enviar dados somente quando necessário { movimento_uplink=0; LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; uint8_t batteryLevel = GetBatteryLevel(); sensor_t sensor_data; UTIL_TIMER_Time_t nextTxIn = 0; if (LmHandlerIsBusy() == false) { #ifdef CAYENNE_LPP uint8_t channel = 0; #else uint16_t pressure = 0; int16_t temperature = 0; uint16_t humidity = 0; uint32_t i = 0; int32_t latitude = 0; int32_t longitude = 0; uint16_t altitudeGps = 0; #endif /* CAYENNE_LPP */ EnvSensors_Read(&sensor_data); APP_LOG(TS_ON, VLEVEL_M, "VDDA: %d\r\n", batteryLevel); APP_LOG(TS_ON, VLEVEL_M, "temp: %d\r\n", (int16_t)(sensor_data.temperature)); AppData.Port = LORAWAN_USER_APP_PORT; #ifdef CAYENNE_LPP CayenneLppReset(); CayenneLppAddBarometricPressure(channel++, sensor_data.pressure); CayenneLppAddTemperature(channel++, sensor_data.temperature); CayenneLppAddRelativeHumidity(channel++, (uint16_t)(sensor_data.humidity)); if ((LmHandlerParams.ActiveRegion != LORAMAC_REGION_US915) && (LmHandlerParams.ActiveRegion != LORAMAC_REGION_AU915) && (LmHandlerParams.ActiveRegion != LORAMAC_REGION_AS923)) { CayenneLppAddDigitalInput(channel++, GetBatteryLevel()); CayenneLppAddDigitalOutput(channel++, AppLedStateOn); } CayenneLppCopy(AppData.Buffer); AppData.BufferSize = CayenneLppGetSize(); #else /* not CAYENNE_LPP */ humidity = (uint16_t)(sensor_data.humidity * 10); /* in %*10 */ temperature = (int16_t)(sensor_data.temperature); pressure = (uint16_t)(sensor_data.pressure * 100 / 10); /* in hPa / 10 */ //AppData.Buffer[i++] = AppLedStateOn; //AppData.Buffer[i++] = (uint8_t)((pressure >> 8) & 0xFF); //AppData.Buffer[i++] = (uint8_t)(pressure & 0xFF); //AppData.Buffer[i++] = (uint8_t)((humidity >> 8) & 0xFF); //AppData.Buffer[i++] = (uint8_t)(humidity & 0xFF); if ((LmHandlerParams.ActiveRegion == LORAMAC_REGION_US915) || (LmHandlerParams.ActiveRegion == LORAMAC_REGION_AU915) || (LmHandlerParams.ActiveRegion == LORAMAC_REGION_AS923)) { /*Tiago Fernandes (17/10/2023) Para obter um resultado exato na medição, foi utilizado uma fonte de alimentação HP ajustada em 3,67Vdc e 2,50Vdc. Com a fonte ajustara em 2,50Vdc a função GetBatteryLevel() enviou para o servidor TTN o valor 90 Com a fonte ajustara em 3,67Vdc a função GetBatteryLevel() enviou para o servidor TTN o valor 254 Com base nesses resultados, foi calculada a equação da reta abaixo NOTA: Foi verificado que o módulo não consegue fazer uplink com a tensão ajustada abaixo de 2,50Vdc*/ //********************TEMPERATURA******************** AppData.Buffer[i++] = (uint8_t)(temperature & 0xFF); temperatura_celcius = (uint8_t)(temperature & 0xFF); //*******************************PONTO FECHADO************************************* //*******************************PONTO FECHADO************************************* //*******************************PONTO FECHADO************************************* /* if(valor_porcento_anterior>=-histerese_alarme && valor_porcento_anterior<=histerese_alarme) { //********************BATERIA******************** //AppData.Buffer[i++] = Get_Bat(); //********************TEMPERATURA******************** AppData.Buffer[i++] = (uint8_t)(temperature & 0xFF); temperatura_celcius = (uint8_t)(temperature & 0xFF); //********************POSIÇÃO******************** AppData.Buffer[i++] = (int)(0); //********************ALARMES******************** //AppData.Buffer[i++] = (uint8_t)(un_ALM.Int); //AppData.Buffer[i++] = Get_Alarms(Get_Bat()); }*/ //*******************************PONTO ABERTO************************************* //*******************************PONTO ABERTO************************************* //*******************************PONTO ABERTO************************************* /* else if(valor_porcento_anterior>=(100-histerese_alarme) && valor_porcento_anterior<=(100+histerese_alarme)) { //********************BATERIA******************** //AppData.Buffer[i++] = Get_Bat(); //********************TEMPERATURA******************** AppData.Buffer[i++] = (uint8_t)(temperature & 0xFF); temperatura_celcius = (uint8_t)(temperature & 0xFF); //********************POSIÇÃO******************** AppData.Buffer[i++] = (int)(100); //********************ALARME******************** //AppData.Buffer[i++] = Get_Alarms(Get_Bat()); }*/ /* else { //********************BATERIA******************** //AppData.Buffer[i++] = Get_Bat(); //********************TEMPERATURA******************** AppData.Buffer[i++] = (uint8_t)(temperature & 0xFF); temperatura_celcius = (uint8_t)(temperature & 0xFF); //********************POSIÇÃO******************** //AppData.Buffer[i++] = (int)(valor_porcento); //********************ALARME******************** //AppData.Buffer[i++] = Get_Alarms(Get_Bat()); }*/ //trava_send_uplink=1; HAL_Delay(3000); //Coloquei esse delay para dar tempo de fazer a transmissão uplink para o servidor, antes que ocorra um novo pedido de transmissão } else { latitude = sensor_data.latitude; longitude = sensor_data.longitude; //AppData.Buffer[i++] = GetBatteryLevel(); /* 1 (very low) to 254 (fully charged) */ AppData.Buffer[i++] = (uint8_t)((latitude >> 16) & 0xFF); AppData.Buffer[i++] = (uint8_t)((latitude >> 8) & 0xFF); AppData.Buffer[i++] = (uint8_t)(latitude & 0xFF); AppData.Buffer[i++] = (uint8_t)((longitude >> 16) & 0xFF); AppData.Buffer[i++] = (uint8_t)((longitude >> 8) & 0xFF); AppData.Buffer[i++] = (uint8_t)(longitude & 0xFF); AppData.Buffer[i++] = (uint8_t)((altitudeGps >> 8) & 0xFF); AppData.Buffer[i++] = (uint8_t)(altitudeGps & 0xFF); } AppData.BufferSize = i; #endif /* CAYENNE_LPP */ if ((JoinLedTimer.IsRunning) && (LmHandlerJoinStatus() == LORAMAC_HANDLER_SET)) { UTIL_TIMER_Stop(&JoinLedTimer); HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */ } status = LmHandlerSend(&AppData, LmHandlerParams.IsTxConfirmed, false); if (LORAMAC_HANDLER_SUCCESS == status) { APP_LOG(TS_ON, VLEVEL_L, "SEND REQUEST\r\n"); } else if (LORAMAC_HANDLER_DUTYCYCLE_RESTRICTED == status) { nextTxIn = LmHandlerGetDutyCycleWaitTime(); if (nextTxIn > 0) { APP_LOG(TS_ON, VLEVEL_L, "Next Tx in : ~%d second(s)\r\n", (nextTxIn / 1000)); } } } if (EventType == TX_ON_TIMER) { UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, MAX(nextTxIn, TxPeriodicity)); UTIL_TIMER_Start(&TxTimer); } } /* USER CODE END SendTxData_1 */ } static void OnTxTimerEvent(void *context) { /* USER CODE BEGIN OnTxTimerEvent_1 */ /* USER CODE END OnTxTimerEvent_1 */ UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); /*Wait for next tx slot*/ UTIL_TIMER_Start(&TxTimer); /* USER CODE BEGIN OnTxTimerEvent_2 */ /* USER CODE END OnTxTimerEvent_2 */ } /* USER CODE BEGIN PrFD_LedEvents */ static void OnTxTimerLedEvent(void *context) { HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); /* LED_GREEN */ } static void OnRxTimerLedEvent(void *context) { HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); /* LED_BLUE */ } static void OnJoinTimerLedEvent(void *context) { HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin); /* LED_RED */ } /* USER CODE END PrFD_LedEvents */ static void OnTxData(LmHandlerTxParams_t *params) { /* USER CODE BEGIN OnTxData_1 */ if ((params != NULL)) { /* Process Tx event only if its a mcps response to prevent some internal events (mlme) */ if (params->IsMcpsConfirm != 0) { HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); /* LED_GREEN */ UTIL_TIMER_Start(&TxLedTimer); APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### ========== MCPS-Confirm =============\r\n"); APP_LOG(TS_OFF, VLEVEL_H, "###### U/L FRAME:%04d | PORT:%d | DR:%d | PWR:%d", params->UplinkCounter, params->AppData.Port, params->Datarate, params->TxPower); APP_LOG(TS_OFF, VLEVEL_H, " | MSG TYPE:"); if (params->MsgType == LORAMAC_HANDLER_CONFIRMED_MSG) { APP_LOG(TS_OFF, VLEVEL_H, "CONFIRMED [%s]\r\n", (params->AckReceived != 0) ? "ACK" : "NACK"); } else { APP_LOG(TS_OFF, VLEVEL_H, "UNCONFIRMED\r\n"); } } } /* USER CODE END OnTxData_1 */ } static void OnJoinRequest(LmHandlerJoinParams_t *joinParams) { /* USER CODE BEGIN OnJoinRequest_1 */ if (joinParams != NULL) { if (joinParams->Status == LORAMAC_HANDLER_SUCCESS) { UTIL_TIMER_Stop(&JoinLedTimer); HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */ APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### = JOINED = "); if (joinParams->Mode == ACTIVATION_TYPE_ABP) { APP_LOG(TS_OFF, VLEVEL_M, "ABP ======================\r\n"); } else { APP_LOG(TS_OFF, VLEVEL_M, "OTAA =====================\r\n"); //Sinaliza_Joined (); Maq_Est_Status_Join = DEF_FINALIZA_PROCESSO; DEF_LED_BLUE_CONF_ON; HAL_Delay(1000); DEF_LED_BLUE_CONF_OFF; join = 1; } } else { APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### = JOIN FAILED\r\n"); //Sinaliza_Join_Failed (); //status_monitor = DEF_DORMINDO; Maq_Est_Status_Join = DEF_RESET; //Func_Reset_Fabrica(); DEF_LED_RED_ALARM_ON; HAL_Delay(1000); DEF_LED_RED_ALARM_OFF; join = 0; } APP_LOG(TS_OFF, VLEVEL_H, "###### U/L FRAME:JOIN | DR:%d | PWR:%d\r\n", joinParams->Datarate, joinParams->TxPower); } /* USER CODE END OnJoinRequest_1 */ } static void OnBeaconStatusChange(LmHandlerBeaconParams_t *params) { /* USER CODE BEGIN OnBeaconStatusChange_1 */ if (params != NULL) { switch (params->State) { default: case LORAMAC_HANDLER_BEACON_LOST: { APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### BEACON LOST\r\n"); break; } case LORAMAC_HANDLER_BEACON_RX: { APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### BEACON RECEIVED | DR:%d | RSSI:%d | SNR:%d | FQ:%d | TIME:%d | DESC:%d | " "INFO:02X%02X%02X %02X%02X%02X\r\n", params->Info.Datarate, params->Info.Rssi, params->Info.Snr, params->Info.Frequency, params->Info.Time.Seconds, params->Info.GwSpecific.InfoDesc, params->Info.GwSpecific.Info[0], params->Info.GwSpecific.Info[1], params->Info.GwSpecific.Info[2], params->Info.GwSpecific.Info[3], params->Info.GwSpecific.Info[4], params->Info.GwSpecific.Info[5]); break; } case LORAMAC_HANDLER_BEACON_NRX: { APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### BEACON NOT RECEIVED\r\n"); break; } } } /* USER CODE END OnBeaconStatusChange_1 */ } static void OnSysTimeUpdate(void) { /* USER CODE BEGIN OnSysTimeUpdate_1 */ /* USER CODE END OnSysTimeUpdate_1 */ } static void OnClassChange(DeviceClass_t deviceClass) { /* USER CODE BEGIN OnClassChange_1 */ APP_LOG(TS_OFF, VLEVEL_M, "Switch to Class %c done\r\n", "ABC"[deviceClass]); /* USER CODE END OnClassChange_1 */ } static void OnMacProcessNotify(void) { /* USER CODE BEGIN OnMacProcessNotify_1 */ /* USER CODE END OnMacProcessNotify_1 */ UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LmHandlerProcess), CFG_SEQ_Prio_0); /* USER CODE BEGIN OnMacProcessNotify_2 */ /* USER CODE END OnMacProcessNotify_2 */ } static void OnTxPeriodicityChanged(uint32_t periodicity) { /* USER CODE BEGIN OnTxPeriodicityChanged_1 */ /* USER CODE END OnTxPeriodicityChanged_1 */ TxPeriodicity = periodicity; if (TxPeriodicity == 0) { /* Revert to application default periodicity */ TxPeriodicity = APP_TX_DUTYCYCLE; } /* Update timer periodicity */ UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, TxPeriodicity); UTIL_TIMER_Start(&TxTimer); /* USER CODE BEGIN OnTxPeriodicityChanged_2 */ /* USER CODE END OnTxPeriodicityChanged_2 */ } void Wakeup_Long_Timer(uint32_t periodicity) { /* USER CODE BEGIN OnTxPeriodicityChanged_1 */ /* USER CODE END OnTxPeriodicityChanged_1 */ //TxPeriodicity = periodicity*1000; TxPeriodicity = periodicity; if (TxPeriodicity == 0) { /* Revert to application default periodicity */ //TxPeriodicity = periodicity*1000; TxPeriodicity = periodicity; } /* Update timer periodicity */ UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, TxPeriodicity); UTIL_TIMER_Start(&TxTimer); /* USER CODE BEGIN OnTxPeriodicityChanged_2 */ /* USER CODE END OnTxPeriodicityChanged_2 */ } void Wakeup_Short_Timer(uint32_t periodicity) { /* USER CODE BEGIN OnTxPeriodicityChanged_1 */ /* USER CODE END OnTxPeriodicityChanged_1 */ TxPeriodicity = periodicity*1000; if (TxPeriodicity == 0) { /* Revert to application default periodicity */ TxPeriodicity = periodicity*1000; } /* Update timer periodicity */ UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, TxPeriodicity); UTIL_TIMER_Start(&TxTimer); /* USER CODE BEGIN OnTxPeriodicityChanged_2 */ /* USER CODE END OnTxPeriodicityChanged_2 */ } static void OnTxFrameCtrlChanged(LmHandlerMsgTypes_t isTxConfirmed) { /* USER CODE BEGIN OnTxFrameCtrlChanged_1 */ /* USER CODE END OnTxFrameCtrlChanged_1 */ LmHandlerParams.IsTxConfirmed = isTxConfirmed; /* USER CODE BEGIN OnTxFrameCtrlChanged_2 */ /* USER CODE END OnTxFrameCtrlChanged_2 */ } static void OnPingSlotPeriodicityChanged(uint8_t pingSlotPeriodicity) { /* USER CODE BEGIN OnPingSlotPeriodicityChanged_1 */ /* USER CODE END OnPingSlotPeriodicityChanged_1 */ LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; /* USER CODE BEGIN OnPingSlotPeriodicityChanged_2 */ /* USER CODE END OnPingSlotPeriodicityChanged_2 */ } static void OnSystemReset(void) { /* USER CODE BEGIN OnSystemReset_1 */ /* USER CODE END OnSystemReset_1 */ if ((LORAMAC_HANDLER_SUCCESS == LmHandlerHalt()) && (LmHandlerJoinStatus() == LORAMAC_HANDLER_SET)) { NVIC_SystemReset(); } /* USER CODE BEGIN OnSystemReset_Last */ /* USER CODE END OnSystemReset_Last */ } static void StopJoin(void) { /* USER CODE BEGIN StopJoin_1 */ HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); /* LED_BLUE */ HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); /* LED_GREEN */ HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET); /* LED_RED */ /* USER CODE END StopJoin_1 */ UTIL_TIMER_Stop(&TxTimer); if (LORAMAC_HANDLER_SUCCESS != LmHandlerStop()) { APP_LOG(TS_OFF, VLEVEL_M, "LmHandler Stop on going ...\r\n"); } else { APP_LOG(TS_OFF, VLEVEL_M, "LmHandler Stopped\r\n"); if (LORAWAN_DEFAULT_ACTIVATION_TYPE == ACTIVATION_TYPE_ABP) { ActivationType = ACTIVATION_TYPE_OTAA; APP_LOG(TS_OFF, VLEVEL_M, "LmHandler switch to OTAA mode\r\n"); } else { ActivationType = ACTIVATION_TYPE_ABP; APP_LOG(TS_OFF, VLEVEL_M, "LmHandler switch to ABP mode\r\n"); } LmHandlerConfigure(&LmHandlerParams); LmHandlerJoin(ActivationType, true); UTIL_TIMER_Start(&TxTimer); } UTIL_TIMER_Start(&StopJoinTimer); /* USER CODE BEGIN StopJoin_Last */ /* USER CODE END StopJoin_Last */ } static void OnStopJoinTimerEvent(void *context) { /* USER CODE BEGIN OnStopJoinTimerEvent_1 */ /* USER CODE END OnStopJoinTimerEvent_1 */ if (ActivationType == LORAWAN_DEFAULT_ACTIVATION_TYPE) { UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStopJoinEvent), CFG_SEQ_Prio_0); } /* USER CODE BEGIN OnStopJoinTimerEvent_Last */ HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); /* LED_BLUE */ HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); /* LED_GREEN */ HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */ /* USER CODE END OnStopJoinTimerEvent_Last */ } static void StoreContext(void) { LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; /* USER CODE BEGIN StoreContext_1 */ /* USER CODE END StoreContext_1 */ status = LmHandlerNvmDataStore(); if (status == LORAMAC_HANDLER_NVM_DATA_UP_TO_DATE) { APP_LOG(TS_OFF, VLEVEL_M, "NVM DATA UP TO DATE\r\n"); } else if (status == LORAMAC_HANDLER_ERROR) { APP_LOG(TS_OFF, VLEVEL_M, "NVM DATA STORE FAILED\r\n"); } /* USER CODE BEGIN StoreContext_Last */ /* USER CODE END StoreContext_Last */ } static void OnNvmDataChange(LmHandlerNvmContextStates_t state) { /* USER CODE BEGIN OnNvmDataChange_1 */ /* USER CODE END OnNvmDataChange_1 */ if (state == LORAMAC_HANDLER_NVM_STORE) { APP_LOG(TS_OFF, VLEVEL_M, "NVM DATA STORED\r\n"); } else { APP_LOG(TS_OFF, VLEVEL_M, "NVM DATA RESTORED\r\n"); } /* USER CODE BEGIN OnNvmDataChange_Last */ /* USER CODE END OnNvmDataChange_Last */ } static void OnStoreContextRequest(void *nvm, uint32_t nvm_size) { /* USER CODE BEGIN OnStoreContextRequest_1 */ /* USER CODE END OnStoreContextRequest_1 */ /* store nvm in flash */ if (FLASH_IF_Erase(LORAWAN_NVM_BASE_ADDRESS, FLASH_PAGE_SIZE) == FLASH_IF_OK) { FLASH_IF_Write(LORAWAN_NVM_BASE_ADDRESS, (const void *)nvm, nvm_size); } /* USER CODE BEGIN OnStoreContextRequest_Last */ /* USER CODE END OnStoreContextRequest_Last */ } static void OnRestoreContextRequest(void *nvm, uint32_t nvm_size) { /* USER CODE BEGIN OnRestoreContextRequest_1 */ /* USER CODE END OnRestoreContextRequest_1 */ FLASH_IF_Read(nvm, LORAWAN_NVM_BASE_ADDRESS, nvm_size); /* USER CODE BEGIN OnRestoreContextRequest_Last */ /* USER CODE END OnRestoreContextRequest_Last */ }

    Conecte o LSM110A Starter KIT na USB do computador e abra um emulador de terminal na COMM que foi criada (9600,N,8,1) e veja o que deve aparecer.

Altere credenciais de se-identity.h obtidas do CHIRPSTACK e faça o JOIN

C:\STM32CubeWL-smartcore\Projects\NUCLEO-WL55JC\Applications\LoRaWAN\LoRaWAN_End_Node\LoRaWAN\App>



#define LORAWAN_DEVICE_EUI                                9e,41,8e,12,5b,3d,ae,f7
#define LORAWAN_JOIN_EUI                                      9e,41,8e,12,5b,3d,ae,f7
#define LORAWAN_APP_KEY                                      24, 73, 80, cb, db, bf, 23, 08, 98, 38, ca, 81, 6f, af, 9e, a0
#define LORAWAN_NWK_KEY                                    24, 73, 80, cb, db, bf, 23, 08, 98, 38, ca, 81, 6f, af, 9e, a0

Com credenciais do CHIRPSTACK execute a aplicação, veja o JOIN
    

Veja os pacotes chegando no CHIRPSTACK


Gateway LoRaWAN


STM32 CUBE IDE


Agradecimentos 

Tiago Fernandes da Silva 

Dúvidas


Kit de avaliação para módulo LoRa e Sigfox Wisol Seong JI SJI LSM110A

Operação em rede pública e privada LoRaWAN  e também ponto a ponto (P2P)

Opera também em Sigfox

Alterne entre LoRa e Sigfox por comando AT, não precisa trocar o Firmware!

Permite embarcar sua aplicação


Módulo LoRa e Sigfox Wisol Seong JI SJI LSM110A

Módulo LoRa e Sigfox compacto

Escolha entre operação LoRa e Sigfox por comando "on the fly", sem precisar trocar firmware !

LoRa: para operação redes públicas e privadas LoRaWAN bem como ponto a ponto (P2P)
Sigfox: zonas RCZ2 e RCZ4 (inclui Brasil)

Caracteristicas:

- Permite embarcar a aplicação
- Dimensão: 14x15x2,8mm
- Frequência: RCZ2 Tx 902,2MHz  Rx 905,2MHz
- Potência de saida: configurável até +22dBm
- Sensibilidade:  -129dBm@LoRa(BW=500KHz, SF=12)
                  -124dBm@Sigfox(0.6Kbps)
- Tensão de operação: 1,8 - 3,6Vdc
- Interface UART 9600 8N1
- Baixo consumo
- Na operação P2P não necessita de gateway LoRaWAN

Aplicações:
- Medição individualizada de água, energia, gás
- Automação comercial, industrial residencial;
- Rede de sensores;
- Sistemas de alarme e segurança;
- Estações meteorológicas;
- Automação agrícola.
 

Referências



Sobre a SMARTCORE

A SmartCore fornece módulos para comunicação wireless, biometria, conectividade, rastreamento e automação.
Nosso portfólio inclui modem 2G/3G/4G/NB-IoT/Cat.M, satelital, módulos WiFi, Bluetooth, GNSS / GPS, Sigfox, LoRa, leitor de cartão, leitor QR code, mecanismo de impressão, mini-board PC, antena, pigtail, LCD, bateria, repetidor GPS e sensores.

Mais detalhes em www.smartcore.com.br