/* 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 "lora_app_version.h"
#include "lorawan_version.h"
#include "subghz_phy_version.h"
#include "lora_info.h"
#include "LmHandler.h"
#include "stm32_lpm.h"
#include "adc_if.h"
#include "CayenneLpp.h"
#include "sys_sensors.h"
#include "flash_if.h"

/* USER CODE BEGIN Includes */
#include "yunhorn_sts_sensors.h"
#include "yunhorn_sts_motion_sensor.h"
#include "sts_cmox_hmac_sha.h"
/* USER CODE END Includes */

/* External variables ---------------------------------------------------------*/
/* USER CODE BEGIN EV */
volatile uint8_t mems_int1_detected = 0;
volatile uint32_t periodicity_length=0;
volatile uint8_t sts_service_mask;
volatile uint32_t rfac_timer=0;
extern hmac_result_t hmac_result;
volatile uint8_t sts_work_mode =0;
volatile uint8_t sts_ac_code[YUNHORN_STS_AC_CODE_SIZE]={0x0};
volatile uint8_t heart_beat_timer=0, sts_lorawan_joined=0;
volatile sts_cfg_nvm_t sts_cfg_nvm={sts_mtmcode1,sts_mtmcode2, sts_version, sts_hardware_ver, 
0x00,'M', 0x05,'M', 0x04,0x00,0x00,0x20, 
{0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, 
 0x01,0x03,0x00,0x02, 
 {0xFF,0xFF,0xFF,0xFF,0xFF,  0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF}
};
volatile uint32_t SamplingPeriodicity = 1000; 		//unit ms
volatile uint32_t HeartBeatPeriodicity = 120000; 		//unit ms

#ifdef YUNHORN_STS_M7_ENABLED
extern volatile uint8_t sensor_data_ready;
extern volatile STS_M7_SensorDataTypeDef sts_m7_sensorData;
extern volatile uint8_t act_threshold, inact_threshold, inact_duration;
#endif
char outbuf[64]="";
/* 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 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);

/**
  * @brief  Yunhorn STS Heart Beat Periodicity Chagne function
  * @param  duration of periodicty in ms (1/1000 sec)
  */
static void OnYunhornSTSHeartBeatPeriodicityChanged(uint32_t periodicity);

/**
  * @brief  Yunhorn STS Heart Beat callback function
  * @param  context ptr of STS Sampling Check context
  */
static void OnYunhornSTSHeartBeatTimerEvent(void *context);


/**
  * @brief  Yunhorn STS Uploading Message periodically
  * @param  context ptr of context
  */
//static void OnYunhornSTSUploadingMessageEvent(void *context);

/**
  * @brief  Yunhorn RFAC Handle process
  * @param  void
  */
static void STS_YUNHORN_RFAC_HANDLE_PROCESS(void);

/* 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,
  .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,
  .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; //TX_ON_EVENT;  //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;

/**
  * @brief Timer to handle the YunHorn STS Sensor Heart Beat Process
  */
static UTIL_TIMER_Object_t YunhornSTSHeartBeatTimer;

/* 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 */
	APP_LOG(TS_OFF, VLEVEL_M, "\r\n\n\n##### YUNHORN_STS_FW:%d SWV%d HWV:%d MTM:%d.%d R:%d.%d.%d####\r\n\n\n", 
	FirmwareVersion, sts_version, sts_hardware_ver, sts_mtmcode1,sts_mtmcode2, MajorVer, MinorVer, SubMinorVer);
	APP_LOG(TS_OFF, VLEVEL_M,"\r\n\n ========================== V12 =======================\r\n");
  /* 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);

  /* 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 */
	
	
		
	UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), UTIL_SEQ_RFU, STS_MOTION_SENSOR_WakeUp_Process);
	UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP2), UTIL_SEQ_RFU, STS_SENSOR_Function_Test_Process);
	UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), UTIL_SEQ_RFU, STS_YunhornSTSEventRFAC_Process);	
	
	STS_REBOOT_CONFIG_Init();
	UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, HeartBeatPeriodicity, UTIL_TIMER_ONESHOT, OnYunhornSTSHeartBeatTimerEvent, NULL);	
  UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);
  /* USER CODE END LoRaWAN_Init_Last */
}

/* USER CODE BEGIN PB_Callbacks */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  switch (GPIO_Pin)
  {
		
#if defined(USE_STM32WLE5)		
    case  MEMS_EXTI2_Pin:
			break;
#endif		
		
#if defined(USE_STM32WL55)
			HAL_Delay(150); //for de-bouncing eliminate
			mems_int1_detected=1;
      /* Note: when "EventType == TX_ON_TIMER" this GPIO is not initialized */
      if (EventType == TX_ON_EVENT)
      {
        UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP2), CFG_SEQ_Prio_0);
				UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
				APP_LOG(TS_OFF, VLEVEL_M, "\r\n(1) Vibration Sensor EXTI Event BUT1 1 \r\n"); //YUNHORN_STS_TODO
				mems_int1_detected=0;
			}
			
      break;
#endif
		
#if defined(USE_STM32WL55)
    case  BUT3_Pin:
      UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStopJoinEvent), CFG_SEQ_Prio_0);
			//mems_int1_detected=1;
//			UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
				//APP_LOG(TS_OFF, VLEVEL_M, "\r\n(1) Vibration Sensor EXTI Event BUT2 2 2 \r\n"); //YUNHORN_STS_TODO
		
      break;
#endif
#if defined(USE_STM32WLE5)
    case  MEMS_EXTI1_Pin:												
			//APP_LOG(TS_OFF, VLEVEL_L, "\r\n(3) Vibration Sensor EXTI Event BUT3  3 3 3 \r\n"); //YUNHORN_STS_TODO
			mems_int1_detected=1;
			UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), CFG_SEQ_Prio_0);
			
			UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
      break;
#endif
    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 */

    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)
              {
                AppLedStateOn = (appData->Buffer[0] -0x30) & 0x01;
                if (AppLedStateOn == RESET)
                {
                  APP_LOG(TS_OFF, VLEVEL_H, "LED OFF\r\n");
                  HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */
                }
                else
                {
                  APP_LOG(TS_OFF, VLEVEL_H, "LED ON\r\n");
                  HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET); /* LED_RED */
                }
              }
              break;
						case LORAWAN_USER_APP_CTRL_PORT:
              if (appData->BufferSize != 1)
              {
									if (appData->BufferSize < 128) {
									USER_APP_AUTO_RESPONDER_Parse((char*)appData->Buffer, appData->BufferSize);
									}
							}

              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);
    }
  }
  /* USER CODE END OnRxData_1 */
}

/**
  * @brief  Yunhorn STS Sensor Heart Beat Timer callback function
  * @param  context ptr of STS Sampling Check context
  */
static void OnYunhornSTSHeartBeatTimerEvent(void *context)
{
	heart_beat_timer = 1;
	UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
	UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);

	if ((sts_lorawan_joined ) && (sts_ac_code[0]==0x0))
	{
	  		/* RFAC  Challenge */
	  		if (rfac_timer < (STS_BURN_IN_RFAC+3)) {
	  			rfac_timer ++;
	  		}
	   		UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), CFG_SEQ_Prio_0);
	}
}

void USER_APP_AUTO_RESPONDER_Parse(char *tlv_buf, size_t tlv_buf_size) 
{
	uint8_t i=0;
	
		
	/*  
	 * YUNHORN STS PRODUCT BOARD LEVEL CONTROL OR REPORT 
	 */
	
	if (((char)tlv_buf[CFG_CMD1] == 'Y') && (tlv_buf_size <=5))  // BEGIN OF *** BOARD LEVEL CONTROL OR REPORT
	{
		switch ((char)tlv_buf[CFG_CMD2]) {
			case 'Z':		//"YZ"
				if ((char)tlv_buf[CFG_CMD3] == 'H') {  //BOARD SOFT RESET, REVIVE "YZH"
					//BOARD REVIVE					
					STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, 20, "!YunHorn STS Revive!");
					HAL_Delay(5000);	
										
					OnSystemReset();
				}	else if 	((char)tlv_buf[CFG_CMD3] == 'S') {		// Self Function Testing "YZS"
					
					STS_SENSOR_Function_Test_Process();
					
				} else if 	((char)tlv_buf[CFG_CMD3] == 'C') {		// Self Function Testing "YZC" LORAWAN CLASS A/B/C
					
			    DeviceClass_t deviceClass = CLASS_A;
					LmHandlerGetCurrentClass( &deviceClass );							
					i=0;
					outbuf[i++] = (uint8_t) 'L';
					outbuf[i++] = (uint8_t) sts_mtmcode1;
					outbuf[i++] = (uint8_t) sts_mtmcode2;
					outbuf[i++] = (uint8_t) sts_version;
					outbuf[i++] = (uint8_t) (0x41+ deviceClass); //translate to 'A','B','C'
					STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
				}
			break;
			case 'M':		//"YM"
				if ((char)tlv_buf[CFG_CMD3] >= '0' && (char)tlv_buf[CFG_CMD3]<='9') 	// Service Mask "YZM"
				{
						sts_service_mask = (uint8_t)(tlv_buf[CFG_CMD3]-0x30)&0xFF;
						sts_cfg_nvm.sts_service_mask = (uint8_t)sts_service_mask;
						outbuf[i++] = (uint8_t) 'Y';
						outbuf[i++] = (uint8_t) 'M';
						outbuf[i++] = (uint8_t) (sts_service_mask+0x30);
						STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
						APP_LOG(TS_OFF, VLEVEL_H, ">>>>>>>>>>>>>>>>>>>>> Mask = [ %02x ] \r\n", sts_service_mask);
						OnStoreSTSCFGContextRequest();
						#ifdef YUNHORN_STS_O6_ENABLED
						if (sts_service_mask != STS_SERVICE_MASK_L0) STS_Lamp_Bar_Set_Dark();
						STS_Combined_Status_Processing();
						#endif
				}
			break;				
			case 'V':	//"YV"
				if ((char)tlv_buf[CFG_CMD3] == 'H') { // "YVH"   REPORT FIRMWARE VERSION "YVH"
					// FIRMWARE VERSION REPORT	
					i = 0;
					outbuf[i++] = (uint8_t) 'V';
					outbuf[i++] = (uint8_t) sts_mtmcode1;
					outbuf[i++] = (uint8_t) sts_mtmcode2;
					outbuf[i++] = (uint8_t) sts_version;
					outbuf[i++] = (uint8_t) FirmwareVersion;
					outbuf[i++] = (uint8_t) MajorVer;
					outbuf[i++] = (uint8_t) MinorVer;
					outbuf[i++] = (uint8_t) SubMinorVer;
					STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
					APP_LOG(TS_OFF, VLEVEL_L, "###### YUNHORN Report Version [ %10x ] \r\n", outbuf);
				} 
				else 
				if ((char)tlv_buf[CFG_CMD3] == 'C') { // "YVC"   REPORT NVM STORED CONFIG PARAMETERS  "YVC"
				
					uint8_t cfg_in_nvm[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};
					OnRestoreSTSCFGContextRequest((uint8_t *)cfg_in_nvm);
					
					outbuf[i++] = (uint8_t) 'C';
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_MTM1];  //MTM Code
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_MTM2];  //MTM Code
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_VER];  //STS Version
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_HWV];  				//STS Version
					outbuf[i++] = (uint8_t) (cfg_in_nvm[NVM_PERIODICITY]);  	//UPLINK Periodicity
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_UNIT];  				//UPLINK Periodicity unit
					outbuf[i++] = (uint8_t) (cfg_in_nvm[NVM_SAMPLING]);  		//Heart-beat or SAMPLING Periodicity
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_S_UNIT];  			//Heart-beat or SAMPLING Periodicity unit
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_WORK_MODE];			// STS WORK MODE
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_SERVICE_MASK];  		//service mask
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_RESERVE01];  		//service mask
					outbuf[i++] = (uint8_t) cfg_in_nvm[NVM_LEN];  				//length of following cfg value


					for (uint8_t j=0; j <= cfg_in_nvm[NVM_LEN]; j++) {						
						outbuf[i++] = (uint8_t) (cfg_in_nvm[NVM_LEN+j]);
					}
					STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
					APP_LOG(TS_OFF, VLEVEL_H, "###### YUNHORN Report Config in NVM [ %10x ] \r\n", outbuf);
					
				}
			break;			
								// "YO#","YF#","YH#","YD##L" ##={0,9} L={S,M,H}
		  case 'O':			
						// TODO # of modules
						if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) {	
							STS_SENSOR_Power_ON((uint8_t)(tlv_buf[CFG_CMD3]-0x30));								
							i=0;
							outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD1];
							outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD2];
							outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD3];	
							STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
						} else {
							STS_SENSOR_Upload_Config_Invalid_Message();
						}
			break;
			case 'F':
					// TODO # of modules
						if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) {	
						STS_SENSOR_Power_OFF((tlv_buf[CFG_CMD3]-0x30));				
						i=0;
						outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD1];
						outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD2];
						outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD3];	
						STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);						
					} else {
						STS_SENSOR_Upload_Config_Invalid_Message();
					}
			break;
			case 'H':			
					// TODO # of modules
						if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) {							
						STS_SENSOR_MEMS_Reset((tlv_buf[CFG_CMD3]-0x30));				
						i=0;
						outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD1];
						outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD2];
						outbuf[i++] 	= (uint8_t) tlv_buf[CFG_CMD3];	
						STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);						
					} else {
						STS_SENSOR_Upload_Config_Invalid_Message();
					}
			break;						
					
			case 'D':
				if ((((char)tlv_buf[CFG_CMD3] >= '0') && ((char)tlv_buf[CFG_CMD3] <='9') 
					&& ((char)tlv_buf[CFG_CMD4] >='0') && ((char)tlv_buf[CFG_CMD4] <='9')) && 
						(((char)tlv_buf[CFG_CMD5] == 'M' || ((char)tlv_buf[CFG_CMD5] =='H') ||((char)tlv_buf[CFG_CMD5] =='S'))))
					{
						periodicity_length = (tlv_buf[CFG_CMD3]-0x30)*10+ (tlv_buf[CFG_CMD4]-0x30);	
						uint8_t periodicity_unit = (char)tlv_buf[CFG_CMD5];	
						if ((char)tlv_buf[CFG_CMD5] == 'M') {
							periodicity_length *= 60;
						} else if ((char)tlv_buf[CFG_CMD5] == 'H') {
							periodicity_length *= 3600;
						}
						TxPeriodicity = periodicity_length*1000;	//translate to 1000ms=1s
						HeartBeatPeriodicity = TxPeriodicity;

						OnTxPeriodicityChanged(TxPeriodicity);
						i = 0;
						outbuf[i++] = (uint8_t) tlv_buf[CFG_CMD1];
						outbuf[i++] = (uint8_t) tlv_buf[CFG_CMD2];
						outbuf[i++] = (uint8_t) tlv_buf[CFG_CMD3];
						outbuf[i++] = (uint8_t) tlv_buf[CFG_CMD4];
						outbuf[i++] = (uint8_t) tlv_buf[CFG_CMD5];

						STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
						// Save config to NVM
						sts_cfg_nvm.mtmcode1 = (uint8_t)sts_mtmcode1;
						sts_cfg_nvm.mtmcode2 = (uint8_t)sts_mtmcode2;
						sts_cfg_nvm.version = (uint8_t)sts_version;
						sts_cfg_nvm.hardware_ver = (uint8_t)sts_hardware_ver;
						sts_cfg_nvm.periodicity = (uint8_t)((tlv_buf[CFG_CMD3]-0x30)*10+(tlv_buf[CFG_CMD4]-0x30));
						sts_cfg_nvm.unit = (uint8_t)tlv_buf[CFG_CMD5];
						sts_cfg_nvm.work_mode = (uint8_t)sts_work_mode;
						sts_cfg_nvm.sts_service_mask = (uint8_t)sts_service_mask;
					
						OnStoreSTSCFGContextRequest();
						APP_LOG(TS_OFF, VLEVEL_L, "###### YUNHORN Periodicity Changed to [ %d ] Seconds\r\n", periodicity_length);
						
					} else {					
						STS_SENSOR_Upload_Config_Invalid_Message();
					}
			break;
				
			default:
					STS_SENSOR_Upload_Config_Invalid_Message();
			break;
			}
		}		// END OF *** BOARD LEVEL CONTROL OR REPORT
		else if (((char)tlv_buf[CFG_CMD1] == 'P') && (tlv_buf_size >= 4)) //   BEGIN OF PARAMETER CONFIG 
		{	
			 /*  
				* YUNHORN STS PRODUCT SUBMODULE, MEMS OR SENSOR HEAD LEVEL PARAMETER TUNING SECTION
				*/		
	
			uint8_t tlv_h2_cnt = 0x00, mems_ver=0x00;
			i = P_MEM_CFG;		//start of parameter
		
		switch (tlv_buf[P_MEMS_NO]-0x30) {   //#1 No. of MEMS components
			//default first sensor head or MEMS component, default 1 sensor heads
			case 0:					//default sensor head or MEMS component
			case 1:					//first sensor head or MEMS component
#ifdef YUNHORN_STS_M7_ENABLED					
			mems_ver = (tlv_buf[P_MTM_VER]-0x30);				// #2 MTM-ver
			if (mems_ver == sts_version) {					// Firmware version or Variation of MEMS/component
					if (tlv_buf_size == CFG_CMD_PARAMETER_SIZE) {		//Validation check
					act_threshold 	= 	(uint8_t) (tlv_buf[i++]-0x30)*10;			// "P 1 0 0 8"  -> 0*10
					act_threshold 	+= 	(tlv_buf[i++]-0x30);									// "P 1 0 0 8"	-> 0*10 + 8
					inact_threshold	= 	(uint8_t) (tlv_buf[i++]-0x30)*10;			// "P 1 0 0 8 0 4"  -> 0*10
					inact_threshold	+= 	(tlv_buf[i++]-0x30);									// "P 1 0 0 8 0 4"  -> 0*10 + 4
					inact_duration 	= 	(uint8_t) (tlv_buf[i++]-0x30)*10;			// "P 1 0 0 8 0 4 0 3"  -> 0*10
					inact_duration 	+= 	(uint8_t) (tlv_buf[i++]-0x30);				// "P 1 0 0 8 0 4 0 3"  -> 0*10+3
						
					if (act_threshold <= inact_threshold)	
						act_threshold += 2;
					}

					STS_MOTION_SENSOR_ACT_INACT_DURATION_Init();				
					
					i=0;						// Step 1: Prepare status update message
					outbuf[i++] 	= (char) 'P';
					outbuf[i++] 	= sts_mtmcode1;
					outbuf[i++] 	= sts_mtmcode2;
					outbuf[i++] 	= sts_version;
					outbuf[i++] 	= sts_hardware_ver;
					outbuf[i++] 	= (uint8_t) act_threshold;
					outbuf[i++]   = (uint8_t) inact_threshold;
					outbuf[i++]   = (uint8_t) inact_duration;							

					// Step 2: Save valid config to NVM
					sts_cfg_nvm.mtmcode1 = sts_mtmcode1;
					sts_cfg_nvm.mtmcode2 = sts_mtmcode2;
					sts_cfg_nvm.version = sts_version;
					sts_cfg_nvm.hardware_ver = sts_hardware_ver;
					sts_cfg_nvm.length = NVM_CFG_PARAMETER_SIZE;
					
					sts_cfg_nvm.p[0] = (uint8_t) act_threshold;
					sts_cfg_nvm.p[1] = (uint8_t) inact_threshold;
					sts_cfg_nvm.p[2] = (uint8_t) inact_duration;
					
					OnStoreSTSCFGContextRequest();
					
			} else {					// Invalid parameters
					// Step 1/2: Prepare status update message
					
					STS_SENSOR_Upload_Config_Invalid_Message();
					APP_LOG(TS_OFF, VLEVEL_L, "###### MTM VER Invalid or Mismatch\r\n");
			}
#endif											
			// Step 3: Upload status update message
					STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
			
#if defined(YUNHORN_STS_R1_ENABLED) || defined(YUNHORN_STS_R2_ENABLED)|| defined(YUNHORN_STS_R3_ENABLED) || defined(YUNHORN_STS_R5_ENABLED)
#endif			
#ifdef YUNHORN_STS_O1_ENABLED					
#endif			
			
			break;

// for multipul sensor heads or MEMS components, TODO   2022-10-21 PARK HERE
			
			case 2:
#ifdef YUNHORN_STS_O2_ENABLED							
				// for 2nd sensor heads such as 2x Presence radar, 2 reedswitch or hall elements
#endif
			break;
			
			default:
			// for multipul sensor heads or MEMS components, TODO   2022-10-21 PARK HERE	
			STS_SENSOR_Upload_Config_Invalid_Message();
			break;
		}	
	} else {
		STS_SENSOR_Upload_Config_Invalid_Message();
	}

} // END OF  USER_APP_AUTO_RESPONDER_Parse

void STS_SENSOR_Upload_Config_Invalid_Message(void)
{
		STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, 5, "PVXXX");
}

void STS_SENSOR_Upload_Message(uint8_t appDataPort, uint8_t appBufferSize, char *appDataBuffer)
{
	LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR;
	UTIL_TIMER_Time_t nextTxIn = 0;
	
	for (uint8_t i=0;i<appBufferSize; i++) {
		AppData.Buffer[i] = appDataBuffer[i];
	}
	AppData.Port = appDataPort;
	AppData.BufferSize = appBufferSize;

  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));
    }
  }
	
}


void STS_SENSOR_Auto_Responder_Process(uint8_t tlv_ver,uint8_t tlv_type, uint8_t tlv_length, uint8_t *tlv_content)
{
	uint8_t sensor_mems_type=(tlv_content[0]-0x30); //sensor_mems_type defined in sts_sensors.h 
	
#ifdef YUNHORN_STS_M7_ENABLED		
	uint8_t fm_version = FirmwareVersion; //MajorVer+MinorVer+SubMinorVer; 
	
#endif
	
	switch (sensor_mems_type)
	{
#ifdef YUNHORN_STS_M7_ENABLED		
		case sts_mtmcode2:				
		//TODO 
		break;
#endif
#ifdef YUNHORN_STS_R0_ENABLED				
		case STS_CTRL_CMD_MEMS_TUNE_TOF_VL53L0X:
			
		break;
#endif		
#ifdef YUNHORN_STS_P1_ENABLED				
		case STS_CTRL_CMD_MEMS_TUNE_FMCW_TI68X:
			
		break;
#endif
#ifdef YUNHORN_STS_OO_ENABLED						
		case STS_CTRL_CMD_MEMS_TUNE_PCR_A12X:
			
		break;

		case STS_CTRL_CMD_PRESENCE_SETTING:
			
		break;
#endif
#ifdef YUNHORN_STS_M3_ENABLED						
		case STS_CTRL_CMD_MEMS_TUNE_DIGITAL_RELAY:
			
		break;
#endif
#ifdef YUNHORN_STS_M5_ENABLED						
		case STS_CTRL_CMD_MEMS_TUNE_FAN_CONTROL:
			
		break;
#endif
		default:
			
		break;
		
	}
}



static void SendTxData(void)
{
  /* USER CODE BEGIN SendTxData_1 */
  LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR;
	uint8_t batteryLevel = GetBatteryLevel();
//  sensor_t sensor_data;
	STS_M7_SensorDataTypeDef m7_data;	
  UTIL_TIMER_Time_t nextTxIn = 0;
  
  uint32_t i = 0;
  
	//EnvSensors_Read(&sensor_data);
	STS_MOTION_SENSOR_Read(&m7_data);
	
  AppData.Port = LORAWAN_USER_APP_PORT;
	AppData.Buffer[i++] = AppLedStateOn;																			//#0
	
	//if (sensor_data_ready == 0L) return ;
	if (heart_beat_timer != 0U) 
	{
		heart_beat_timer = 0U;
		AppData.Port = YUNHORN_STS_M7_LORA_APP_HTBT_PORT;
		AppData.Buffer[i++] = (uint8_t)(99*batteryLevel/254);										//#01
	} 
	if (sensor_data_ready !=0U)
	{	
	sensor_data_ready = 0U;
	AppData.Buffer[i++] = (uint8_t)(0xFF & sts_mtmcode1); //mtmcode1;					//#01
	AppData.Buffer[i++] = (uint8_t)(0xFF & sts_mtmcode2); //mtmcode2;					//#02
	AppData.Buffer[i++] = (uint8_t)(0xFF & sts_hardware_ver); //hardware_Ver; //#03
	AppData.Buffer[i++] = (uint8_t)(99*batteryLevel/254);											//#04  		/* 99% (very low) to 254 (fully charged) */
	AppData.Buffer[i++] = 0x0D;		//temp																			//#05
	
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vibration_duration);  			//06
	
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_x_freq >> 8);						//07      Freq Max 256 Hz Given sample rate & FFT Length 512
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_x_freq);								//08      Freq Max 256 Hz Given sample rate & FFT Length 512
	
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_y_freq >> 8);						//09			Freq Max 256 Hz Given sample rate & FFT Length 512
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_y_freq);								//10			Freq Max 256 Hz Given sample rate & FFT Length 512
	
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_z_freq >> 8);						//11			Freq Max 256 Hz Given sample rate & FFT Length 512
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_z_freq);								//12			Freq Max 256 Hz Given sample rate & FFT Length 512
	
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_x_rms >> 8 );						//13			Freq Max 256 Hz Given sample rate & FFT Length 512
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_x_rms);									//14
		
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_y_rms >> 8);						//15
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_y_rms);									//16
		
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_z_rms >>8 );						//17
	AppData.Buffer[i++] = (uint8_t)(0xFF & m7_data.vb_z_rms);									//18
	
	
	
	APP_LOG(TS_OFF, VLEVEL_M, "###### Duration: %02d seconds | FREQ_X:%d Hz | FREQ_Y:%d Hz | FREQ_Z:%d Hz |\r\n###### | RMS_X:%d | RMS_Y:%d | RMS_Z:%d | BATTERY_B:%02d%% |\r\n", 
		AppData.Buffer[6], (AppData.Buffer[7]*255+AppData.Buffer[8]), (AppData.Buffer[9]*255+AppData.Buffer[10]), (AppData.Buffer[11]*255+AppData.Buffer[12]), 
		(AppData.Buffer[13]*255+AppData.Buffer[14]),(AppData.Buffer[15]*255+AppData.Buffer[16]),(AppData.Buffer[17]*255+AppData.Buffer[18]),AppData.Buffer[04]);
	}

/*
  if ((LmHandlerParams.ActiveRegion == LORAMAC_REGION_US915) || (LmHandlerParams.ActiveRegion == LORAMAC_REGION_AU915)
      || (LmHandlerParams.ActiveRegion == LORAMAC_REGION_AS923))
  {   }   
	else   
	{   }
	
*/
	
  AppData.BufferSize = i;

  if ((JoinLedTimer.IsRunning) && (LmHandlerJoinStatus() == LORAMAC_HANDLER_SET))
  {
    UTIL_TIMER_Stop(&JoinLedTimer);
    HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */
  }
  if (i>1) 
	{
		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 */
	heart_beat_timer = 1U;
  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");
      }
			
			sts_lorawan_joined =  (uint8_t) joinParams->Mode;			
			OnTxPeriodicityChanged(periodicity_length*1000);
			APP_LOG(TS_OFF, VLEVEL_L, "\r\n==================== Tx Periodicity changed to = %d second(s) \r\n", (int)periodicity_length);
    }
    else
    {
      APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### = JOIN FAILED\r\n");
    }
  }
  /* 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 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 */
}

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 */
}

void OnStoreSTSCFGContextRequest(void)
{
  /* USER CODE BEGIN OnStoreContextRequest_1 */
	uint8_t i=0, j=0, nvm_store_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0}, nvm_store_size=YUNHORN_STS_MAX_NVM_CFG_SIZE;
	
#ifdef YUNHORN_STS_M7_ENABLED
	sts_cfg_nvm.length   = STS_NVM_CFG_SIZE;
	nvm_store_value[i++] = sts_cfg_nvm.mtmcode1;
	nvm_store_value[i++] = sts_cfg_nvm.mtmcode2;
	nvm_store_value[i++] = sts_cfg_nvm.version;
	nvm_store_value[i++] = sts_cfg_nvm.hardware_ver;
	nvm_store_value[i++] = sts_cfg_nvm.periodicity;
	nvm_store_value[i++] = sts_cfg_nvm.unit;
	nvm_store_value[i++] = sts_cfg_nvm.sampling;
	nvm_store_value[i++] = sts_cfg_nvm.s_unit;
	nvm_store_value[i++] = sts_cfg_nvm.work_mode;
	nvm_store_value[i++] = sts_cfg_nvm.sts_service_mask;
	nvm_store_value[i++] = sts_cfg_nvm.reseve01;
	nvm_store_value[i++] = (uint8_t) STS_NVM_CFG_SIZE; //sts_cfg_nvm.length;

	for (j = 0; j < STS_CFG_PCFG_SIZE; j++) {
		nvm_store_value[i++] = (sts_cfg_nvm.p[j]);
	}

	nvm_store_value[i++] = sts_cfg_nvm.fall_detection_acc_threshold;
	nvm_store_value[i++] = sts_cfg_nvm.fall_detection_depth_threshold;
	nvm_store_value[i++] = sts_cfg_nvm.fall_detection_reserve;
	nvm_store_value[i++] = sts_cfg_nvm.occupancy_overtime_threshold;

	for (j = 0; j < YUNHORN_STS_AC_CODE_SIZE; j++) {
		nvm_store_value[i++] = (sts_cfg_nvm.ac[j]);
	}
#endif	

#ifdef YUNHORN_STS_O0_ENABLED

#endif	

#ifdef YUNHORN_STS_R0_ENABLED

#endif	
  /* USER CODE END OnStoreContextRequest_1 */
  /* store nvm in flash */
  if (FLASH_IF_Erase(STS_CONFIG_NVM_BASE_ADDRESS, FLASH_PAGE_SIZE) == FLASH_IF_OK)
  {
    FLASH_IF_Write(STS_CONFIG_NVM_BASE_ADDRESS, (const void *)nvm_store_value, YUNHORN_STS_MAX_NVM_CFG_SIZE);
  }
  /* USER CODE BEGIN OnStoreContextRequest_Last */

#ifdef YUNHORN_STS_M7_ENABLED	
		
	
	
#endif		
  /* USER CODE END OnStoreContextRequest_Last */
}

void OnRestoreSTSCFGContextRequest(uint8_t *cfg_in_nvm)
{
  /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_1 */
	uint8_t i=0, nvm_store_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]="", nvm_store_size=YUNHORN_STS_MAX_NVM_CFG_SIZE;

  /* USER CODE END OnRestoreSTSCFGContextRequest_1 */
  UTIL_MEM_cpy_8(nvm_store_value, (void *)STS_CONFIG_NVM_BASE_ADDRESS, nvm_store_size);
  /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_Last */

	memcpy(cfg_in_nvm, nvm_store_value, YUNHORN_STS_MAX_NVM_CFG_SIZE);
/*
	APP_LOG(TS_OFF, VLEVEL_M, "CFG IN NVM =%02x %02x %02x %02x \r\n",
			cfg_in_nvm[0],cfg_in_nvm[1],cfg_in_nvm[2],cfg_in_nvm[3]);
*/
  /* USER CODE END OnRestoreSTSCFGContextRequest_Last */
}
	

void STS_REBOOT_CONFIG_Init(void) 
{
  /* USER CODE BEGIN OnRestoreContextRequest_1 */
	uint8_t i=0, nvm_stored_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0}, nvm_store_size=YUNHORN_STS_MAX_NVM_CFG_SIZE;

  /* USER CODE END OnRestoreContextRequest_1 */
  UTIL_MEM_cpy_8(nvm_stored_value, (void *)STS_CONFIG_NVM_BASE_ADDRESS, nvm_store_size);
  /* USER CODE BEGIN OnRestoreContextRequest_Last */
#ifdef YUNHORN_STS_M7_ENABLED
  if ((nvm_stored_value[NVM_MTM1] != sts_mtmcode1) || (nvm_stored_value[NVM_MTM2] != sts_mtmcode2) || (nvm_stored_value[NVM_VER] != sts_version))
	{
		APP_LOG(TS_OFF, VLEVEL_H, "\r\nInitial Boot with Empty Config, Flash with default config....\r\n");
		OnStoreSTSCFGContextRequest();
		UTIL_MEM_set_8((void *)sts_ac_code, 0x00, YUNHORN_STS_AC_CODE_SIZE);
		HAL_Delay(1000);
	} else
	{
		sts_cfg_nvm.periodicity 		= (uint8_t)(nvm_stored_value[NVM_PERIODICITY]);				//TxPeriodicity interval
		sts_cfg_nvm.unit				= (uint8_t)(nvm_stored_value[NVM_UNIT]);
		sts_cfg_nvm.sampling			= (uint8_t)(nvm_stored_value[NVM_SAMPLING]);				//Heart-beat or sampling interval
		sts_cfg_nvm.s_unit				= (uint8_t)(nvm_stored_value[NVM_S_UNIT]);
		sts_cfg_nvm.work_mode			= (uint8_t)(nvm_stored_value[NVM_WORK_MODE]);
		sts_cfg_nvm.sts_service_mask	= (uint8_t)(nvm_stored_value[NVM_SERVICE_MASK]);
		sts_cfg_nvm.reseve01			= (uint8_t)(nvm_stored_value[NVM_RESERVE01]);
		sts_cfg_nvm.length 				= (uint8_t)(nvm_stored_value[NVM_LEN]&0x3F);		//MAX 32 bytes

			for (uint8_t j=0; j< sts_cfg_nvm.length; j++) {
				sts_cfg_nvm.p[j] 				= (uint8_t)nvm_stored_value[NVM_LEN+j];
			}
			
		sts_cfg_nvm.fall_detection_acc_threshold 	= (uint8_t)nvm_stored_value[NVM_FALL_DETECTION_ACC_THRESHOLD];
		sts_cfg_nvm.fall_detection_depth_threshold 	= (uint8_t)nvm_stored_value[NVM_FALL_DETECTION_DEPTH_THRESHOLD];
		sts_cfg_nvm.fall_detection_reserve			= (uint8_t)nvm_stored_value[NVM_FALL_DETECTION_RESERVE];
		sts_cfg_nvm.occupancy_overtime_threshold 	= (uint8_t)nvm_stored_value[NVM_OCCUPANCY_OVERTIME_THRESHOLD];

		for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++) {
			sts_cfg_nvm.ac[j] 				= (uint8_t)nvm_stored_value[NVM_AC_CODE_START +j];
		}
		
	}
#endif	

#ifdef YUNHORN_STS_O0_ENABLED

#endif	

#ifdef YUNHORN_STS_R0_ENABLED

#endif	
	
	OnRestoreSTSCFGContextProcess();

  /* USER CODE END OnRestoreContextRequest_Last */
}

void OnRestoreSTSCFGContextProcess(void)
{
	periodicity_length = (sts_cfg_nvm.periodicity);
	if ((char)sts_cfg_nvm.unit =='M') {
		periodicity_length *= 60;
	} else if ((char) sts_cfg_nvm.unit =='H') {
		periodicity_length *= 3600;
	} else if ((char) sts_cfg_nvm.unit =='S') {
		periodicity_length *= 1;
	}
	
	periodicity_length = (periodicity_length>10)? periodicity_length : 10;	
	if (sts_lorawan_joined) 
	{
		OnTxPeriodicityChanged(periodicity_length*1000);
	} else 
	{
		OnTxPeriodicityChanged(TxPeriodicity);
	}
		
	sts_work_mode	= sts_cfg_nvm.work_mode;
	sts_service_mask = sts_cfg_nvm.sts_service_mask;

	for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++)
	{
		sts_ac_code[j] = sts_cfg_nvm.ac[j];
	}
	
#ifdef YUNHORN_STS_M7_ENABLED	
	if ((sts_version == sts_cfg_nvm.version)&& (NVM_CFG_PARAMETER_SIZE == sts_cfg_nvm.length)) {
		
		act_threshold 		= 	sts_cfg_nvm.p[0];
		inact_threshold		= 	sts_cfg_nvm.p[1];
		inact_duration		=		sts_cfg_nvm.p[2];	
	
		STS_MOTION_SENSOR_ACT_INACT_DURATION_Init();
	}
	
#endif


}

void STS_SENSOR_Function_Test_Process(void)
{
	char outbuf[32] =""; uint8_t i=0, count=10;
  uint8_t i2c_Slave_Dev_ID = 0x00;
	
	outbuf[i++] = (uint8_t) 'S';
	outbuf[i++] = (uint8_t) sts_mtmcode1;
	outbuf[i++] = (uint8_t) sts_mtmcode2;
	outbuf[i++] = (uint8_t) sts_version;
	outbuf[i++] = (uint8_t) sts_hardware_ver;
	outbuf[i++] = (uint8_t) (99*((GetBatteryLevel()/254)&0xff));					
	
	
	if (STS_SENSOR_MEMS_Get_ID(&i2c_Slave_Dev_ID) == 0x00) {
		outbuf[i++] = (uint8_t) 0X01;	//SIZE OF FOLLOWING DATA
    outbuf[i++] = (uint8_t) 'X'; // Slave MEMS Not Avaliable	
	}	else 
	{
#ifdef YUNHORN_STS_M7_ENABLED
	int16_t self_test_result[9]={0,0,0,0, 0,0,0, 0,0};	
	
	STS_MOTION_SENSOR_Function_Test_Process(&self_test_result[0], count);	
	
	outbuf[i++] = (uint8_t) 0X12;	//SIZE OF FOLLOWING DATA
	
	outbuf[i++] = (uint8_t) (self_test_result[0]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[0])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[1]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[1])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[2]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[2])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[3]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[3])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[4]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[4])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[5]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[5])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[6]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[6])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[7]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[7])&0xff;
	
	outbuf[i++] = (uint8_t) (self_test_result[8]>>8)&0xff;
	outbuf[i++] = (uint8_t) (self_test_result[8])&0xff;
#endif

	}
	
	STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, outbuf);
	
}

void STS_YunhornAuthenticationCode_Process(void)
{
	if (sts_ac_code[0] == 0x00) {
		APP_LOG(TS_OFF,VLEVEL_H, "Initial AC CODE blank... \r\n");
		return;
	}

	sts_service_mask = (sts_hmac_verify()!= 0)? STS_SERVICE_MASK_L2:STS_SERVICE_MASK_L0;
	if (sts_service_mask == STS_SERVICE_MASK_L2) {
		sts_ac_code[0] = 0x0;
	}
	APP_LOG(TS_OFF, VLEVEL_H, "STS_SERVICE_MASK:%d \r\n",sts_service_mask);
}

void STS_YunhornSTSEventRFAC_Process(void)
{
	if (sts_ac_code[0] ==0x0)
	{
		if ((rfac_timer >= STS_BURN_IN_RFAC) && (rfac_timer < (STS_BURN_IN_RFAC +3)))
		{
			APP_LOG(TS_OFF, VLEVEL_H, "\r\n -------------------RFAC Process\r\n");
			STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, 4, "RFAC");
		}
		if ((rfac_timer > (STS_BURN_IN_RFAC + 2)))
		{
			APP_LOG(TS_OFF, VLEVEL_H, "\r\n -------------------Verify RFAC Success or Not\r\n");
			sts_service_mask = (sts_hmac_verify()!= 0)? STS_SERVICE_MASK_L2:STS_SERVICE_MASK_L0;
			if (sts_service_mask == STS_SERVICE_MASK_L2) {
				sts_ac_code[0] = 0x0;
			}
		}
	}

}