/* 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"
#ifdef	CLOCK_SYNC
#include "LmhpClockSync.h"
#endif
/* USER CODE BEGIN Includes */
#include "app_tof_pin_conf.h"
#include "app_tof_peoplecount.h"
#include "yunhorn_sts_prd_conf.h"
#include "yunhorn_sts_sensors.h"
#if	defined(STS_O6)||defined(STS_T6)||defined(O1L)
#include "sts_lamp_bar.h"
#endif
/* USER CODE END Includes */

/* External variables ---------------------------------------------------------*/
/* USER CODE BEGIN EV */
uint8_t outbuf[128]={0x0};

extern volatile uint8_t sts_ac_code[20], sts_service_mask;
extern volatile uint8_t sts_work_mode, sts_cloud_netcolor, sts_lamp_bar_color, sts_status_color, luminance_level;
volatile static bool r_b=true;
volatile uint8_t heart_beat_timer =0;
extern volatile uint8_t sensor_data_ready;
extern uint8_t sts_door_jam_profile;
extern uint8_t sts_color_occupy_vacant;

#ifdef STS_T6
volatile uint8_t PIRValue =0, prev_sts_pir_state=0, sts_pir_state_changed=0;
extern volatile uint8_t sts_tof_presence_state;
uint32_t lowIn=0;
volatile bool lockLow = true, takeLowTime;
#endif
static uint32_t sts_warm_up_count = 0;
extern volatile sts_cfg_nvm_t sts_cfg_nvm;
extern volatile uint32_t rfac_timer;
extern volatile uint32_t STS_TOFScanPeriod_msec, STS_TxPeriod_sec, STS_HeartBeatTimerPeriod_sec;
extern volatile uint8_t sts_pir_state;
volatile uint8_t sts_data_buf[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]={0x0};
//volatile LmHandlerAppData_t sts_app_data={ 0, 0, sts_data_buf };
#ifdef 	STS_M1
extern volatile uint8_t sts_water_leakage_state;
#endif

static void STS_Show_STS_CFG_NVM(uint8_t * store_value, uint16_t store_size);
static uint8_t nvm_stored_value[2*YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};
static uint8_t sts_cfg_nvm_factory_default[YUNHORN_STS_MAX_NVM_CFG_SIZE];
volatile sts_cfg_nvm_t sts_cfg_nvm = {
		sts_mtmcode1,
		sts_mtmcode2,
		sts_version,
		sts_hardware_ver,
		0x0A,		//Regular TxPeriodicity interval
		'M', 		//Uplink data interval unit,  for heart-beat uplink
#if	defined(STS_P2)||defined(L8)||defined(STS_O6T)||defined(STS_T6)
		0x1E,		//Heart-beat interval or Sampling interval
		'M', 		//Sampling sensor interval unit, for real-time sensing of MEMS
#else
		0x3C,		//Heart-beat interval ,  for heart-beat uplink
		'M', 		//Heart-beat interval unit
#endif
		0x04,		// dual mode=4, uni_mode =5
		0x00,		// sts service mask
		0x00, 		//sts_ioc_mask
		0x20,   	//32 bytes, below start of p[0] 20 BYTES AND 12 BYTES FALL DOWN CFG
		{			// below 20 bytes
#ifdef	 STS_P2
		0x0,0x8,0x10,0x0,0x3,0x8,0x21,0x1,0xaf,0xe7, //current work config profile short
		0x1,0x8,0x10,0x0,0x3,0x8,0x21,0x1,0xaf,0xe7, //current work config profile long, after measured distance
		// change the max distance, min distance,  SPAD, front center and back center, etc.
#else
		0x08,		//start_m [8]*0.1 meter =0.8
		0x19,		//lenght_m 0x19=[25]*0.1=2.5f meter
		0x0F,		//threshold  0X0F=[15]*0.1=1.5f
		0x28,		//receiver gain 0x28 =[40]*0.01=0.40f max 99=0x63
		0x04,		//profile [4]=4
		0x0A,		//rate tracking 0x0A=10= 10U
		0x41,		//rate presence 0x41=65= 65U
		0x3F,		//hwaas   0x3F=63 =63U
		0x00,		//nbr removed pc [0]=0
		0x05,		//inter frame deviation time const 0x05=[5]*0.1=0.5f
		0x0A,		//inter frame fast cutoff 0x0A=[10] = 10U
		0x01,		//inter frame slow cutoff,0x01=1[1]*0.01=0.01f
		0x00,		//intra frame time const [0]=0   Lower to reduce sensitivity, higher to increase sensitivity
		0x0A,		//intra frame weight, 0x00=[0]*0.1=0.0F		0x0A=10, 10*0.1=1 FOR FAST MOVEMENT TRACKING FALL DETECTION
		0x05,		//output time const 0x05=[5]*0.1=0.5
		0x02,		//downsampling factor [2]=2
		0x03,		//power saving mode ACTIVE [3] = 3U
		0x00,		//reserve --P[17]
		0x00,		//reserve --P[18]
		0x00,		//reserve --P[19]
#endif
		},			// above  20 bytes
		0x21,		// color occupy (red:2) | color vacant (green:1) or  other 0x20 occupy(red:2) | color vacant (dark:0) for ATAL-HK 20241230
		0x06,		// sts_door_jam_profile for O6T
		0x20,		// sensor install height in dm =10 cm, default 32*10=320cm, 3.2meter

		0x00,		//reserve5	alarm_parameter05
		0x06,		//reserve6  alarm_mute_or_reset_expire_timer_in_10sec, 60 seconds
		0x23,		//reserve7  alarm Lamp Bar Flashing color define, 0x20, 2==STS_RED, 0 = STS_DARK, 0x23, 2=STS_RED, 3=STS_BLUE
		0x03, 		//reserve8  occupancy over time threshold  3*10 = 30 minutes

		0x09,		//reserve8  motionless_duration_threshold_in_min+1, normal: 10 min(0x0A) Minutes (2 min.) 1-9== 2-10min
		0x09, 		//unconscious threshold * 128, 0-9, 9*128=1280 motion level

		0x01,		//fall_detection_acc_threshold = *10 acceleration measure
		0x03,		//fall detection_depth_threshold  *10cm
		0x03,		//falldown_confirm_threshold_in_10sec, 0x3=30 sec default
					// below 20 bytes for RFAC code
		{0x0,0x0,0x0,0x0,0x0,   0x0,0x0,0x0,0x0,0x0,    0x0,0x0,0x0,0x0,0x0,   0x0,0x0,0x0,0x0,0x0}
};


/* 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);

/**
  * @brief  STS Wake Up Scan timer callback function
  * @param  context ptr of VL53LX TOF People Counting Process context
  */
static void OnYunhornSTSWakeUpScanTimerEvent(void *context);


/**
  * @brief  STS Lamp Bar timer callback function
  * @param  context ptr of Lamp Bar LED context
  */
static void OnYunhornSTSLampBarColorTimerEvent(void *context);

/**
  * @brief  SYS occupancy, door lock, motion duration check timer callback function
  * @param  context ptr of duration check context
  */
static void OnYunhornSTSDurationCheckTimerEvent(void *context);

/**
  * @brief  Yunhorn STS Occupancy RSS WakeUP timer callback function
  * @param  context ptr of STS RSS WakeUp context
  */

//static void OnYunhornSTSOORSSWakeUpTimerEvent(void *context);

/**
  * @brief  Yunhorn STS Heart beat timer callback function
  * @param  context ptr of context
  */

static void OnYunhornSTSHeartBeatTimerEvent(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);




/* 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 Timer to handle the application ToF Ranging Scan
  */
static UTIL_TIMER_Object_t YunhornSTSWakeUpScanTimer;

/**
  * @brief Timer to handle the application Heart beat timer
  */
static UTIL_TIMER_Object_t YunhornSTSHeartBeatTimer;

/**
  * @brief Timer to handle the application Lamp Bar LED Timer refresh
  */
static UTIL_TIMER_Object_t STSLampBarColorTimer;

/**
  * @brief Timer to handle the application Duration check Timer
  */
static UTIL_TIMER_Object_t STSDurationCheckTimer;

/**
  * @brief Tx Timer period
  */
//static UTIL_TIMER_Time_t TxPeriodicity = APP_TX_DUTYCYCLE;
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;

static volatile bool IsClockSynched = false;

/* USER CODE END PV */

/* Exported functions ---------------------------------------------------------*/
/* USER CODE BEGIN EF */
extern volatile uint8_t ToF_EventDetected;
SysTime_t sts_pir_start_time, sts_pir_duration_check_time;
/* 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 */

  APP_LOG(TS_OFF, VLEVEL_M, "\n\n# YUNHORN SMARTOILETS: (%s) MTM:%d.%d HWFW:%d.%d V:%d.%d.%d #\n\n",(char*)YUNHORN_STS_PRD_STRING,
		  (uint8_t)sts_mtmcode1, (uint8_t)sts_mtmcode2,(uint8_t)sts_hardware_ver,(uint8_t)FirmwareVersion,
		  (uint8_t)MajorVer,(uint8_t)MinorVer,(uint8_t)SubMinorVer);
  /* 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);

  UTIL_TIMER_Create(&STSLampBarColorTimer, 2*LED_PERIOD_TIME, UTIL_TIMER_ONESHOT, OnYunhornSTSLampBarColorTimerEvent, NULL);
  //UTIL_TIMER_Create(&STSDurationCheckTimer, 20*LED_PERIOD_TIME, UTIL_TIMER_ONESHOT, OnYunhornSTSDurationCheckTimerEvent, 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);

#ifdef	CLOCK_SYNC
    LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL );
    IsClockSynched = false;
#endif

  /* 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 */
#if 0
  STS_REBOOT_CONFIG_Init();

  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), UTIL_SEQ_RFU, STS_YunhornSTSEventRFAC_Process);

#if	defined(STS_M1)||defined(STS_O5)

  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), UTIL_SEQ_RFU, STS_YunhornSTSEventP1_Process);

#endif

#if	defined(STS_T6)||defined(STS_O6)
  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP3), UTIL_SEQ_RFU, STS_YunhornSTSEventP3_Process);
#endif

#if	defined(STS_P2)||defined(STS_T6)||defined(L8)

  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP5), UTIL_SEQ_RFU, STS_YunhornSTSEventP5_Process);

#endif

#ifdef	STS_R4
  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP6), UTIL_SEQ_RFU, STS_YunhornSTSEventP6_Process);
#endif

#ifdef VL53L0
  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP4), UTIL_SEQ_RFU, STS_YunhornSTSEventP4_Process);
#endif

#if	defined(STS_T6)||defined(L8)
  UTIL_TIMER_Create(&YunhornSTSWakeUpScanTimer, STS_TOFScanPeriod_msec, UTIL_TIMER_PERIODIC, (void*)OnYunhornSTSWakeUpScanTimerEvent, NULL);
  //UTIL_TIMER_Create(&YunhornSTSWakeUpScanTimer, STS_TOFScanPeriod_msec, UTIL_TIMER_PERIODIC, (void*)STS_TOF_VL53LX_PresenceDetection_Process_Start, NULL);
  UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);

  UTIL_TIMER_Start(&STSLampBarColorTimer);

#elif	defined(STS_P2)
  UTIL_TIMER_Create(&YunhornSTSWakeUpScanTimer, STS_TOFScanPeriod_msec, UTIL_TIMER_PERIODIC, (void*)STS_TOF_VL53LX_PeopleCounting_Process_Start, NULL);
  UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);
#endif

  //  UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, 1000*STS_HeartBeatTimerPeriod_sec, UTIL_TIMER_PERIODIC, OnYunhornSTSHeartBeatTimerEvent, NULL);
  //  UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, 1000*STS_HeartBeatTimerPeriod_sec, UTIL_TIMER_ONESHOT, OnYunhornSTSHeartBeatTimerEvent, NULL);
  //  UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);
#endif
  /* USER CODE END LoRaWAN_Init_Last */
}

void STS_Sensor_Init(void)
{

	 STS_REBOOT_CONFIG_Init();

	  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), UTIL_SEQ_RFU, STS_YunhornSTSEventRFAC_Process);

	#if	defined(STS_M1)||defined(STS_O5)

	  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), UTIL_SEQ_RFU, STS_YunhornSTSEventP1_Process);

	#endif

	#if	defined(STS_T6)||defined(STS_O6)
	  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP3), UTIL_SEQ_RFU, STS_YunhornSTSEventP3_Process);
	#endif

	#if	defined(STS_P2)||defined(STS_T6)||defined(L8)

	  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP5), UTIL_SEQ_RFU, STS_YunhornSTSEventP5_Process);

	#endif

	#ifdef	STS_R4
	  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP6), UTIL_SEQ_RFU, STS_YunhornSTSEventP6_Process);
	#endif

	#ifdef VL53L0
	  UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP4), UTIL_SEQ_RFU, STS_YunhornSTSEventP4_Process);
	#endif

	#if	defined(STS_T6)||defined(L8)
	  UTIL_TIMER_Create(&YunhornSTSWakeUpScanTimer, STS_TOFScanPeriod_msec, UTIL_TIMER_ONESHOT, (void*)OnYunhornSTSWakeUpScanTimerEvent, NULL);
	  //UTIL_TIMER_Create(&YunhornSTSWakeUpScanTimer, STS_TOFScanPeriod_msec, UTIL_TIMER_PERIODIC, (void*)STS_TOF_VL53LX_PresenceDetection_Process_Start, NULL);

	  UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, 1000*STS_HeartBeatTimerPeriod_sec, UTIL_TIMER_PERIODIC, OnYunhornSTSHeartBeatTimerEvent, NULL);
	  //UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);


//	  UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);

	  //UTIL_TIMER_Start(&STSLampBarColorTimer);

	#elif	defined(STS_P2)
	  UTIL_TIMER_Create(&YunhornSTSWakeUpScanTimer, STS_TOFScanPeriod_msec, UTIL_TIMER_PERIODIC, (void*)STS_TOF_VL53LX_PeopleCounting_Process_Start, NULL);
	  UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);
	#endif

	  //  UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, 1000*STS_HeartBeatTimerPeriod_sec, UTIL_TIMER_PERIODIC, OnYunhornSTSHeartBeatTimerEvent, NULL);
	  //  UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, 1000*STS_HeartBeatTimerPeriod_sec, UTIL_TIMER_ONESHOT, OnYunhornSTSHeartBeatTimerEvent, NULL);
	  //  UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);


}


void STS_Sensor_Prepare(void)
{

	//STS_TOF_VL53LX_PresenceDetection_Process_Init();
	UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);

}

/* USER CODE BEGIN PB_Callbacks */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  switch (GPIO_Pin)
  {
#ifdef	STS_O5
  case  HALL1_Pin:

  	  if (0 == HALL1_STATE)
  	  {
  		HAL_Delay(20);
  		//if (0 == HALL1_STATE) APP_LOG(TS_OFF, VLEVEL_M, "\r\n Button 1 state == 0 \r\n");
  	  } else if (1 == HALL1_STATE)
  	  {
  		HAL_Delay(20);
  		//if (1 == HALL1_STATE) 	APP_LOG(TS_OFF, VLEVEL_M, "\r\n Button 1 state ==1 \r\n");
  	  }
  	  HAL_Delay(100);
  	  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
  		  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
    break;
  case  HALL2_Pin:

  	  if (0 == HALL2_STATE)
  	  {
  		HAL_Delay(20);
  		  APP_LOG(TS_OFF, VLEVEL_M, "\r\n Button 2 state == 0 \r\n");
  	  } else
  	  {
  		HAL_Delay(20);
  		  APP_LOG(TS_OFF, VLEVEL_M, "\r\n Button 2 state ==1 \r\n");
  	  }
  	  HAL_Delay(100);
  	  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

  		  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
    break;

#elif defined(STS_M1)
  case WATER_DETECT_Pin:
	  sts_water_leakage_state = WATER_DETECT_STATE;
	  if (0 == sts_water_leakage_state)
	  {
		  HAL_Delay(20);
		  sts_water_leakage_state = WATER_DETECT_STATE;
		  if (0 == sts_water_leakage_state)
		  APP_LOG(TS_OFF, VLEVEL_M, "\r\n water leakage state == 0 \r\n");
	  } else
	  {
		  HAL_Delay(20);
		  sts_water_leakage_state = WATER_DETECT_STATE;
		  if (1 == sts_water_leakage_state)
		  APP_LOG(TS_OFF, VLEVEL_M, "\r\n water leakage state == 1 \r\n");
	  }
  	  HAL_Delay(100);
  	  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

	  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
	  break;
#else
    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;


#ifndef	STS_R4
    case  BUT2_Pin:
      UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStopJoinEvent), CFG_SEQ_Prio_0);
      break;
#endif
#endif
#ifdef	STM32WL55xx
    case  BUT3_Pin:
      UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStoreContextEvent), CFG_SEQ_Prio_0);
      break;
#endif
#ifdef STS_T6
    case  PIR_Pin:
    	sts_pir_state= PIR_STATE;
    	APP_LOG(TS_OFF, VLEVEL_M, "\r\n PIR_Read=%d \r\n", sts_pir_state);
    	if (sts_pir_state == 1)
    	{
    		if (lockLow)
    		{
    			PIRValue = 1;
    			lockLow = false;
    			sts_pir_start_time = SysTimeGet();
    			APP_LOG(TS_OFF, VLEVEL_M, "\r\n PIRValue=%d \r\n", PIRValue);
    			if (sts_pir_state != prev_sts_pir_state) {
    			    	sts_pir_state_changed = 1;
    			}
    			prev_sts_pir_state = sts_pir_state;
    		}
    		takeLowTime = true;
    	}

    	if (sts_pir_state ==0)
    	{

    		if (takeLowTime)
    		{
    			sts_pir_duration_check_time = SysTimeGet();
    			lowIn = sts_pir_duration_check_time.Seconds;
    			takeLowTime = false;
    		}

    		sts_pir_duration_check_time = SysTimeGet();
    		if ((!lockLow && (sts_pir_duration_check_time.Seconds - lowIn) > 5))
    		{
    			PIRValue = 0;
    			lockLow = true;
    			sts_pir_state = 0;
    			APP_LOG(TS_OFF, VLEVEL_M, "\r\n PIRValue=%d \r\n", PIRValue);
    			if (sts_pir_state != prev_sts_pir_state) {
    			    	sts_pir_state_changed = 1;
    			}
    			prev_sts_pir_state = sts_pir_state;
    		}
    	}
    	  // HAL_Delay(50);
    	  //__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    	// APP_LOG(TS_OFF, VLEVEL_M, "\r\nMotion Detection result=%d \r\n", sts_pir_state);
    	if ( sts_pir_state_changed == 1)
    	{
    		sts_pir_state_changed = 0;
    		UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
    	}

      break;
#endif
#if	(defined(VL53L0)||defined(VL53LX)||defined(L8))
    case TOF_INT_EXTI_PIN:
    	 ToF_EventDetected = 1;
    	 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)
  {
#ifndef	STM32WLE5xx
    HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); /* LED_BLUE */
#endif
    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;
                }
              }
              /*   switch class A/B/C  			*/
              DeviceClass_t deviceClass = CLASS_A;
              LmHandlerGetCurrentClass( &deviceClass );
              uint8_t	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(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
              break;
            case LORAWAN_USER_APP_PORT:
              if (appData->BufferSize == 1)
              {
                AppLedStateOn = appData->Buffer[0] & 0x01;
                if (AppLedStateOn == RESET)
                {
                  APP_LOG(TS_OFF, VLEVEL_H, "LED OFF\r\n");
#ifndef	STM32WLE5xx
                  HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */
#endif
                }
                else
                {
                  APP_LOG(TS_OFF, VLEVEL_H, "LED ON\r\n");
#ifndef	STM32WLE5xx
                  HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET); /* LED_RED */
#endif
                }
              }
              break;
			case YUNHORN_STS_USER_APP_CTRL_PORT:
			  if (appData->BufferSize != 1)
			  {
				if (appData->BufferSize < 128) {
					USER_APP_AUTO_RESPONDER_Parse((uint8_t*)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 */
}
void STS_SENSOR_Upload_AppData_Message(LmHandlerAppData_t stsAppdata)
{
	uint32_t nextTxIn =0;
	LmHandlerErrorStatus_t status;

	if (LmHandlerIsBusy() == false)
	{

		status = LmHandlerSend(&stsAppdata, LmHandlerParams.IsTxConfirmed, false);
		if (LORAMAC_HANDLER_SUCCESS == status)
		{
			APP_LOG(TS_ON, VLEVEL_H, "SEND REQUEST\r\n");
		}
		else if (LORAMAC_HANDLER_DUTYCYCLE_RESTRICTED == status)
		{
			nextTxIn = LmHandlerGetDutyCycleWaitTime();
			if (nextTxIn > 0)
			{
				APP_LOG(TS_ON, VLEVEL_H, "Next Tx in  : ~%d second(s)\r\n", (nextTxIn / 1000));
			}
		}

	}

}

void STS_SENSOR_Upload_Message(uint8_t appDataPort, uint8_t appBufferSize, uint8_t *appDataBuffer)
{
	LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR;
	UTIL_TIMER_Time_t nextTxIn = 0;

	if (LmHandlerIsBusy() == false)
	{

		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_H, "SEND REQUEST\r\n");
		}
		else if (LORAMAC_HANDLER_DUTYCYCLE_RESTRICTED == status)
		{
			nextTxIn = LmHandlerGetDutyCycleWaitTime();
			if (nextTxIn > 0)
			{
				APP_LOG(TS_ON, VLEVEL_H, "Next Tx in  : ~%d second(s)\r\n", (nextTxIn / 1000));
			}
		}

	}

}

static void SendTxData(void)
{
  /* USER CODE BEGIN SendTxData_1 */
  LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR;
  uint8_t batteryLevel = GetBatteryLevel();
  sensor_t sensor_data;
  UTIL_TIMER_Time_t nextTxIn = 0;
#ifdef STS_P2
  sts_people_count_sensor_data_t sts_p2_sensor_data={0x0};
#elif	defined(STS_T6)
  sts_tof_presence_detection_sensor_data_t sts_t6_sensor_data={0x0};
#elif	defined(STS_R1)||defined(STS_R1D)||defined(STS_R2)||defined(STS_R5)
  sts_tof_range_data_t sts_rr_sensor_data={0x0,0x0,0x0};
#elif	defined(STS_R4)
  sts_r_sensor_data_t sts_r4_sensor_data={0};
#elif	defined(STS_M1)
  sts_r_sensor_data_t sts_m1_sensor_data={0};
#elif	defined(STS_O5)
  STS_OO_SensorDataTypeDef oo_data;
#endif

  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;
*/
    uint32_t i = 0;
#endif /* CAYENNE_LPP */

    EnvSensors_Read(&sensor_data);

#ifdef  STS_O5
    STS_O5_SENSOR_Read(&oo_data);
#elif	defined(STS_R4)
    //UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP6), CFG_SEQ_Prio_0);
    //STS_YunhornSTSEventP6_Process();
    STS_R4_sensor_read(&sts_r4_sensor_data);
#elif	defined(STS_M1)
    STS_M1_sensor_read(&sts_m1_sensor_data);
#endif



#ifdef VL53LX
#ifdef STS_P2
    STS_people_count_sensor_Read(&sts_p2_sensor_data);
#elif defined(STS_T6)
    STS_tof_presence_detection_sensor_Read(&sts_t6_sensor_data);
#endif
#endif

#ifdef VL53L0
    //STS_YunhornSTSEventP4_Process();
    STS_RR_Sensor_Read(&sts_rr_sensor_data);
    APP_LOG(TS_OFF, VLEVEL_H, "\r\n VL53L0 sensor data read \r\n");

#ifdef STS_R1
    AppData.Port = YUNHORN_STS_R1_LORA_APP_DATA_PORT; /* STS-R1 Data Port */
#elif defined(STS_R1D)
    AppData.Port = YUNHORN_STS_R1D_LORA_APP_DATA_PORT; /* STS-R1D Data Port */
#elif defined(STS_R2)
    AppData.Port = YUNHORN_STS_R2_LORA_APP_DATA_PORT; /* STS-R2 Data Port */
#elif defined(STS_R5)
    AppData.Port = YUNHORN_STS_R5_LORA_APP_DATA_PORT; /* STS-R5 Data Port */
#endif	//STS_R1

#endif	//VL53L0

#ifdef	STS_R4		//SOAP/SANITIZER LEVEL
    AppData.Port = YUNHORN_STS_R4_LORA_APP_DATA_PORT; /* STS-R4 Data Port */

#elif	defined(STS_M1)		// WATER LEAKAGE SENSOR
    AppData.Port = YUNHORN_STS_M1_LORA_APP_DATA_PORT; /* STS-M1 Data Port */

#elif	defined(STS_O5)
    AppData.Port = YUNHORN_STS_O5_LORA_APP_DATA_PORT; /* STS-O5 Data Port */
#endif
    AppLedStateOn = LED1_STATE;
    AppData.Buffer[i++]	= (uint8_t) (AppLedStateOn|0x80);		// for first byte, cannot be 0x0
    AppData.Buffer[i++]	= (uint8_t) sts_mtmcode1;
    AppData.Buffer[i++]	= (uint8_t) sts_mtmcode2;
    AppData.Buffer[i++]	= (uint8_t) sts_hardware_ver;
    AppData.Buffer[i++]	= (uint8_t) 99*batteryLevel/254;

#if 0
    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;
#endif

#ifdef	STS_P2
    AppData.Port = YUNHORN_STS_P2_LORA_APP_DATA_PORT; /* STS-P2 Data Port */
#elif 	defined(STS_T6)
    AppData.Port = YUNHORN_STS_T6_LORA_APP_DATA_PORT; /* STS-T6 Data Port */
#elif 	defined(L8)
    AppData.Port = YUNHORN_STS_L8_LORA_APP_DATA_PORT; /* STS-L8 Data Port */

#endif

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

#if 0
    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)(temperature & 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))
    {
      AppData.Buffer[i++] = 0;
      AppData.Buffer[i++] = 0;
      AppData.Buffer[i++] = 0;
      AppData.Buffer[i++] = 0;
    }
    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);
    }

#endif  //if 0

#endif /* CAYENNE_LPP */

#ifdef STS_O5
    	AppData.Buffer[i++]	= 1;
    	AppData.Buffer[i++] = (uint8_t)(oo_data.state_sensor1_on_off);
#endif

#ifdef	VL53L0		//VL53L0

#if	(defined(STS_R1)||defined(STS_R5))
    AppData.Buffer[i++]	= 2;
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_1_distance_mm >>8 & 0xFF);
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_1_distance_mm  & 0xFF);
#elif	defined(STS_R1D)
    AppData.Buffer[i++]	= 4;
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_1_distance_mm >>8 & 0xFF);
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_1_distance_mm  & 0xFF);
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_2_distance_mm >>8 & 0xFF);
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_2_distance_mm  & 0xFF);
#elif	defined(STS_R5_EXT)
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_3_distance_mm >>8 & 0xFF);
    AppData.Buffer[i++] = (uint8_t)(sts_rr_sensor_data.tof_3_distance_mm  & 0xFF);
#endif

#endif			//VL53L0
#ifdef	STS_P2

#ifdef VL53LX	// VL53L1X
    AppData.Buffer[i++] = (uint8_t) 15;	//sum of below
     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Walk_In_People_Count>>8) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Walk_In_People_Count & 0xFF);

     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Walk_Out_People_Count>>8) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Walk_Out_People_Count & 0xFF);

     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Walk_Around_People_Count>>8) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Walk_Around_People_Count & 0xFF);
#endif			// VL53L1X
#ifdef VL53LX	// VL53L1X
     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Count_Period) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Count_Period_Unit) & 0xFF);

     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Sum_Day_Walk_In_People_Count>>8) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Sum_Day_Walk_In_People_Count & 0xFF);

     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Sum_Day_Walk_Out_People_Count>>8) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Sum_Day_Walk_Out_People_Count & 0xFF);

     AppData.Buffer[i++] = (uint8_t)((sts_p2_sensor_data.Sum_Day_Walk_Around_People_Count>>8) & 0xFF);
     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Sum_Day_Walk_Around_People_Count & 0xFF);

     AppData.Buffer[i++] = (uint8_t)(sts_p2_sensor_data.Count_Valid & 0xFF);
#endif		// VL53L1X

#endif	//STS_P2

     if ((heart_beat_timer != 0L))
     {
    	 heart_beat_timer=0;
    	 sensor_data_ready = 0;

    	 AppData.Port = (uint8_t)YUNHORN_STS_T6_LORA_APP_HTBT_PORT; //LORAWAN_USER_APP_PORT+1;
  	 	 AppData.Buffer[i++]		= (uint8_t)(AppLedStateOn|0x80)&0x0ff;
    	 AppData.Buffer[i++] 	= (uint8_t)(99*batteryLevel/254)&0xff;
     } else if ((sensor_data_ready != 0))
     {
    	 sensor_data_ready = 0;

#if	defined(STS_T6)
     AppData.Buffer[i++] = 4;
     AppData.Buffer[i++] = (uint8_t)((sts_t6_sensor_data.tof_range_presence_state & 0xFF));
     AppData.Buffer[i++] = (uint8_t)((sts_t6_sensor_data.pir_motion_sensor_state  & 0xFF));
     AppData.Buffer[i++] = (uint8_t)((sts_t6_sensor_data.lamp_bar_color  & 0xFF));
     AppData.Buffer[i++] = (uint8_t)((sts_t6_sensor_data.tof_presence_distance_dm & 0xFF));

#endif	//STS_T6

#if	defined(L8)
     AppData.Buffer[i++] = 1;
     AppData.Buffer[i++] = 8; //testing
     //(uint8_t)((sts_l8_sensor_data.tof_range_presence_state & 0xFF));

#endif	//STS_T6

/* STS-R4 SOAP LEVEL SENSOR */
#ifdef	STS_R4
     AppData.Buffer[i++]	= 2;
     AppData.Buffer[i++] 	= (uint8_t)(sts_r4_sensor_data.measure_tech & 0xFF);
     AppData.Buffer[i++] 	= (uint8_t)(sts_r4_sensor_data.on_off_event & 0xFF);
#endif	//STS_R4

/* STS-M1 WATER LEAKAGE SENSOR */
#ifdef	STS_M1
          AppData.Buffer[i++]	= 2;
          AppData.Buffer[i++] 	= (uint8_t)(sts_m1_sensor_data.measure_tech & 0xFF);
          AppData.Buffer[i++] 	= (uint8_t)(sts_m1_sensor_data.on_off_event & 0xFF);
#endif	//STS_M1
     }

    //AppData.BufferSize = (uint8_t)(i&(~sts_service_mask));
     AppData.BufferSize = (uint8_t)(sts_service_mask > STS_SERVICE_MASK_L1? 0:i)&0xff;;

#ifdef 	CLOCK_SYNC
    if( IsClockSynched == false )
    {
        status = LmhpClockSyncAppTimeReq( );

        if (LORAMAC_HANDLER_SUCCESS == status) {
        	OnSysTimeUpdate();
        }
    }
#endif

    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));
      }
    }
  }
  heart_beat_timer = 0;
  sensor_data_ready = 0;
  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 */
	if (sts_warm_up_count <= 5)
	{
  /* USER CODE END OnTxTimerEvent_1 */
	//UTIL_TIMER_Stop(&TxTimer);

#ifdef STS_R4
  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP6), CFG_SEQ_Prio_0);
#elif defined(STS_M1)
  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), CFG_SEQ_Prio_0);
#elif (defined(STS_R1D)||defined(STS_R5)||defined(STS_R1))
  APP_LOG(TS_OFF, VLEVEL_H, "\nSET TASK  P4\r\n");
  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP4), CFG_SEQ_Prio_0);

#elif (defined(STS_P2)||defined(STS_T6))
	UTIL_TIMER_Stop(&YunhornSTSWakeUpScanTimer);
	APP_LOG(TS_OFF, VLEVEL_M, "\r\nTxTimer Event \r\n");
#endif

	UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);


#if (defined(STS_P2)||defined(STS_T6))
	UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);
#endif

	sts_warm_up_count++;
  /*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");
      }
      AppData.Port = 1;
      AppData.BufferSize = 16;
      //UTIL_MEM_cpy_8((uint8_t*)AppData.Buffer, (uint8_t *)"YUNHORN168", 10);
      UTIL_MEM_cpy_8((uint8_t*)AppData.Buffer, (uint8_t *)(uint8_t*)YUNHORN_STS_PRD_STRING, sizeof(YUNHORN_STS_PRD_STRING));
      AppData.BufferSize = sizeof(YUNHORN_STS_PRD_STRING)-1;
      LmHandlerParams.IsTxConfirmed = true;
      LmHandlerErrorStatus_t status = LmHandlerSend(&AppData, LmHandlerParams.IsTxConfirmed, false);
      if (status ==LORAMAC_HANDLER_SUCCESS )  LmHandlerParams.IsTxConfirmed = false;
    }
    else
    {
      APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### = JOIN FAILED\r\n");
    }

    APP_LOG(TS_OFF, VLEVEL_H, "###### U/L FRAME:JOIN | DR:%d | PWR:%d\r\n", joinParams->Datarate, joinParams->TxPower);

  }
  UTIL_TIMER_Start(&STSLampBarColorTimer);

  UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);

  /* 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 */
	IsClockSynched = true;
  /* 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 */
}

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 */
#ifndef	STM32WLE5xx
  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 */
#endif
  /* 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 */
}


/**
  * @brief  STS Lamp Bar timer callback function
  * @param  context ptr of Lamp Bar LED context
  */
static void OnYunhornSTSLampBarColorTimerEvent(void *context)
{
	uint8_t high4=(sts_lamp_bar_color>>4)&0x0f, low4=sts_lamp_bar_color&0x0f;
#if	defined(STS_O6)||defined(STS_T6)	//||defined(O1L)
	  //UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP3), CFG_SEQ_Prio_0);

	UTIL_TIMER_Stop(&STSLampBarColorTimer);

	if (high4==0)
	{
		STS_Lamp_Bar_Set_STS_RGB_Color(sts_lamp_bar_color, luminance_level);

	} else
	{
		STS_Lamp_Bar_Set_STS_RGB_Color(r_b?high4:low4, luminance_level);
		r_b = !r_b;
	}


	  UTIL_TIMER_Start(&STSLampBarColorTimer);
#endif
}

/**
  * @brief  SYS occupancy, door lock, motion duration check timer callback function
  * @param  context ptr of duration check context
  */
#if 0
static void OnYunhornSTSDurationCheckTimerEvent(void *context)
{
#ifdef STS_O6

#endif
}
#endif
/**
  * @brief  Yunhorn STS Occupancy RSS WakeUP timer callback function
  * @param  context ptr of STS RSS WakeUp context
  */
#ifdef STS_O6
static void OnYunhornSTSOORSSWakeUpTimerEvent(void *context)
{


}
#endif
/**
  * @brief  Yunhorn STS Heart beat timer callback function
  * @param  context ptr of context
  */

static void OnYunhornSTSHeartBeatTimerEvent(void *context)
{
//	  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), CFG_SEQ_Prio_0);
	UTIL_TIMER_Stop(&YunhornSTSHeartBeatTimer);

	uint8_t appHeartBeatDataPort=2, appHeartBeatBufferSize=2, appHeartBeatDataBuffer[32]={0x0};

    if ((rfac_timer <(STS_BURN_IN_RFAC+3))&&(sts_cfg_nvm.ac[0]==0x0)&&(sts_cfg_nvm.ac[19]==0x0))
    {
    	//APP_LOG(TS_OFF, VLEVEL_M, "\n\n RFAC_TIMER = %d\n\n", rfac_timer);

    	//STS_YunhornSTSEventRFAC_Process();
    	// the following doesn't executed
#if 1
    	//APP_LOG(TS_OFF, VLEVEL_M, "\n Start send RFAC request \n");
    	appHeartBeatBufferSize = 4;
    	UTIL_MEM_cpy_8((uint8_t*)appHeartBeatDataBuffer,"RFAC",4);
        STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, appHeartBeatBufferSize, (uint8_t*)appHeartBeatDataBuffer);
#endif
  			rfac_timer ++;
    } else { // normal heart-beat process

#if 1
#ifdef STS_P2
	appHeartBeatDataPort = YUNHORN_STS_P2_LORA_APP_HTBT_PORT;
#elif defined(STS_R1)
	appHeartBeatDataPort = YUNHORN_STS_R1_LORA_APP_HTBT_PORT;
#elif defined(STS_R1D)
	appHeartBeatDataPort = YUNHORN_STS_R1D_LORA_APP_HTBT_PORT;
#elif defined(STS_R5)
	appHeartBeatDataPort = YUNHORN_STS_R5_LORA_APP_HTBT_PORT;
#elif defined(STS_R4)
	appHeartBeatDataPort = YUNHORN_STS_R4_LORA_APP_HTBT_PORT;
#elif defined(STS_T6)
	appHeartBeatDataPort = YUNHORN_STS_T6_LORA_APP_HTBT_PORT;
#elif defined(STS_O5)
	appHeartBeatDataPort = YUNHORN_STS_O5_LORA_APP_HTBT_PORT;
#elif defined(STS_M1)
	appHeartBeatDataPort = YUNHORN_STS_M1_LORA_APP_HTBT_PORT;
#endif

	appHeartBeatBufferSize = 2;
	appHeartBeatDataBuffer[0]=(uint8_t)(0x80|AppLedStateOn);
	appHeartBeatDataBuffer[1]=(uint8_t)(SYS_GetBatteryLevel()/100);  //TODO XXX change to battery level in mV
	//APP_LOG(TS_OFF, VLEVEL_M, "\n\n HEART-BEAT TIMER = %d\n\n", rfac_timer);
    STS_SENSOR_Upload_Message(appHeartBeatDataPort, appHeartBeatBufferSize, (uint8_t*)appHeartBeatDataBuffer);

#endif

    }

	UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);
}


/**
  * @brief  Yunhorn STS Heart Beat Periodicity Chagne function
  * @param  duration of periodicty in ms (1/1000 sec)
  */
void OnYunhornSTSHeartBeatPeriodicityChanged(uint32_t periodicity)
{
  /* USER CODE BEGIN OnYunhornSTSHeartBeatPeriodicityChanged_1 */

  /* USER CODE END OnYunhornSTSHeartBeatPeriodicityChanged_1 */

  if (periodicity == 0)
  {
    /* Revert to application default Heat-beat periodicity */
	  periodicity = 10*APP_TX_DUTYCYCLE;		//10*10 000 ms
  }

  /* Update timer YunhornSTSHeartBeatTimer */

	  UTIL_TIMER_Stop(&YunhornSTSHeartBeatTimer);
	  UTIL_TIMER_SetPeriod(&YunhornSTSHeartBeatTimer, periodicity);
	  UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);

  /* USER CODE BEGIN OnYunhornSTSHeartBeatPeriodicityChanged_2 */
  APP_LOG(TS_OFF, VLEVEL_M,"* STS HeartBeatPeriodicity = %u (sec)\r\n", periodicity/1000 );

  /* USER CODE END OnYunhornSTSHeartBeatPeriodicityChanged_2 */
}

/* USER CODE BEGIN PrFD_YunhornSTSWakeUpScanTimerEvents */
static void OnYunhornSTSWakeUpScanTimerEvent(void *context)
{
#if	defined(STS_P2)||defined(STS_T6)||defined(L8)
	UTIL_TIMER_Stop(&YunhornSTSWakeUpScanTimer);

  UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP5), CFG_SEQ_Prio_0);

  UTIL_TIMER_Start(&YunhornSTSWakeUpScanTimer);
#endif

}

/**
  * @brief  Yunhorn STS Tx Periodicity Change function
  * @param  duration of periodicty in ms (1/1000 sec)
  */
void OnYunhornSTSTxPeriodicityChanged(uint32_t periodicity)
{
  /* USER CODE BEGIN OnYunhornSTSTxPeriodicityChanged */

  /* USER CODE END OnYunhornSTSTxPeriodicityChanged */

  /* Update timer OnYunhornSTSTxPeriodicityChanged */
	OnTxPeriodicityChanged(periodicity);
	/*
	  UTIL_TIMER_Stop(&TxTimer);
	  TxPeriodicity = periodicity;
	  UTIL_TIMER_SetPeriod(&TxTimer, TxPeriodicity);
	  UTIL_TIMER_Start(&TxTimer);
	  */

  /* USER CODE BEGIN OnYunhornSTSTxPeriodicityChanged */

  APP_LOG(TS_OFF, VLEVEL_H,"\n* STS TxPeriodicity = %u (sec)\r\n", TxPeriodicity/1000 );

  /* USER CODE END OnYunhornSTSTxPeriodicityChanged */
}


void OnStoreSTSCFGContextRequest(void)
{
  /* USER CODE BEGIN OnStoreContextRequest_1 */
#if 0
	uint8_t i=0,j=0;
	uint8_t to_store__value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};  /*  KEEP THIS LOCAL */
	sts_cfg_nvm.length   = STS_NVM_CFG_SIZE;
	to_store__value[i++] = sts_cfg_nvm.mtmcode1;
	to_store__value[i++] = sts_cfg_nvm.mtmcode2;
	to_store__value[i++] = sts_cfg_nvm.version;
	to_store__value[i++] = sts_cfg_nvm.hardware_ver;
	to_store__value[i++] = sts_cfg_nvm.periodicity;
	to_store__value[i++] = sts_cfg_nvm.unit;
	to_store__value[i++] = sts_cfg_nvm.sampling;
	to_store__value[i++] = sts_cfg_nvm.s_unit;
	to_store__value[i++] = sts_cfg_nvm.work_mode;
	to_store__value[i++] = sts_cfg_nvm.sts_service_mask;
	to_store__value[i++] = sts_cfg_nvm.sts_ioc_mask;
	to_store__value[i++] = (uint8_t) STS_CFG_PCFG_SIZE; //sts_cfg_nvm.length;

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

	to_store__value[i++] = sts_cfg_nvm.color_occupy_vacant;
	to_store__value[i++] = sts_cfg_nvm.sts_door_jam_profile;
	to_store__value[i++] = sts_cfg_nvm.sensor_install_height_in_10cm;
	to_store__value[i++] = sts_cfg_nvm.alarm_parameter05;
	to_store__value[i++] = sts_cfg_nvm.alarm_mute_reset_timer_in_10sec;
	to_store__value[i++] = sts_cfg_nvm.alarm_lamp_bar_flashing_color;
	to_store__value[i++] = sts_cfg_nvm.occupancy_overtime_threshold_in_10min;

	to_store__value[i++] = sts_cfg_nvm.motionless_duration_threshold_in_min;
	to_store__value[i++] = sts_cfg_nvm.unconscious_or_motionless_level_threshold;
	to_store__value[i++] = sts_cfg_nvm.fall_detection_acc_threshold;
	to_store__value[i++] = sts_cfg_nvm.fall_detection_depth_threshold;
	to_store__value[i++] = sts_cfg_nvm.fall_confirm_threshold_in_10sec;

	if ((nvm_stored_value[NVM_AC_CODE_START]!= 0x0) && (nvm_stored_value[NVM_AC_CODE_START+19]!=0x0))
	{
		//APP_LOG(TS_OFF, VLEVEL_M, "\n\r Transfer good NVM Stored ac_code to NVM_STORE_VALUE\r\n");
		UTIL_MEM_cpy_8((void*)&to_store__value[NVM_AC_CODE_START], (void*)&nvm_store_value[NVM_AC_CODE_START],YUNHORN_STS_AC_CODE_SIZE);
	} else if ((sts_ac_code[0]!=0x0) && (sts_ac_code[YUNHORN_STS_AC_CODE_SIZE-1]!=0x0))
	{
		//APP_LOG(TS_OFF, VLEVEL_M, "\n\r Transfer new generated ac_code to NVM_STORE_VALUE\r\n");
		UTIL_MEM_cpy_8((void*)&to_store__value[NVM_AC_CODE_START], (void*)sts_ac_code,YUNHORN_STS_AC_CODE_SIZE);
		UTIL_MEM_cpy_8((void*)&nvm_store_value[NVM_AC_CODE_START], (void*)sts_ac_code,YUNHORN_STS_AC_CODE_SIZE);
	}
#endif
  /* USER CODE END OnStoreContextRequest_1 */
  /* store nvm in flash */
	//if ((sts_ac_code[0] != 0 ) && (sts_ac_code[YUNHORN_STS_AC_CODE_SIZE-1] !=0))
	{
		for (uint8_t j=0; j<YUNHORN_STS_AC_CODE_SIZE; j++)
		{
			//sts_ac_code[j]	= sts_cfg_nvm.ac[j];
			sts_cfg_nvm_factory_default[NVM_AC_CODE_START+j] = sts_ac_code[j];
		}
	}
	STS_Show_STS_CFG_NVM((uint8_t*)sts_cfg_nvm_factory_default, YUNHORN_STS_MAX_NVM_CFG_SIZE);

	UTIL_MEM_cpy_8((void*)nvm_stored_value,(void*)&sts_cfg_nvm, sizeof(sts_cfg_nvm));
	UTIL_MEM_cpy_8((void*)(nvm_stored_value + YUNHORN_STS_MAX_NVM_CFG_SIZE), (const void*)sts_cfg_nvm_factory_default, sizeof(sts_cfg_nvm_factory_default));

	STS_Show_STS_CFG_NVM((uint8_t*)nvm_stored_value, 2*YUNHORN_STS_MAX_NVM_CFG_SIZE);

  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_stored_value, 2*YUNHORN_STS_MAX_NVM_CFG_SIZE);
  }

  /* USER CODE BEGIN OnStoreContextRequest_Last */


  /* USER CODE END OnStoreContextRequest_Last */
}

void OnRestoreSTSCFG_FactoryDefault_ContextRequest(void)
{
	//uint8_t nvm_store_value[2*YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};

	APP_LOG(TS_OFF, VLEVEL_M, "Restore Factory Default NVM ********************** \r\n");

  /* USER CODE END OnRestoreSTSCFGContextRequest_1 */
	FLASH_IF_Read((void*)sts_cfg_nvm_factory_default, (void*)STS_CONFIG_NVM_BASE_ADDRESS+YUNHORN_STS_MAX_NVM_CFG_SIZE, YUNHORN_STS_MAX_NVM_CFG_SIZE);

	UTIL_MEM_cpy_8((void*)nvm_stored_value, (void*)sts_cfg_nvm_factory_default, YUNHORN_STS_MAX_NVM_CFG_SIZE);
	UTIL_MEM_cpy_8((void*)&nvm_stored_value+YUNHORN_STS_MAX_NVM_CFG_SIZE, (void*)sts_cfg_nvm_factory_default, YUNHORN_STS_MAX_NVM_CFG_SIZE);

	STS_Show_STS_CFG_NVM((uint8_t*)nvm_stored_value, sizeof(nvm_stored_value));


	if (FLASH_IF_Erase(STS_CONFIG_NVM_BASE_ADDRESS, FLASH_PAGE_SIZE) == FLASH_IF_OK)
	  {
		  APP_LOG(TS_OFF, VLEVEL_M, "\r\n %%%%% write CFG to normal NVM \r\n");

	      FLASH_IF_Write(STS_CONFIG_NVM_BASE_ADDRESS, (const void *)nvm_stored_value, 2*YUNHORN_STS_MAX_NVM_CFG_SIZE);
	      //FLASH_IF_Write(FLASH_MFG_DEFAULT_START_ADDR, (const void *)sts_cfg_nvm_factory_default, YUNHORN_STS_MAX_NVM_CFG_SIZE);

		  //sts_cfg_nvm_factory_default[0] = 0xF3;		// with valid ac code
	  }

}

void OnRestoreSTSCFGContextRequest(void *cfg_in_nvm)
{
  /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_1 */

  /* USER CODE END OnRestoreSTSCFGContextRequest_1 */
  UTIL_MEM_cpy_8((void*)cfg_in_nvm, (void *)STS_CONFIG_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE);
  /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_Last */

  /* USER CODE END OnRestoreSTSCFGContextRequest_Last */
}

void OnRestoreSTSLOGContextRequest(void *log_in_nvm)
{
  /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_1 */

  /* USER CODE END OnRestoreSTSCFGContextRequest_1 */
  UTIL_MEM_cpy_8((void*)log_in_nvm, (void *)STS_SENSOR_DATA_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE);
  /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_Last */

  /* USER CODE END OnRestoreSTSCFGContextRequest_Last */
}

void STS_REBOOT_CONFIG_Init(void)
{
  /* USER CODE BEGIN OnRestoreContextRequest_1 */
	//uint8_t nvm_store_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};
  /* USER CODE END OnRestoreContextRequest_1 */
	FLASH_IF_Read((void*)nvm_stored_value, STS_CONFIG_NVM_BASE_ADDRESS, 2*YUNHORN_STS_MAX_NVM_CFG_SIZE);

	STS_Show_STS_CFG_NVM((uint8_t*)nvm_stored_value, sizeof(nvm_stored_value));
  /* USER CODE BEGIN OnRestoreContextRequest_Last */

	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_M, "Initial Boot with Empty Config, Flash with default config....\r\n");
		UTIL_MEM_cpy_8((void*)sts_cfg_nvm_factory_default, (void*)&sts_cfg_nvm, (sizeof(sts_cfg_nvm)-YUNHORN_STS_AC_CODE_SIZE));
		OnStoreSTSCFGContextRequest();
		//UTIL_MEM_set_8((void *)sts_ac_code, 0x00, YUNHORN_STS_AC_CODE_SIZE);
		HAL_Delay(1000);
		//__set_FAULTMASK(1);
		//NVIC_SystemReset();
	} else
	{
		UTIL_MEM_cpy_8((void*)sts_cfg_nvm_factory_default, (void*)(nvm_stored_value+YUNHORN_STS_MAX_NVM_CFG_SIZE), YUNHORN_STS_MAX_NVM_CFG_SIZE);
		sts_cfg_nvm.mtmcode1 			= (uint8_t)nvm_stored_value[NVM_MTM1];
		sts_cfg_nvm.mtmcode2 			= (uint8_t)nvm_stored_value[NVM_MTM2];
		sts_cfg_nvm.version 			= (uint8_t)nvm_stored_value[NVM_VER];
		sts_cfg_nvm.hardware_ver  		= (uint8_t)nvm_stored_value[NVM_HWV];
		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.sts_ioc_mask			= (uint8_t)(nvm_stored_value[NVM_IOC_MASK]);
		sts_cfg_nvm.length 				= (uint8_t)(nvm_stored_value[NVM_LEN]&0x3F);		//MAX 32 bytes

		for (uint8_t j=0; j< STS_CFG_PCFG_SIZE; j++) {
			sts_cfg_nvm.p[j] 				= (uint8_t)nvm_stored_value[NVM_CFG_START+j];
		}

		sts_cfg_nvm.color_occupy_vacant		=(uint8_t)nvm_stored_value[NVM_RESERVE02];
		sts_cfg_nvm.sts_door_jam_profile	=(uint8_t)nvm_stored_value[NVM_RESERVE03];
		sts_cfg_nvm.sensor_install_height_in_10cm			=(uint8_t)nvm_stored_value[NVM_SENSOR_INSTALL_HEIGHT];
		sts_cfg_nvm.alarm_parameter05			=(uint8_t)nvm_stored_value[NVM_ALARM_PARAMETER05];
		sts_cfg_nvm.alarm_mute_reset_timer_in_10sec = (uint8_t)nvm_stored_value[NVM_ALARM_MUTE_RESET_TIMER];
		sts_cfg_nvm.alarm_lamp_bar_flashing_color = (uint8_t)nvm_stored_value[NVM_ALARM_LAMP_BAR_FLASHING_COLOR];
		sts_cfg_nvm.occupancy_overtime_threshold_in_10min = (uint8_t)nvm_stored_value[NVM_OCCUPANCY_OVERTIME_THRESHOLD];
		sts_cfg_nvm.motionless_duration_threshold_in_min= (uint8_t)nvm_stored_value[NVM_MOTIONLESS_DURATION_THRESHOLD];
		sts_cfg_nvm.unconscious_or_motionless_level_threshold 		= (uint8_t)nvm_stored_value[NVM_UNCONSCIOUS_LEVEL_THRESHOLD];
		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_confirm_threshold_in_10sec		= (uint8_t)nvm_stored_value[NVM_FALL_CONFIRM_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];
		}

	}
	STS_Show_STS_CFG_NVM((uint8_t*)nvm_stored_value, sizeof(nvm_stored_value));
	OnRestoreSTSCFGContextProcess();

  /* USER CODE END OnRestoreContextRequest_Last */
}

void OnRestoreSTSCFGContextProcess(void)
{
	uint32_t periodicity = (sts_cfg_nvm.periodicity);		//TxPeriodicty interval
	if ((char)sts_cfg_nvm.unit =='M') {
		periodicity *= 60;
	} else if ((char) sts_cfg_nvm.unit =='H') {
		periodicity *= 3600;
	} else if ((char) sts_cfg_nvm.unit =='S') {
		periodicity *= 1;
	}
	periodicity = (periodicity > 10)? periodicity : 10;		// in seconds unit

	//APP_LOG(TS_OFF, VLEVEL_M, "\n\n Tx periodicity in NVM =%u sec\n",periodicity);

	TxPeriodicity= periodicity*1000;  // to ms

	uint32_t sampling_heartbeat_periodicity = (sts_cfg_nvm.sampling);		//Heart-beat or Sampling interval
	if ((char)sts_cfg_nvm.s_unit =='M') {
		sampling_heartbeat_periodicity *= 60;
	} else if ((char) sts_cfg_nvm.s_unit =='H') {
		sampling_heartbeat_periodicity *= 3600;
	} else if ((char) sts_cfg_nvm.s_unit =='S') {
		sampling_heartbeat_periodicity *= 1;
	} else if ((char) sts_cfg_nvm.s_unit =='L') {
		sampling_heartbeat_periodicity *= 100;
	}

	STS_HeartBeatTimerPeriod_sec = sampling_heartbeat_periodicity;
	APP_LOG(TS_OFF, VLEVEL_H, "\n\n sampling or heartbeat periodicity in NVM =%u sec\n",sampling_heartbeat_periodicity);



	if ((sts_cfg_nvm.ac[0] ==0x0 )&& (sts_cfg_nvm.ac[19]==0x0))
	{															// ensure it's not in production yet

		OnYunhornSTSTxPeriodicityChanged(APP_TX_DUTYCYCLE);				// in msec unit
		OnYunhornSTSHeartBeatPeriodicityChanged(STS_HeartBeatTimerPeriod_sec); 	//TODO XXXX

		//OnTxPeriodicityChanged(10000);				// APP_TX_DUTYCYCLE in msec unit
		//TxPeriodicity = APP_TX_DUTYCYCLE;

	} else
	{
		//OnYunhornSTSTxPeriodicityChanged(TxPeriodicity);				// in msec unit
		//OnTxPeriodicityChanged(TxPeriodicity);
		//Heart-beat or Sampling interval
		//sampling_heartbeat_periodicity = (sampling_heartbeat_periodicity > 0)? sampling_heartbeat_periodicity : 1;		// in seconds unit
		//sampling_heartbeat_periodicity = sampling_heartbeat_periodicity*1000;
#ifdef STS_P2
		STS_TxPeriod_sec			 = periodicity;
		STS_HeartBeatTimerPeriod_sec = sampling_heartbeat_periodicity;
		sts_people_count_sensor_data->Count_Period 		= sts_cfg_nvm.periodicity;
		sts_people_count_sensor_data->Count_Period_Unit 	= sts_cfg_nvm.unit;
#endif

#if	defined(STS_T6)
		STS_HeartBeatTimerPeriod_sec = periodicity;
		OnYunhornSTSHeartBeatPeriodicityChanged(STS_HeartBeatTimerPeriod_sec);
#endif

#if	defined(STS_R1)||defined(STS_R5)||defined(STS_R4)||defined(STS_R1D)||defined(STS_O5)||defined(STS_M1)
	OnYunhornSTSHeartBeatPeriodicityChanged(sampling_heartbeat_periodicity*1000);
#endif
	}

	sts_work_mode	= sts_cfg_nvm.work_mode;
	sts_service_mask = sts_cfg_nvm.sts_service_mask;
	sts_door_jam_profile = sts_cfg_nvm.sts_door_jam_profile;
	sts_color_occupy_vacant = sts_cfg_nvm.color_occupy_vacant;
	APP_LOG(TS_OFF, VLEVEL_M, "\r\n Color Occupy =%02x, VACANT =%02x \r\n",((sts_color_occupy_vacant>>4)&0x0f), sts_color_occupy_vacant&0x0f );

#ifdef YUNHORN_STS_O6_ENABLED
	sts_lamp_bar_color = STS_COLOR_DEFAULT_VACANT;
	sts_fall_detection_acc_threshold 	= (uint8_t)sts_cfg_nvm.fall_detection_acc_threshold*10;
	sts_fall_detection_depth_threshold 	= (uint8_t)sts_cfg_nvm.fall_detection_depth_threshold*10;		//in cm
	// ****								= sts_cfg_nvm.fall_detection_reserve;
	sts_occupancy_overtime_threshold 	= (uint8_t)sts_cfg_nvm.occupancy_overtime_threshold*10;			// minutes
#endif


	for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++)
	{
		sts_ac_code[j] = sts_cfg_nvm.ac[j];
	}
	//for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++)
	//{
	//		sts_ac_code[j] = sts_cfg_nvm.ac[j];
	//}
	//UTIL_MEM_cpy_8((void*)sts_ac_code,(void*)sts_cfg_nvm.ac, YUNHORN_STS_AC_CODE_SIZE);

#ifdef YUNHORN_STS_O6_ENABLED
	if ((sts_version == sts_cfg_nvm.version)&& (NVM_CFG_PARAMETER_SIZE == sts_cfg_nvm.length))
	{
		STS_PRESENCE_SENSOR_Init();
		STS_PRESENCE_SENSOR_RSS_Init();
	}
#endif

}

static void STS_Show_STS_CFG_NVM(uint8_t * store_value, uint16_t store_size)
{
	APP_LOG(TS_OFF, VLEVEL_M, "\n-----------------------------------------------\n");
	APP_LOG(TS_OFF, VLEVEL_M, "\n00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n");
	for (uint16_t i=0; i< store_size; i++)
	{
		if (i%16==0) APP_LOG(TS_OFF, VLEVEL_M, "\n");
		APP_LOG(TS_OFF, VLEVEL_M, "%02X ", store_value[i]);

	}
	APP_LOG(TS_OFF, VLEVEL_M, "\n\r");
	APP_LOG(TS_OFF, VLEVEL_M, "\n###############################################\n\r");
}