/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    yunhorn_sts_process.c      									   *   
  * @author  Yunhorn (r) Technology Limited Application Team	               *
  * @brief   Yunhorn (r) SmarToilets (r) Product configuration file.		   *
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 Yunhorn Technology Limited.
  * Copyright (c) 2022 Shenzhen Yunhorn Technology Co., Ltd.
  * 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 "stdint.h"
#include "platform.h"
#include "sys_conf.h"
#include "sys_app.h"
#include "stdio.h"
#include "stm32_systime.h"
#include "adc_if.h"
#include "gpio.h"
#include "LmHandler.h"
#include "app_tof.h"
#include "lora_app.h"
#include "yunhorn_sts_prd_conf.h"
#include "yunhorn_sts_sensors.h"
#include "sts_cmox_hmac_sha.h"
#include "flash_if.h"
#include "lora_app.h"
/* USER CODE BEGIN Includes */
#include "main.h"
#include "stm32_seq.h"
#include "stm32_timer.h"
#include "utilities_def.h"
#ifdef	VL53L0
#include "X-WL55_WLE5_53L0X.h"
#endif
#if	defined(STS_P2)||defined(STS_T6)
#include "app_tof.h"
#include "app_tof_peoplecount.h"
extern volatile uint8_t sts_door_jam_profile;
extern volatile uint8_t sts_tof_presence_state_changed;
#elif defined(L8)
#include "app_tof.h"
#endif
volatile sts_cfg_nvm_t sts_cfg_nvm = {
		sts_mtmcode1,
		sts_mtmcode2,
		sts_version,
		sts_hardware_ver,
		0x05,		//Regular TxPeriodicity interval
		'M', 		//Uplink data interval unit,  for heart-beat uplink
#if	defined(STS_P2)||defined(L8)||defined(STS_O6T)||defined(STS_T6)
		0x01,		//Heart-beat interval or Sampling interval
		'S', 		//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
		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]
		},			// above  20 bytes
		0x00,		//reserve2
		0x00,		//reserve3
		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}
};
volatile uint8_t nvm_store_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};
volatile uint8_t sts_ac_code[20]={0x0};
volatile uint8_t sts_service_mask=STS_SERVICE_MASK_L0;
volatile uint8_t sts_work_mode=4;
volatile uint32_t rfac_timer=0;
volatile uint16_t sts_sensor_install_height=3000;
volatile uint8_t sensor_data_ready=0;

#if	defined(STS_R1)||defined(STS_R5)||defined(STS_R4)||defined(STS_R1D)
volatile uint32_t STS_TxPeriod_sec=30, STS_HeartBeatTimerPeriod_sec=3600;
#elif	defined(STS_L8)||defined(STS_P2)||defined(STS_O6T)||defined(STS_T6)
volatile uint32_t STS_TOFScanPeriod_msec=5000, STS_TxPeriod_sec=10, STS_HeartBeatTimerPeriod_sec=300;
#endif

static uint8_t outbuf[128]={0x0};
extern volatile hmac_result_t hmac_result;
extern uint16_t sensor_id;
extern UTIL_TIMER_Time_t TxPeriodicity;
extern UTIL_TIMER_Object_t YunhornSTSHeartBeatTimer;
static void STS_Show_STS_CFG_NVM(uint8_t * nvm_store_value);
#ifdef VL53L0
extern volatile int sts_tof_distance_data[MAX_TOF_COUNT];
volatile sts_tof_range_data_t sts_range_sensor_data={0x0,0x0,0x0};
#endif
#if	defined(STS_P2)
volatile uint8_t sts_door_jam_profile = 0;
#endif
#ifdef STS_R4
volatile uint8_t sts_soap_level_state=0;
void STS_R4_sensor_read(sts_r_sensor_data_t *sts_r_sensor_data);
#endif
#ifdef	STS_M1
volatile uint8_t sts_water_leakage_state=0;
#endif
#if 0
volatile uint8_t sts_reed_hall_result, last_sts_reed_hall_result,sts_reed_hall_changed_flag;
volatile uint32_t event_start_time, event_stop_time;
volatile uint8_t sts_soap_level_state;
extern volatile uint8_t sts_reed_hall_result, sts_work_mode, sts_service_mask;
volatile uint8_t sts_reed_hall_ext_int = 0;
volatile uint8_t sts_occupancy_status;
volatile uint8_t sts_reed_hall_changed_flag = 0;
volatile uint8_t sts_reed_hall_result =0;
volatile uint8_t sts_water_leakage_result=0;
volatile uint8_t sts_water_leakage_changed_flag=0;
#endif



#if (defined(YUNHORN_STS_O6_ENABLED) && defined(USE_ACCONEER_A111))
extern volatile STS_OO_RSS_SensorTuneDataTypeDef sts_presence_rss_config;
extern volatile uint8_t sts_rss_result, sts_rss_2nd_result;
extern volatile distance_measure_cfg_t distance_cfg;
volatile uint8_t sts_work_mode = STS_DUAL_MODE;
extern uint8_t luminance_level;
extern volatile uint8_t sts_status_color;
extern volatile uint8_t sts_lamp_bar_color;		//puColor
extern volatile uint8_t sts_cloud_netcolor;		//netColor

volatile uint8_t sts_tof_result_changed_flag = 0;

volatile uint8_t sts_rss_result_changed_flag = 0;
volatile uint8_t sts_rss_result = STS_RESULT_NO_MOTION;
volatile uint8_t sts_rss_2nd_result = STS_RESULT_NO_MOTION;		//2nd RSS sensor status
volatile uint8_t sts_tof_result = STS_RESULT_NO_MOTION;
volatile uint8_t last_sts_rss_result;
extern volatile uint8_t last_sts_rss_result;
extern volatile uint8_t last_sts_reed_hall_result;
extern volatile uint8_t last_lamp_bar_color;
extern volatile float sts_presence_rss_distance;

#endif   


/*
  	    // UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP4), CFG_SEQ_Prio_0);
	  	// P1    --- REEDSWITCH, HALL ELEMENT, WATER LEAKAGE
	   	// P2    --- SEE ABOVE, RSS PRESENCE
	   	// P3    ----LAMP BAR SCOLLER PROCESS
	   	// P4    --- TOF DISTANCE  VL53L0X simple distance
	   	// P5    --- TOF IN OUT COUNT  VL53L3X in out or duration
	   	// P6    --- SOAP Level, capacitive measurement
	   	// P7    --- UltraSonic, 2nd wave UltraSonic range measure
	   	// P8    --- AIR QUALITY AND ODOR LEVEL, SMOKING DETECTION
*/


/* USER CODE END Includes */

/* External variables ---------------------------------------------------------*/
/* USER CODE BEGIN EV */
//extern UTIL_TIMER_Object_t YunhornSTSHeartBeatTimer;
/* USER CODE END EV */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */

/* Exported functions --------------------------------------------------------*/

/* 			initiated by AUTO RESPOND PARSE PROCESS		*/
void STS_YunhornAuthenticationCode_Process(void)
{
	if (sts_hmac_verify() != 0)	//Mismatch position =0, Passed, else failed
	{
		sts_service_mask = STS_SERVICE_MASK_L2;
		sts_cfg_nvm.ac[0] = 0x0;
		sts_cfg_nvm.ac[19]= 0x0;
	} else {
		sts_service_mask = STS_SERVICE_MASK_L0;
	}
	//APP_LOG(TS_OFF, VLEVEL_H, "STS_SERVICE_MASK:%d \r\n",sts_service_mask);
}

/* 			initiated by Heart-beat timer		*/
void STS_YunhornSTSEventRFAC_Process(void)
{
	if ((sts_cfg_nvm.ac[0]==0x0)&&(sts_cfg_nvm.ac[19]==0x0))
	{
		if ((rfac_timer >= STS_BURN_IN_RFAC) && (rfac_timer < (STS_BURN_IN_RFAC +3)))
		{
			//APP_LOG(TS_OFF, VLEVEL_M, "\r\n -RFAC Process\r\n");
			STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, 4, (uint8_t*)"RFAC");
		}
	}
#if 1
	if ((rfac_timer > (STS_BURN_IN_RFAC + 3)))
	{
		//APP_LOG(TS_OFF, VLEVEL_M, "\r\n -Verify RFAC Success or Not\r\n");
		STS_YunhornAuthenticationCode_Process();
	}
#endif
}

/*
 *  STS-P1    --- REEDSWITCH, HALL ELEMENT, WATER LEAKAGE
 */

void STS_YunhornSTSEventP1_Process(void)
{

#if defined(YUNHORN_STS_O5_ENABLED)

	if ((sts_work_mode == STS_WIRED_MODE) || (sts_work_mode == STS_REEDSWITCH_MODE) || (sts_work_mode == STS_DUAL_MODE))
		{
			STS_Reed_Hall_Presence_Detection();

			if (sts_reed_hall_result == last_sts_reed_hall_result) {
				sts_reed_hall_changed_flag = 0;
			} else {
				sts_reed_hall_changed_flag = 1;
#ifdef LED_ONBOARD
				STS_Combined_Status_Processing();
#endif
			}

			last_sts_reed_hall_result = sts_reed_hall_result;
		}

#endif
#if (defined(YUNHORN_STS_O6_ENABLED) && defined(USE_ACCONEER_A111))
	if ((sts_work_mode == STS_WIRED_MODE) || (sts_work_mode == STS_REEDSWITCH_MODE) || (sts_work_mode == STS_DUAL_MODE))
	{
		STS_Reed_Hall_Presence_Detection();

		if (sts_reed_hall_result == last_sts_reed_hall_result) {
			sts_reed_hall_changed_flag = 0;
		} else {
			sts_reed_hall_changed_flag = 1;
			STS_Combined_Status_Processing();
		}

		last_sts_reed_hall_result = sts_reed_hall_result;
	}
#endif

/* STS-M1 Water leakage sensor */

#if	defined(STS_M1)
	APP_LOG(TS_OFF, VLEVEL_M, "\r\n WATER LEAKAGE DETECTION Process \n");
	sts_water_leakage_state = WATER_LEAKAGE_DATA;
#endif

}


/*
 *  STS-P2    --- SEE ABOVE, RSS PRESENCE
 */
void STS_YunhornSTSEventP2_Process(void)
{
#if (defined(YUNHORN_STS_O6_ENABLED) && defined(USE_ACCONEER_A111))
	if ((sts_work_mode >= STS_RSS_MODE) && (sts_work_mode <= STS_TOF_RSS_MODE))
	{
		STS_RSS_Smart_Presence_Detection();
		STS_Reed_Hall_Presence_Detection();

		if (sts_rss_result == last_sts_rss_result) {
			sts_rss_result_changed_flag =0;
		} else 	{
			sts_rss_result_changed_flag =1;
		}

		if (sts_reed_hall_result == last_sts_reed_hall_result)
		{
			sts_reed_hall_changed_flag = 0;

		} else
		{
			sts_reed_hall_changed_flag = 1;
		}

		STS_Combined_Status_Processing();

		last_sts_rss_result = sts_rss_result;
		last_sts_reed_hall_result = sts_reed_hall_result;
	}
#endif
}

void STS_Reed_Hall_Presence_Detection(void)
{
#if (defined(YUNHORN_STS_O5_ENABLED) || defined(YUNHORN_STS_O6_ENABLED) || defined(USE_ACCONEER_A111))
	HAL_Delay(50);										// BOUNCING ELIMIATION
	if (STS_Reed_Hall_State == STS_Status_Door_Open)
	{
		sts_reed_hall_result = STS_Status_Door_Open;

	} else if (STS_Reed_Hall_State == STS_Status_Door_Close)
	{
		sts_reed_hall_result = STS_Status_Door_Close;

	}
	HAL_Delay(20);										// BOUNCING ELIMIATION
	sts_reed_hall_changed_flag = 0;
	sts_reed_hall_ext_int = 0;
#endif
}

void STS_RSS_Smart_Presence_Detection(void)
{
#if (defined(YUNHORN_STS_O6_ENABLED) && defined(USE_ACCONEER_A111))
	sts_presence_rss_pressence_detection();
#endif
}

/*
 *  STS P3 process, Lamp Bar Scoller
 */
void STS_YunhornSTSEventP3_Process(void)
{
#if (defined(YUNHORN_STS_O6_ENABLED) && defined(USE_ACCONEER_A111))
		if (STS_Reed_Hall_State == STS_Status_Door_Open)
		{
			sts_lamp_bar_color =STS_GREEN;
		}
		else
		{
			sts_lamp_bar_color =STS_RED;
		}
		STS_Lamp_Bar_Scoller(sts_lamp_bar_color, luminance_level);
#endif
}

/*
 *  STS-P4 Detection ToF distance (VL53L0X)
 *
 */
void STS_YunhornSTSEventP4_Process(void)
{
	//STS_SENSOR_Power_ON(0);
	//HAL_Delay(10);
#ifdef	LED_ONBOARD
	LED_ON;
	HAL_Delay(10);
	LED_OFF;
#endif
#if defined(TOF_1)||defined(TOF_2)||defined(VL53L0)
	APP_LOG(TS_OFF, VLEVEL_H, "\r\n TOF_1, TOF_2 RANGING Process\r\n");
	PME_ON;
	STS_TOF_VL53L0X_Range_Process();
	PME_OFF;
	//MX_TOF_Process();
#endif

#ifdef TOF_3
	APP_LOG(TS_OFF, VLEVEL_H, "\r\n TOF 3 RANGING Process ---- TOF250 Ranging \r\n");
	STS_TOF250_Range_Process();
#endif

	//STS_SENSOR_Power_OFF(0);

}


/*
 *  STS P5 Process, Detection ToF IN-OUT PEOPLE COUNT (VL53L3X)
 *
 */
void STS_YunhornSTSEventP5_Process(void)
{
#ifdef STS_P2
	STS_TOF_VL53LX_PeopleCounting_Process_Start();
#elif	defined(STS_T6)
	STS_TOF_VL53LX_PresenceDetection_Process_Start();
	if (sts_tof_presence_state_changed)
	{
		sts_tof_presence_state_changed = 0;
		UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);

	}
#elif defined(L8)
	//STS_TOF_VL53L8X_Process();
	//MX_TOF_Process();
	MX_TOF_Ranging_Process();
#endif

}

/*
 * STS-P6	--- SOAP Level, capacitive measurement
 * STS Soap Level Detection Process, STS_CAP_Sensor_Detection Process
 * STS_CAP_SWITCH(ON) Boost Voltage to 5V, then hold for 1000 ms
 * HAL_Delay(1000) (ms)
 * STS_CAP_Read_Data()	Read STS_CAP_DATA state
 * STS_CAP_SWITCH(OFF)   Switch Off Boosted Voltage
 */
void STS_YunhornSTSEventP6_Process(void)
{
	APP_LOG(TS_OFF, VLEVEL_M, "\r\n P6 Testing Process\r\n");

	PME_ON;
	//HAL_Delay(150);
//#ifdef LED_ONBOARD
	LED1_ON;
	HAL_Delay(100);
	LED1_OFF;
//#endif
/* 1. Sensor  Power On */
#if defined(STS_R4)

	HAL_GPIO_WritePin(SOAP_SWITCH_GPIO_Port, SOAP_SWITCH_Pin, GPIO_PIN_SET);

	HAL_Delay(2000);
/* 2. Read sensor state */
	//sts_soap_level_state = 0;
	sts_soap_level_state = HAL_GPIO_ReadPin(SOAP_STATUS_GPIO_Port,SOAP_STATUS_Pin);
	//APP_LOG(TS_OFF, VLEVEL_M, "\r\n Soap State = 0x%02X \r\n", sts_soap_level_state);
	APP_LOG(TS_OFF, VLEVEL_M, "\r\n Soap State read=%02x  State: %s \r\n", sts_soap_level_state, (sts_soap_level_state==0x0)?"  +++  Liquid Detected":"  ---  No Liquid");

	HAL_GPIO_WritePin(SOAP_SWITCH_GPIO_Port, SOAP_SWITCH_Pin, GPIO_PIN_RESET);

	if (sts_soap_level_state == 1)
	{
//#ifdef LED_ONBOARD
	LED1_ON;
	HAL_Delay(100);
	LED1_OFF;
	HAL_Delay(50);
	LED1_ON;
	HAL_Delay(100);
	LED1_OFF;
//#endif
	} else {
		LED1_ON;
		HAL_Delay(250);
		LED1_OFF;
	}

#endif
/* 3. Sensor  Power Off */
	PME_OFF;
}


/*
 *  STS P7 Process, Detection IAQ Sensors
 *  air quality and odor level sensors
 */
void STS_YunhornSTSEventP7_Process(void)
{

	APP_LOG(TS_OFF, VLEVEL_L, "\r\n P7 Testing Process\r\n");

}


/*
 *  STS P8 Process, Detection ETR Sensors, Water flow sensors, pulse counting
 *  PA5 sensors , TIM2_ETR, STS-M4
 */
void STS_YunhornSTSEventP8_Process(void)
{
	APP_LOG(TS_OFF, VLEVEL_L, "\r\n P8 Testing Process\r\n");

}

/*
 *  STS P_IO_RS485 Process, Send Out Sensor Data Via RS485 interface
 *  sensors
 */

void STS_YunhornSTSEventPIORS485_Process(void)
{
	APP_LOG(TS_OFF, VLEVEL_L, "\r\n P_IO_RS485 Process\r\n");
}


void STS_SENSOR_Power_ON(uint8_t cnt)
{
	PME_ON;
}
void STS_SENSOR_Power_OFF(uint8_t cnt)
{
	PME_OFF;
}

void STS_SENSOR_MEMS_Reset(uint8_t cnt)
{
	PME_TOGGLE;
}

#ifdef	STS_R4

void STS_R4_sensor_read(sts_r_sensor_data_t *sts_r_sensor_data)
{
	// sts_soap_level_state    0x00 --- Liquid Detected,   0x01 --- no Detection
	sts_r_sensor_data->on_off_event  = (sts_soap_level_state ==0x00? true:false);
	sts_r_sensor_data->measure_tech  = 0; //liquid capacity

}

#endif


#ifdef	STS_M1
void STS_M1_sensor_read(sts_r_sensor_data_t *sts_m_sensor_data)
{
	sts_m_sensor_data->on_off_event  = sts_water_leakage_state;
	sts_m_sensor_data->measure_tech  = 0; //weak current detection
}
#endif


#if	defined(YUNHORN_STS_O5_ENABLED)
void STS_O5_SENSOR_Read(STS_OO_SensorDataTypeDef *oo_data)
{

	oo_data->state_sensor1_on_off  = sts_reed_hall_result;


	sensor_data_ready = 1;
}
#endif

void USER_APP_Parse_CMD_P(uint8_t *parse_buffer, uint8_t parse_buffer_size)
{

	switch (parse_buffer_size) {

	case 4:
		sts_work_mode = (uint8_t)(parse_buffer[CFG_CMD4]-0x30);
		switch (sts_work_mode) {
			case STS_NETWORK_MODE:

				break;
			case STS_WIRED_MODE:		// STS-O2

				break;
			case STS_REEDSWITCH_MODE:	// STS-O2
				break;
			case STS_RSS_MODE:			// STS-O6
				break;
			case STS_DUAL_MODE:			// STS-O6
				break;
			case STS_UNI_MODE:			// STS-O7
				break;
			case STS_DUAL_RSS_MODE:
				break;
			case STS_TOF_RSS_MODE:		// STS-O7T
				break;
			case STS_TOF_DISTANCE_MODE:	// STS-R1/R2/R5/R1D
				break;
			case STS_TOF_PRESENCE_MODE:	// STS-O6T
				break;
			case STS_TOF_IN_OUT_MODE:	// STS-P2
				break;
			case STS_FALL_DETECTION_MODE:	// STS-O7F
				break;
			case STS_OTHER_MODE:
				break;
			default:
				break;
		}
		break;
	case 5:
		break;
	case 12:
		break;
	default:
		break;
	}


}
// following to be fill up
#if 0
	uint8_t pbuf[128]={0x0}, i=0, pbuf_size=parse_buffer_size&0x7F;
	uint8_t invalid_flag = 1;
	UTIL_MEM_cpy_8((void*)pbuf,(void*)parse_buffer, pbuf_size); /* 127 BYTES MAX */

	if (((char)pbuf[CFG_CMD1] == 'P') && (pbuf_size >= 3)) //   BEGIN OF PARAMETER CONFIG
		{
		 /*
		  * YUNHORN STS PRODUCT SUBMODULE, MEMS OR SENSOR HEAD LEVEL PARAMETER TUNING SECTION
		  */

			//i = P_MEM_CFG;		//start of parameter

			switch ((char)pbuf[CFG_CMD2])   //BEGIN OF SWITCH TVL_BUF_P_MEMS_NO
			{   //#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

					uint8_t mems_ver = (uint8_t)(pbuf[CFG_CMD3]-0x30);

					uint8_t j=0;
					if (mems_ver == sts_version)
					{					// Firmware version or Variation of MEMS/component
						if (pbuf_size == 5 && pbuf[CFG_CMD4]=='0')  //switch network mode color
						{
							invalid_flag = 0;

							sts_work_mode = (uint8_t)(pbuf[CFG_CMD4] - 0x30);
							if (sts_work_mode == STS_NETWORK_MODE)
							{	//network mode
								sts_cloud_netcolor = (uint8_t)(pbuf[CFG_CMD5]-0x30);
								if (sts_cloud_netcolor == STS_COLOR_MAX) sts_cloud_netcolor = STS_RED_BLUE;
								else if (sts_cloud_netcolor > STS_COLOR_MAX)
								{
	#if 1
									switch((uint8_t)pbuf[CFG_CMD5])
									{
										case STS_GREENDARK:
											sts_lamp_bar_color = STS_GREEN_DARK;
											sts_cloud_netcolor = STS_GREEN_DARK;
										break;
										case STS_REDDARK:
											sts_lamp_bar_color = STS_RED_DARK;
											sts_cloud_netcolor = STS_RED_DARK;
										break;
										case STS_REDBLUE:
											sts_lamp_bar_color = STS_RED_BLUE;
											sts_cloud_netcolor = STS_RED_BLUE;
										break;
										case STS_BLUEDARK:
											sts_lamp_bar_color = STS_BLUE_DARK;
											sts_cloud_netcolor = STS_BLUE_DARK;
										break;
										case STS_REDGREEN:
											sts_lamp_bar_color = STS_RED_GREEN;
											sts_cloud_netcolor = STS_RED_GREEN;
										break;
										case STS_BLUEGREEN:
											sts_lamp_bar_color = STS_BLUE_GREEN;
											sts_cloud_netcolor = STS_BLUE_GREEN;
										break;
									}
								}
	#endif
								APP_LOG(TS_OFF, VLEVEL_L, "\r\n Cloud Color Set to 0X%02X \r\n",sts_cloud_netcolor);
							}
							sts_service_mask = STS_SERVICE_MASK_L0;

							sts_cfg_nvm.work_mode = (uint8_t)sts_work_mode;
							sts_cfg_nvm.sts_service_mask = (uint8_t)sts_service_mask;
							OnStoreSTSCFGContextRequest();

							i=0;						// Step 1: Prepare status update message
							UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
							UTIL_MEM_cpy_8((void*)outbuf,(void*)pbuf, pbuf_size);
							i = pbuf_size;

							STS_Combined_Status_Processing();

						} else if  (pbuf_size == 7 && tlv_buf[CFG_CMD4]=='F')  // Change fall detection
						{
							invalid_flag = 0;									// P 1 1 F A B C
							if (((pbuf[CFG_CMD5] >='0') && (pbuf[CFG_CMD5]<='9')) && ((pbuf[CFG_CMD6]<='9') && (pbuf[CFG_CMD6]>='0'))
									&& ((pbuf[CFG_CMD7]<='9') && (pbuf[CFG_CMD7]>='0'))) //&& ((tlv_buf[CFG_CMD8]<='9') && (pbuf[CFG_CMD8]>='0')))
							{
								sts_fall_detection_acc_threshold 			= (uint8_t)(pbuf[CFG_CMD5] - 0x30)*10;			//A: acc *10 mg/s2
								sts_fall_detection_depth_threshold 			= (uint8_t)(pbuf[CFG_CMD6] - 0x30)*10;			//D: depth *10 in cm
								sts_fall_confirm_threshold_in_10sec			= (uint8_t)(pbuf[CFG_CMD7] - 0x30)*10;			//C: fall_confirm_threshold_in_10sec

								//sts_occupancy_overtime_threshold_in_10min 	= (uint8_t)(tlv_buf[CFG_CMD8] - 0x30)*10;			//T: overtime *10 min

								sts_cfg_nvm.fall_detection_acc_threshold 	= (uint8_t)(pbuf[CFG_CMD5] - 0x30);
								sts_cfg_nvm.fall_detection_depth_threshold 	= (uint8_t)(pbuf[CFG_CMD6] - 0x30);
								sts_cfg_nvm.fall_confirm_threshold_in_10sec	= (uint8_t)(pbuf[CFG_CMD7] - 0x30);

								//sts_cfg_nvm.occupancy_overtime_threshold_in_10min 	= (uint8_t)(tlv_buf[CFG_CMD8] - 0x30);

								if (sts_work_mode == STS_UNI_MODE)		// fall detection threshold only effective in Uni_mode
								{
									if ((sts_fall_detection_acc_threshold ==0)&&(sts_fall_detection_depth_threshold==0))
									{
										sts_presence_fall_detection = FALSE;
									} else {
										sts_presence_fall_detection = TRUE;
									}
								}

								OnStoreSTSCFGContextRequest();

								i=0;						// Step 1: Prepare status update message
								UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
								UTIL_MEM_cpy_8((void*)outbuf,(void*)pbuf, pbuf_size);
								i = pbuf_size;
								APP_LOG(TS_OFF, VLEVEL_M, "###### Fall detection CFG = %s\r\n",(char*)outbuf);

								STS_Combined_Status_Processing();
							}



						}else if  (pbuf_size == 8 && pbuf[CFG_CMD4]=='O')  // Change occupancy/motionless/ unconscious  overtime threshold
						{
							invalid_flag = 0;									// P 1 1 O A B C D
							if (((pbuf[CFG_CMD5] >='0') && (pbuf[CFG_CMD5]<='9')) && ((pbuf[CFG_CMD6]<='9') && (pbuf[CFG_CMD6]>='0'))
									&& ((pbuf[CFG_CMD7]<='9') && (pbuf[CFG_CMD7]>='0'))&& ((pbuf[CFG_CMD8]<='9') && (pbuf[CFG_CMD8]>='0')))
							{
								sts_motionless_duration_threshold_in_min	= (uint8_t)(pbuf[CFG_CMD5] - 0x30);			//Motionless duration in min
								sts_occupancy_overtime_threshold_in_10min	= (uint8_t)(pbuf[CFG_CMD6] - 0x30)*10;			//Long occupation in min
								sts_unconscious_level_threshold				= (uint8_t)(pbuf[CFG_CMD7] - 0x30+1)*128;		//motion level threshold less than 1280
								sts_alarm_mute_reset_timer_in_10sec		 	= (uint8_t)(pbuf[CFG_CMD8] - 0x30)*10;			//alarm mute reset timer in 10 sec

								sts_cfg_nvm.motionless_duration_threshold_in_min 	= (uint8_t)(pbuf[CFG_CMD5] - 0x30);
								sts_cfg_nvm.occupancy_overtime_threshold_in_10min 	= (uint8_t)(pbuf[CFG_CMD6] - 0x30);
								sts_cfg_nvm.unconscious_or_motionless_level_threshold		= (uint8_t)(pbuf[CFG_CMD7] - 0x30+1);
								sts_cfg_nvm.alarm_mute_reset_timer_in_10sec 	= (uint8_t)(pbuf[CFG_CMD8] - 0x30)*10;

								OnStoreSTSCFGContextRequest();

								i=0;						// Step 1: Prepare status update message
								UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
								UTIL_MEM_cpy_8((void*)outbuf,(void*)pbuf, pbuf_size);
								i = pbuf_size;
								APP_LOG(TS_OFF, VLEVEL_M, "###### Occupancy/Overstay/unconscious config changed =%s\r\n",(char *)outbuf);
								STS_Combined_Status_Processing();
							}
						}
						else if  (pbuf_size == 4 )		// P WORK mode switch
						{
							invalid_flag = 0;

							if (((pbuf[CFG_CMD4] >='0') && (pbuf[CFG_CMD4]<='9')) || ((pbuf[CFG_CMD4]<='Z') && (pbuf[CFG_CMD4]>='A')))
							{
								if ((pbuf[CFG_CMD4] >='0') && (pbuf[CFG_CMD4]<='9'))
								{
									sts_work_mode = (uint8_t)((tlv_buf[CFG_CMD4] - 0x30));
								} else if ((pbuf[CFG_CMD4]<='Z') && (pbuf[CFG_CMD4]>='A'))
								{
									sts_work_mode = (uint8_t)((pbuf[CFG_CMD4] - 0x41) + 10);
								}

							i=0;						// Step 1: Prepare status update message
							UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
							UTIL_MEM_cpy_8((void*)outbuf,(void*)pbuf, pbuf_size);
							i = pbuf_size;
							APP_LOG(TS_OFF, VLEVEL_L, "###### P Work mode switched =%s\r\n",(char *)outbuf);

							//sts_service_mask = STS_SERVICE_MASK_L0;
							//sts_lamp_bar_color = STS_GREEN;
							sts_presence_fall_detection=FALSE;
							sts_rss_config_updated_flag = STS_RSS_CONFIG_NON;

							switch (sts_work_mode) {
								case STS_NETWORK_MODE:
								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MODE_0_MASK;
								break;

								case STS_WIRED_MODE:
								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MODE_1_MASK;
								break;

								case STS_REEDSWITCH_MODE:
								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MODE_2_MASK;
								break;

								case STS_RSS_MODE:
								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MODE_3_MASK;
								sts_rss_config_updated_flag = STS_RSS_CONFIG_DEFAULT;
								break;

								case STS_DUAL_MODE:
								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MODE_4_MASK;
								sts_rss_config_updated_flag = STS_RSS_CONFIG_DEFAULT;
								break;

								case STS_UNI_MODE:
								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MODE_5_MASK;
								sts_rss_config_updated_flag = STS_RSS_CONFIG_FALL_DETECTION;
								sts_presence_fall_detection=TRUE;
								break;

								default:

								sts_cfg_nvm.sts_ioc_mask = STS_IOC_MASK_NONE;
								break;
							}
							sts_cfg_nvm.work_mode = (uint8_t)sts_work_mode;

							sts_cfg_nvm.sts_service_mask = (uint8_t)sts_service_mask;
							OnStoreSTSCFGContextRequest();

							STS_Combined_Status_Processing();
							HAL_Delay(2000);

							//OnSystemReset();

							} else {
								invalid_flag = 1;
							}

						} else if (pbuf_size == CFG_CMD_RSS_FULL_SIZE)
						{
								invalid_flag = 0;

								for (j =0; j < CFG_CMD_RSS_FULL_SIZE-3; j++)
								{
									if ((pbuf[CFG_CMD4+j] >='0') && (pbuf[CFG_CMD4+j]<='9'))
									{
										//sts_cfg_nvm.p[j] = (uint8_t)((tlv_buf[CFG_CMD4+j] - 0x30)&0xFF);
										//APP_LOG(TS_OFF,VLEVEL_H,"\r\n tlv_buf %d = %02x cfg->p[%d]=%02x \r\n",j,tlv_buf[CFG_CMD4+j], j, sts_cfg_nvm.p[j]);
									} else {
										invalid_flag = 1;
									}
								}
								i=0;
								sts_cfg_nvm.p[RSS_CFG_START_M] 					= (uint8_t)((pbuf[CFG_CMD4] - 0x30)*10+(pbuf[CFG_CMD5] - 0x30));
								sts_cfg_nvm.p[RSS_CFG_LENGTH_M] 				= (uint8_t)((pbuf[CFG_CMD6] - 0x30)*10+(pbuf[CFG_CMD7] - 0x30));
								sts_cfg_nvm.p[RSS_CFG_THRESHOLD] 				= (uint8_t)((pbuf[CFG_CMD8] - 0x30)*10+(pbuf[CFG_CMD9] - 0x30));
								sts_cfg_nvm.p[RSS_CFG_RECEIVER_GAIN] 			= (uint8_t)((pbuf[CFG_CMD10]- 0x30)*10+(pbuf[CFG_CMD11]- 0x30));

								sts_cfg_nvm.p[RSS_CFG_PROFILE] 					= (uint8_t)((pbuf[CFG_CMD12]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_RATE_TRACKING] 			= (uint8_t)((pbuf[CFG_CMD13]- 0x30)*10+(pbuf[CFG_CMD14]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_RATE_PRESENCE] 			= (uint8_t)((pbuf[CFG_CMD15]- 0x30)*10+(pbuf[CFG_CMD16]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_HWAAS] 					= (uint8_t)((pbuf[CFG_CMD17]- 0x30)*10+(pbuf[CFG_CMD18]- 0x30));

								sts_cfg_nvm.p[RSS_CFG_NBR_REMOVED_PC] 			= (uint8_t)((pbuf[CFG_CMD19]- 0x30));

								sts_cfg_nvm.p[RSS_CFG_ITE_DEVIATION] 			= (uint8_t)((pbuf[CFG_CMD20]- 0x30)*10+(pbuf[CFG_CMD21]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_ITE_FAST_CUTOFF] 			= (uint8_t)((pbuf[CFG_CMD22]- 0x30)*10+(pbuf[CFG_CMD23]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_ITE_SLOW_CUTOFF] 			= (uint8_t)((pbuf[CFG_CMD24]- 0x30)*10+(pbuf[CFG_CMD25]- 0x30));

								sts_cfg_nvm.p[RSS_CFG_ITR_TIME] 				= (uint8_t)((pbuf[CFG_CMD26]- 0x30)*10+(pbuf[CFG_CMD27]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_ITR_WEIGHT] 				= (uint8_t)((pbuf[CFG_CMD28]- 0x30)*10+(pbuf[CFG_CMD29]- 0x30));

								sts_cfg_nvm.p[RSS_CFG_OUTPUT_TIME] 				= (uint8_t)((pbuf[CFG_CMD30]- 0x30)*10+(pbuf[CFG_CMD31]- 0x30));

								sts_cfg_nvm.p[RSS_CFG_DOWNSAMPLING_FACTOR] 		= (uint8_t)((pbuf[CFG_CMD32]- 0x30));
								sts_cfg_nvm.p[RSS_CFG_POWER_MODE] 				= (uint8_t)((pbuf[CFG_CMD33]- 0x30));



								if (invalid_flag == 0)
								{
									STS_PRESENCE_SENSOR_NVM_CFG();

									i=0;						// Step 1: Prepare status update message
									UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
									UTIL_MEM_cpy_8((void*)outbuf,(void*)pbuf, pbuf_size);
									i = pbuf_size;
									APP_LOG(TS_OFF, VLEVEL_M, "###### RSS Full CFG=%s\r\n",(char *)outbuf);

									// 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.work_mode	= sts_work_mode;
									sts_cfg_nvm.sts_service_mask = sts_service_mask;
									//sts_cfg_nvm.length = CFG_CMD_RSS_FULL_SIZE;

									OnStoreSTSCFGContextRequest();
								}

						} else if (tlv_buf_size == CFG_CMD_RSS_SIMPLE_SIZE)
						{
								//Validation check
								invalid_flag = 0;
	#if 1
								for (j =0; j < CFG_CMD_RSS_SIMPLE_SIZE-3; j++)
								{
									if ((pbuf[CFG_CMD4+j] < '0') || (pbuf[CFG_CMD4+j] >'9'))
									{
										invalid_flag = 1;
									}
								}
	#endif
								if (invalid_flag == 0)
								{
									sts_cfg_nvm.p[RSS_CFG_START_M] 			= (uint8_t)((pbuf[CFG_CMD4] - 0x30)*10+(pbuf[CFG_CMD5] - 0x30));
									sts_cfg_nvm.p[RSS_CFG_LENGTH_M] 		= (uint8_t)((pbuf[CFG_CMD6] - 0x30)*10+(pbuf[CFG_CMD7] - 0x30));
									sts_cfg_nvm.p[RSS_CFG_THRESHOLD] 		= (uint8_t)((pbuf[CFG_CMD8] - 0x30)*10+(pbuf[CFG_CMD9] - 0x30));
									sts_cfg_nvm.p[RSS_CFG_RECEIVER_GAIN] 	= (uint8_t)((pbuf[CFG_CMD10]- 0x30)*10+(pbuf[CFG_CMD11]- 0x30));


									STS_PRESENCE_SENSOR_NVM_CFG_SIMPLE();

									i=0;						// Step 1: Prepare status update message
									UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
									UTIL_MEM_cpy_8((void*)outbuf,(void*)pbuf, pbuf_size);
									i = pbuf_size;
									APP_LOG(TS_OFF, VLEVEL_M, "###### RSS Simple CFG=%s\r\n",(char*)outbuf);

									// 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.work_mode = sts_work_mode;
									sts_cfg_nvm.sts_service_mask = sts_service_mask;
									//sts_cfg_nvm.length = CFG_CMD_RSS_SIMPLE_SIZE;

									OnStoreSTSCFGContextRequest();
								}
						}

						// Invalid parameters
						// Step 1/2: Prepare status update message
					if (invalid_flag == 1)
					{
						STS_SENSOR_Upload_Config_Invalid_Message();
						APP_LOG(TS_OFF, VLEVEL_L, "###### MTM VER Invalid or Mismatch\r\n");
					} else {

						// Step 3: Upload status update message
						STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
					}
					}

				break;

				// for multiple 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 reed-switch or hall elements
				#endif

				break;
				default:
				// for multiple sensor heads or MEMS components, TODO   2022-10-21 PARK HERE
					//STS_SENSOR_Upload_Config_Invalid_Message();
				break;
			}   //END OF SWITCH TVL_BUF_P_MEMS_NO
			 //END  OF PARAMETER CONFIG
		}
#endif




void USER_APP_AUTO_RESPONDER_Parse(uint8_t *parse_buffer, uint8_t parse_buffer_size)
{
	uint8_t i=0, tlv_buf[128]={0x0};
	memset((void*)outbuf,0x0, sizeof(outbuf));
	UTIL_MEM_cpy_8((void*)tlv_buf,(void*)parse_buffer, parse_buffer_size&0x7F); /* 127 BYTES MAX */

	switch ((char)tlv_buf[CFG_CMD1])
	{								/*  Begin of switch tlv_buf[CFG_CMD1] 	*/
	/* 111111111111111111111111111111111111111111111111111111111111111111111 */
	case 'Y':
		switch ((char)tlv_buf[CFG_CMD2])
		{
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'Z':					/*  Begin of Board level Req/Response	*/
			switch ((char)tlv_buf[CFG_CMD3])
			{
			case  'H':				/*	"YZH": BOARD SOFT RESET, REVIVE 	*/
				//BOARD REVIVE
				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, 20, (uint8_t *)"!YunHorn STS Revive!");
				HAL_Delay(2000);
				APP_LOG(TS_OFF, VLEVEL_H, "\r\n Yunhorn STS Node Revive ... \r\n");
				HAL_Delay(2000);
				__set_FAULTMASK(1);
				NVIC_SystemReset();
				//OnSystemReset();
				break;
			case 'S':				/* "YZS": Self Function Testing 			*/
				STS_SENSOR_Function_Test_Process();

				break;
			case 'C':				/* "YZC": report 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(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
				break;
			case 'D':				/* "YZD": Distance/Install height Measure 	*/
				STS_SENSOR_Distance_Test_Process();
				sts_cfg_nvm.sensor_install_height_in_10cm 	= sts_sensor_install_height/100;  //in 10 cm, say 4500mm=450cm=45 dm
				APP_LOG(TS_OFF, VLEVEL_M, "\n STS CFG NVM -> SENSOR INSTALL HEIGHT STORED = %d dm(10cm)\n", sts_cfg_nvm.sensor_install_height_in_10cm);
				OnStoreSTSCFGContextRequest();
				i = 0;
				outbuf[i++] 	= (uint8_t)'D';
				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));
				outbuf[i++] 	= (uint8_t)(4);	//four bytes for distance
				#if	defined(VL53LX)||defined(VL53L0)
				outbuf[i++] 	= (uint8_t)(sts_sensor_install_height/1000+0x30)&0xff;
				outbuf[i++] 	= (uint8_t)((sts_sensor_install_height/100)%10+0x30)&0xff;
				outbuf[i++] 	= (uint8_t)((sts_sensor_install_height/10)%10+0x30)&0xff;
				outbuf[i++] 	= (uint8_t)((sts_sensor_install_height/1)%10+0x30)&0xff;
					//outbuf[i++] 	= (uint8_t)(sts_sensor_install_height>>8)&0xFF;
					//outbuf[i++] 	= (uint8_t)(sts_sensor_install_height)&0xFF;
				#endif

				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
				break;
			case 'M':				/* "YZM": Mask level			 			*/
				i = 0;
				outbuf[i++] 	= (uint8_t)'M';
				outbuf[i++] 	= (uint8_t)sts_service_mask;
				outbuf[i++] 	= (uint8_t)sts_work_mode;
				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);

				break;

			default:
				break;
			}

			break;					/*  End   of Board level Req/Response	*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'V':					/*  Begin of Board level Version check	*/
			switch ((char)tlv_buf[CFG_CMD3])
			{
			case  'H':				// "YVH"   REPORT FIRMWARE VERSION 		*/
				// 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) sts_hardware_ver;
				outbuf[i++] = (uint8_t) MajorVer;
				outbuf[i++] = (uint8_t) MinorVer;
				outbuf[i++] = (uint8_t) SubMinorVer;
				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
				break;
			case 'C':
				uint8_t cfg_in_nvm[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0};
				OnRestoreSTSCFGContextRequest((void*)&cfg_in_nvm);
				i=0;
#if 0
				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_IOC_MASK];  			//sts ioc 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_CFG_START+j]);
				}
#endif
				outbuf[0] = 0x43; 	// 'C' for config
				UTIL_MEM_cpy_8(outbuf+1, cfg_in_nvm,44);
				i=45;
				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);

				break;
			case 'T':
				 struct tm localtime;
				 SysTime_t UnixEpoch = SysTimeGet();
				 UnixEpoch.Seconds -= 18; /*removing leap seconds*/

				 //UnixEpoch.Seconds += 3600 * 2; /*adding 2 hours*/

				 SysTimeLocalTime(UnixEpoch.Seconds,  &localtime);

				  APP_LOG(TS_OFF, VLEVEL_M, "LTIME:%02dh%02dm%02ds on %02d/%02d/%04d\r\n",
				            localtime.tm_hour, localtime.tm_min, localtime.tm_sec,
				            localtime.tm_mday, localtime.tm_mon + 1, localtime.tm_year + 1900);
					i=0;
					outbuf[i++] = (uint8_t) 'T';

					uint16_t year = localtime.tm_year+1900;
					outbuf[i++] = (uint8_t) ((year)>>8);
					outbuf[i++] = (uint8_t) (year)&0xff;
					outbuf[i++] = (uint8_t) localtime.tm_mon+1;
					outbuf[i++] = (uint8_t) localtime.tm_mday;
					outbuf[i++] = (uint8_t) localtime.tm_hour;
					outbuf[i++] = (uint8_t) localtime.tm_min;
					outbuf[i++] = (uint8_t) localtime.tm_sec;

					STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);

				break;
			default:
				break;
			}

			break;					/*  End   of Board level Version check	*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'M':					/*  Begin of Mask check					*/
			if ((tlv_buf[CFG_CMD3]>='0')&&(tlv_buf[CFG_CMD3]<='9'))
			{
				sts_service_mask = (uint8_t)(tlv_buf[CFG_CMD3]-0x30);
			}

			break;					/*  End of Mask check					*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'O':					/*  Begin of Power control of modules	*/
									/*  TODO XXX STS YUNHORN 				*/
			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));
				PME_ON;

				// 2024-07-31
				UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
				UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf,parse_buffer_size);
				i = parse_buffer_size;
				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
			} else {
				STS_SENSOR_Upload_Config_Invalid_Message();
			}

			break;					/*  End  of Power control of modules	*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'F':					/*  Begin of Power control of modules	*/
									/*  TODO XXX STS YUNHORN 				*/
			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));
			PME_OFF;
			// 2024-07-31
			UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
			UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf, parse_buffer_size);
			i = parse_buffer_size;
			STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
		} else {
			STS_SENSOR_Upload_Config_Invalid_Message();
		}

			break;					/*  End  of Power control of modules	*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'H':					/*  Begin of Reset/Toggle     modules	*/
									/*  TODO XXX STS YUNHORN 				*/
			if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) {
			PME_ON;
			PME_OFF;
			PME_ON;
			// 2024-07-31
			UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
			UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf,parse_buffer_size);
			i = parse_buffer_size;
			STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);
		} else {
			STS_SENSOR_Upload_Config_Invalid_Message();
		}

			break;					/*  End of Reset/Toggle  modules		*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'D':					/*  Begin of Upload Periodic interval	*/
			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'))))
				{
					uint32_t periodicity_length = (tlv_buf[CFG_CMD3]-0x30)*10+ (tlv_buf[CFG_CMD4]-0x30);

					if ((char)tlv_buf[CFG_CMD5] == 'M') {
						periodicity_length *= 60;
					} else if ((char)tlv_buf[CFG_CMD5] == 'H') {
						periodicity_length *= 3600;
					}
					STS_TxPeriod_sec = periodicity_length;

					TxPeriodicity = periodicity_length*1000;
					APP_LOG(TS_OFF,VLEVEL_M, "\nSTS Tx Periodicty changed to %u sec\n\r", STS_TxPeriod_sec);
#ifdef	STS_R4
					OnYunhornSTSTxPeriodicityChanged(STS_TxPeriod_sec*1000);
#elif defined(STS_R1D)||defined(STS_R1)||defined(STS_R5)||defined(STS_P2)||defined(STS_O6T)||defined(STS_R2)||defined(STS_R3)||defined(STS_R6)
					OnYunhornSTSTxPeriodicityChanged(STS_TxPeriod_sec*1000);
#elif	defined(STS_O6)||defined(STS_O7)
					OnYunhornSTSHeartBeatPeriodicityChanged(periodicity_length);
#endif
					// 2024-07-31
					UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
					UTIL_MEM_cpy_8(outbuf,parse_buffer,parse_buffer_size);
					i = parse_buffer_size;

					STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)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_M, "###### YUNHORN Periodicity Changed to [ %d ] Seconds\r\n", periodicity_length);

				} else {
					STS_SENSOR_Upload_Config_Invalid_Message();
				}

			break;					/*  End of Upload Periodic interval		*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		case 'L':
		case 'S':					/*  Begin Sampling/HeartBeat interval	*/
			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'))))
				{
				uint32_t heart_beat_or_sampling_periodicity_length = (tlv_buf[CFG_CMD3]-0x30)*10+ (tlv_buf[CFG_CMD4]-0x30);

				if ((char)tlv_buf[CFG_CMD5] == 'M') {
					heart_beat_or_sampling_periodicity_length *= 60;
				} else if ((char)tlv_buf[CFG_CMD5] == 'H') {
					heart_beat_or_sampling_periodicity_length *= 3600;
				}

				STS_HeartBeatTimerPeriod_sec = heart_beat_or_sampling_periodicity_length;

#if	defined(STS_P2)||defined(STS_R4)||defined(STS_T6)||defined(STS_R1D)||defined(STS_R5)
				OnYunhornSTSHeartBeatPeriodicityChanged(STS_HeartBeatTimerPeriod_sec*1000);
#endif
// LEGACY CODE, TO BE XXX LATER  =============
#ifdef YUNHORN_STS_E0_ENABLED
				SamplingPeriodicity = heart_beat_or_sampling_periodicity_length*1000;  //translate to 1000ms=1s
				OnYunhornSTSSamplingPeriodicityChanged(SamplingPeriodicity);
#endif
#if defined(YUNHORN_STS_R0_ENABLED)||defined(YUNHORN_STS_R5_ENABLED)
				STS_HeartBeatTimerPeriod_sec = heart_beat_or_sampling_periodicity_length*1000;  //translate to 1000ms=1s
				OnYunhornSTSHeartBeatPeriodicityChanged(STS_HeartBeatTimerPeriod_sec);
#endif
#if	defined(STS_O6)||defined(STS_O7)
				SamplingPeriodicity = heart_beat_or_sampling_periodicity_length*1000;  //translate to 1000ms=1s
				OnYunhornSTSSamplingPeriodicityChanged(SamplingPeriodicity);
#endif
// LEGACY CODE, TO BE XXX LATER  =============
					// 2024-07-31
				    UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
					UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf, parse_buffer_size);
					i = parse_buffer_size;

					STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)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.sampling = (uint8_t)((tlv_buf[CFG_CMD3]-0x30)*10+(tlv_buf[CFG_CMD4]-0x30));
					sts_cfg_nvm.s_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_M, "###### YUNHORN HeartBeat or Sampling Interval Changed to [ %d ] msec\r\n", (SamplingPeriodicity));

				} else {
					STS_SENSOR_Upload_Config_Invalid_Message();
				}
			break;					/*  End Sampling/HeartBeat interval		*/
		/* 2222222222222222222222222222222222222222222222222222222222222222 */
		//	case 'L':					/*  Begin Sampling/HeartBeat interval	*/
		//								/*  YUNHORN TODO XXX 					*/
		//  break;						/*  End Sampling/HeartBeat interval		*/
		default:
			/*	illegal CFG_CMD2*/
			break;
		}
		break;
	/* 111111111111111111111111111111111111111111111111111111111111111111111 */
	case 'P':

		/*		TODO XXX  	FOR NON STS-P2   				*/
		USER_APP_Parse_CMD_P(tlv_buf, parse_buffer_size);

		/*		TODO XXX  	FOR NON STS-P2   				*/

		break;
	/* 111111111111111111111111111111111111111111111111111111111111111111111 */
	case 'A':
		if (((char)tlv_buf[CFG_CMD1] == 'A') && ((char)tlv_buf[CFG_CMD2] == 'C') && (parse_buffer_size == (YUNHORN_STS_AC_CODE_SIZE+2)))  // BEGIN OF *** BOARD LEVEL AUTHORIZATION CODE
			{
				// 'AC'+ AC_CODE(20bytes)
				//UTIL_MEM_cpy_8(sts_ac_code, tlv_buf+2,YUNHORN_STS_AC_CODE_SIZE);

				for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++)
				{
					sts_ac_code[j] = (uint8_t) tlv_buf[2+j];
				}

				STS_YunhornAuthenticationCode_Process();

				if ((hmac_result.ac_pass == 1U)) // good ac code
				{
					//UTIL_MEM_cpy_8(sts_cfg_nvm.ac, sts_ac_code,YUNHORN_STS_AC_CODE_SIZE);

					for (uint8_t j=0; j < YUNHORN_STS_AC_CODE_SIZE; j++)
					{
						sts_cfg_nvm.ac[j] = sts_ac_code[j];
					}

					sts_service_mask = STS_SERVICE_MASK_L0;

					sts_cfg_nvm.sts_service_mask = sts_service_mask;
					OnStoreSTSCFGContextRequest();


				} else {
					sts_service_mask = STS_SERVICE_MASK_L2;
					sts_ac_code[0]	=0x0;
					sts_ac_code[19]	=0x0;
				}

				i=0;
				UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf));
				UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf, parse_buffer_size);
				i = parse_buffer_size;
				STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);

			}
		break;
	default:
		/*	illegal CFG_CMD1*/
		break;
	}								/* End of switch tlv_buf[CFG_CMD1]   */

	/*
	 * YUNHORN STS PRODUCT BOARD LEVEL CONTROL OR REPORT
	 *          --Y
	 *              --Z 			BOARD LEVEL
	 *                 --H 'YZH'			Hardware REBOOT  				[YZH] WVpI
	 *                 --C 'YZC'            LoRa-WAN CLASS A/B/C  			[YZC] WVpD
	 *                 --S 'YZS'            SELF-TEST FUNCTION TEST			[YZS] WVpT
	 *                 --D 'YZD'			DISTANCE MEASURE				[YZD] WVpE
	 *
	 *
	 *              --V				VERSION
	 *                 --H 'YVH'			HARDWARE/FIRMWARE VERSION		[YVH] WVZI
	 *                 --C 'YVC'			NVM CONFIG VERSION				[YVC] WVZD
	 *
	 *              --O				POWER-ON
	 *                 --# 'YO1', 'YO2','YO3'								[YO0] WU8w, [YO1] WU8x, [YO2] WU8y
	 *
	 *              --F				POWER-OFF
	 *                 --# 'YF1', 'YF2','YF3'								[YF0] WUYw, [YF1] WUYx, [YF2] WUYy
	 *
	 *              --H				MEMS RESET
	 *                 --# 'YH0','YH1','YH2'								[YH0] WUgw, [YH1] WUgx, [YH2] WUgy
	 *
	 *              --M				SERVICE LEVEL MASK
	 *                 --# 'YM0', 'YM1','YM2', 'YM3'						[YM0] WU0w [YM1]WU0x [YM2]WU0y [YM3]WU0z
	 *
	 *              --D				UPLINK DURATION OR PERIODICITY			Periodicity of Tx interval or Heart-Beat interval for real-time occupancy status update  2023-04-28
	 *                 --#
	 *                    --#
	 *                       --U		UNIT (S, M, H) SECONDS, MINUTES, HOURS
	 *              --S				SAMPLING INTERVAL OR PERIODICITY        periodicity for real-time sensing
	 *                 --#
	 *                    --#
	 *                       --U		UNIT (S, M, H) SECONDS, MINUTES, HOURS

	 *
	 *          --P					***** WORKMODE AND NETWORK COLOR
	 *               --#			MTM-VER   1
	 *                  --#         STS-VER   1
	 *                     --M   	WORK MODE
	 *
	 *                     --N		NETWORK WORK MODE  {0,1,2,3,4,5,6}
	 *                        --C	NETWORK COLOR, {0,1,2,3,4,5,6,7,8,9}
	 *
	 *          --P					***** SIMPLE CONFIG PARAMETER FOR RSS  (8 DIGITS)
	 *               --#							MTM-VER   1
	 *                  --#         				STS-VER   1
	 *
	 *                     --##						START   #.# meter
	 *                         --##					LENGTH  #.# meter
	 *                             --##				THRESHOLD	#.#*1000
	 *                                 --##   		GAIN		0.##
	 *
	 *          --P					***** DISTANCE MEASURE CONFIG PARAMETER FOR RSS  (7 DIGITS)
	 *               --#							MTM-VER   1
	 *                  --#         				STS-VER   1
	 *                     --##						START   #.# meter
	 *                         --##					LENGTH  #.# meter
	 *                             --#				PROFILE	#
	 *                                 --##   		HWAAS	##
	 *
	 **          --P					***** FULL CONFIG PARAMETER FOR RSS  (30 DIGITS)
	 *               --#							MTM-VER   1
	 *                  --#         				STS-VER   1
	 *						--30{#}		FULL CONFIG PARAMETER
	 *	         --A					***** AC CODE   (22 BYTES)
	 *               --C
	 *                  --#
	 *						--20{#}		AC CODE 20 BYTES
	 *
	 */

} // END OF  USER_APP_AUTO_RESPONDER_P_CMD


void STS_SENSOR_Upload_Config_Invalid_Message(void)
{
	if (sts_service_mask == STS_SERVICE_MASK_L0)
		STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, 5, (uint8_t *)"PVXXX");
}





void OnStoreSTSCFGContextRequest(void)
{
  /* USER CODE BEGIN OnStoreContextRequest_1 */
	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.reserve02;
	to_store__value[i++] = sts_cfg_nvm.reserve03;
	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_store_value[NVM_AC_CODE_START]!= 0x0) && (nvm_store_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);
	}

  /* 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 *)to_store__value, YUNHORN_STS_MAX_NVM_CFG_SIZE);
  }

  /* USER CODE BEGIN OnStoreContextRequest_Last */


  /* USER CODE END OnStoreContextRequest_Last */
}

void OnRestoreSTSCFGContextRequest(uint8_t *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 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_store_value, (void*)STS_CONFIG_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE);
	//STS_Show_STS_CFG_NVM((uint8_t*)nvm_store_value);
  /* USER CODE BEGIN OnRestoreContextRequest_Last */

  if ((nvm_store_value[NVM_MTM1] != sts_mtmcode1) || (nvm_store_value[NVM_MTM2] != sts_mtmcode2) || (nvm_store_value[NVM_VER] != sts_version))
	{
		APP_LOG(TS_OFF, VLEVEL_L, "\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);
		NVIC_SystemReset();
	} else
	{

		sts_cfg_nvm.mtmcode1 			= (uint8_t)nvm_store_value[NVM_MTM1];
		sts_cfg_nvm.mtmcode2 			= (uint8_t)nvm_store_value[NVM_MTM2];
		sts_cfg_nvm.version 			= (uint8_t)nvm_store_value[NVM_VER];
		sts_cfg_nvm.hardware_ver  		= (uint8_t)nvm_store_value[NVM_HWV];
		sts_cfg_nvm.periodicity 		= (uint8_t)(nvm_store_value[NVM_PERIODICITY]);				//TxPeriodicity interval
		sts_cfg_nvm.unit				= (uint8_t)(nvm_store_value[NVM_UNIT]);
		sts_cfg_nvm.sampling			= (uint8_t)(nvm_store_value[NVM_SAMPLING]);				//Heart-beat or sampling interval
		sts_cfg_nvm.s_unit				= (uint8_t)(nvm_store_value[NVM_S_UNIT]);
		sts_cfg_nvm.work_mode			= (uint8_t)(nvm_store_value[NVM_WORK_MODE]);
		sts_cfg_nvm.sts_service_mask	= (uint8_t)(nvm_store_value[NVM_SERVICE_MASK]);
		sts_cfg_nvm.sts_ioc_mask			= (uint8_t)(nvm_store_value[NVM_IOC_MASK]);
		sts_cfg_nvm.length 				= (uint8_t)(nvm_store_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_store_value[NVM_CFG_START+j];
		}

		sts_cfg_nvm.reserve02			=(uint8_t)nvm_store_value[NVM_RESERVE02];
		sts_cfg_nvm.reserve03			=(uint8_t)nvm_store_value[NVM_RESERVE03];
		sts_cfg_nvm.sensor_install_height_in_10cm			=(uint8_t)nvm_store_value[NVM_SENSOR_INSTALL_HEIGHT];
		sts_cfg_nvm.alarm_parameter05			=(uint8_t)nvm_store_value[NVM_ALARM_PARAMETER05];
		sts_cfg_nvm.alarm_mute_reset_timer_in_10sec = (uint8_t)nvm_store_value[NVM_ALARM_MUTE_RESET_TIMER];
		sts_cfg_nvm.alarm_lamp_bar_flashing_color = (uint8_t)nvm_store_value[NVM_ALARM_LAMP_BAR_FLASHING_COLOR];
		sts_cfg_nvm.occupancy_overtime_threshold_in_10min = (uint8_t)nvm_store_value[NVM_OCCUPANCY_OVERTIME_THRESHOLD];
		sts_cfg_nvm.motionless_duration_threshold_in_min= (uint8_t)nvm_store_value[NVM_MOTIONLESS_DURATION_THRESHOLD];
		sts_cfg_nvm.unconscious_or_motionless_level_threshold 		= (uint8_t)nvm_store_value[NVM_UNCONSCIOUS_LEVEL_THRESHOLD];
		sts_cfg_nvm.fall_detection_acc_threshold 	= (uint8_t)nvm_store_value[NVM_FALL_DETECTION_ACC_THRESHOLD];
		sts_cfg_nvm.fall_detection_depth_threshold 	= (uint8_t)nvm_store_value[NVM_FALL_DETECTION_DEPTH_THRESHOLD];
		sts_cfg_nvm.fall_confirm_threshold_in_10sec		= (uint8_t)nvm_store_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_store_value[NVM_AC_CODE_START +j];
		}

	}
  	  //STS_Show_STS_CFG_NVM((uint8_t*)nvm_store_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;
	}

	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(APP_TX_DUTYCYCLE*5); 	//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_HeartBeatTimerPeriod_sec = sampling_heartbeat_periodicity;
#endif
#if	defined(YUNHORN_STS_O6_ENABLED) ||defined(YUNHORN_STS_O5_ENABLED)
	OnYunhornSTSSamplingPeriodicityChanged(sampling_heartbeat_periodicity);				// in m-sec unit
#endif


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

	sts_work_mode	= sts_cfg_nvm.work_mode;
	sts_service_mask = sts_cfg_nvm.sts_service_mask;

#ifdef YUNHORN_STS_O6_ENABLED
	sts_lamp_bar_color = STS_GREEN;
	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];
	//}
	//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)
{
	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 (uint8_t i=0; i<YUNHORN_STS_MAX_NVM_CFG_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");
}
void STS_SENSOR_Distance_Test_Process(void)
{
#ifdef	YUNHORN_STS_O6_ENABLED
	sts_distance_rss_distance =0;
	do {
		STS_PRESENCE_SENSOR_Distance_Measure_Process();
		HAL_Delay(200);
	} while(sts_distance_rss_distance == 0);

	APP_LOG(TS_OFF, VLEVEL_M, "\r\nSensor Function Test: Distance Measured =%u mm\r\n", (int)sts_distance_rss_distance);
#endif

#if	defined(VL53LX)||defined(L8)
		//MX_TOF_Init();
		//MX_TOF_Process();
		sts_sensor_install_height = (uint16_t)MX_TOF_Ranging_Process();
		APP_LOG(TS_OFF, VLEVEL_M, "\n STS SENSOR INSTALLATION HEIGHT =%d mm\n\r", (uint16_t)sts_sensor_install_height);
#endif
#if	defined(VL53L0)
		STS_TOF_VL53L0X_Range_Process();
		sts_sensor_install_height=sts_tof_distance_data[0]+sts_tof_distance_data[1];
#endif

}


void STS_SENSOR_MEMS_Get_ID(uint16_t *devID)
{
#ifdef	VL53LX
	*devID = sensor_id;
#endif
}

void STS_SENSOR_Function_Test_Process(void)
{
	char tstbuf[128] =""; uint8_t i=0;

	tstbuf[i++] = (uint8_t) 'S';
	tstbuf[i++] = (uint8_t) sts_mtmcode1;
	tstbuf[i++] = (uint8_t) sts_mtmcode2;
	tstbuf[i++] = (uint8_t) sts_version;
	tstbuf[i++] = (uint8_t) sts_hardware_ver;
	tstbuf[i++] = (uint8_t) (99*GetBatteryLevel()/254)&0xff;

#if	(defined(STS_P2)||defined(STS_T6))
	STS_SENSOR_MEMS_Get_ID(&sensor_id);

	if (((sensor_id & 0xff)!= 0xCC) && (((sensor_id >>8) & 0xFF)!=0xEA))		// no VL53L1X found
	{
		tstbuf[i++] = (uint8_t) 'X'; // Slave MEMS Not Avaliable
	} else
	{
		STS_SENSOR_Distance_Test_Process();
		APP_LOG(TS_OFF, VLEVEL_M, "\nSensor Install Height =%4d mm\n", sts_sensor_install_height);
		tstbuf[i++] = (uint8_t) (2)&0xff;								//length of following data
		tstbuf[i++] = (uint8_t) (sts_sensor_install_height>>8)&0xff;	// MSB of sensor height
		tstbuf[i++] = (uint8_t) (sts_sensor_install_height)&0xff;		// LSB of sensor height
	}
	/*                                                                                    */
	/* for STS_P2, set ppc_config -> door_jam_profile and distance threshold accordingly  */
	/*                                                                                    */

	if ((sts_sensor_install_height >= 1500)&&(sts_sensor_install_height<=4000))
		{
		 sts_door_jam_profile = DOOR_JAM_2000;	// DOOR_JAM_2000: assume door_jame less 2000mm

		 if (sts_sensor_install_height >= 2000)
			 sts_door_jam_profile ++;							//DOOR_JAM_2400
		 if (sts_sensor_install_height >= 2400)
			 sts_door_jam_profile ++;							//DOOR_JAM_3000
		 if (sts_sensor_install_height >= 3000)
			 sts_door_jam_profile ++;					//DOOR_JAM_3500
		 if (sts_sensor_install_height >= 3500)
			 sts_door_jam_profile ++;					//DOOR_JAM_4000
		}
#endif
#ifdef YUNHORN_STS_O6_ENABLED
		tstbuf[i++] = (uint8_t)20; //length of following data
		uint8_t self_test_result[10]={0,0,0,0,0, 0,0,0,0,0};

		STS_PRESENCE_SENSOR_Function_Test_Process(&self_test_result[0], count);

		for (uint8_t j=0; j < 10; j++)
			tstbuf[i++] = (uint8_t) (self_test_result[j])&0xff;

		STS_PRESENCE_SENSOR_Distance_Measure_Process();

		tstbuf[i++] = (uint8_t) ((((uint16_t)sts_distance_rss_distance)/1000)%10+0x30)&0xff;
		tstbuf[i++] = (uint8_t) ((((uint16_t)sts_distance_rss_distance)/100)%10+0x30)&0xff;
		tstbuf[i++] = (uint8_t) ((((uint16_t)sts_distance_rss_distance)/10)%10+0x30)&0xff;
		tstbuf[i++] = (uint8_t) (((uint16_t)sts_distance_rss_distance)%10+0x30)&0xff;
#endif

#if	(defined(STS_R1D))
		tstbuf[i++] = (uint8_t) (4)&0xff;
#elif (defined(STS_R5)||defined(STS_R1))
		tstbuf[i++] = (uint8_t) (2)&0xff;
#endif
		//MX_TOF_Process();
#ifdef STS_P2
		MX_TOF_Init();
		MX_TOF_Ranging_Process();
#endif
#ifdef	VL53L0
		PME_ON;
		STS_TOF_VL53L0X_Range_Process();
		PME_OFF;
#endif

#ifdef	TOF_1
		tstbuf[i++] = (uint8_t) ((sts_tof_distance_data[0] >>8 ) &0xff);
		tstbuf[i++] = (uint8_t) (sts_tof_distance_data[0]  &0xff);
#endif
#ifdef	TOF_2
		tstbuf[i++] = (uint8_t) ((sts_tof_distance_data[1] >>8 ) &0xff);
		tstbuf[i++] = (uint8_t) (sts_tof_distance_data[1]  &0xff);
#endif
#ifdef	TOF_3
		tstbuf[i++] = (uint8_t) ((sts_tof_distance_data[2] >>8 ) &0xff);
		tstbuf[i++] = (uint8_t) (sts_tof_distance_data[2]  &0xff);
#endif


	UTIL_MEM_set_8((void*)outbuf,0x0,sizeof(outbuf));
	UTIL_MEM_cpy_8((void*)outbuf, tstbuf, i);

	STS_SENSOR_Upload_Message(YUNHORN_STS_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf);

}


/**
  * @brief  Yunhorn STS Occupancy RSS WakeUP timer callback function, act as sampling process
  * @param  context ptr of STS RSS WakeUp context
  */
void OnYunhornSTSOORSSWakeUpTimerEvent(void *context)
{
#if 0
	if ((sts_work_mode == STS_RSS_MODE)||(sts_work_mode == STS_DUAL_MODE)||(sts_work_mode == STS_UNI_MODE))
	{
		UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP2), CFG_SEQ_Prio_0);

		if ((sts_rss_result_changed_flag == 1) || (sts_fall_rising_detected_result_changed_flag == 1))
		{
			//SendTxData();
			sts_rss_result_changed_flag = 0;
			sts_fall_rising_detected_result_changed_flag = 0;

			UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0);
			//if ((last_sts_rss_result ==STS_RESULT_NO_MOTION)&& (sts_rss_result==STS_RESULT_MOTION))
				{
					//OnSensor3StateChanged();
				}
		}

	}

	UTIL_TIMER_Start(&YunhornSTSRSSWakeUpTimer);
#endif
}

/**
  * @brief  Yunhorn STS Sensor Heart Beat Timer callback function
  * @param  context ptr of STS Sampling Check context
  */
#if 0
void OnYunhornSTSHeartBeatTimerEvent(void *context)
{
#if 0
	uint8_t appDataPort, appBufferSize, appDataBuffer[32];
	appDataPort = YUNHORN_STS_P2_LORA_APP_HTBT_PORT;
	appBufferSize = 2;
	appDataBuffer[0]=0x80;
	appDataBuffer[1]=0x63;  //TODO XXX change to battery level %

    STS_SENSOR_Upload_Message(appDataPort, appBufferSize, (uint8_t*)appDataBuffer);

	if ((sts_ac_code[0]==0x0) && (sts_ac_code[19]==0x0))		/* simple validation of non-empty ac code */
	{
	  		/* RFAC  Challenge */
	  		if (rfac_timer < (STS_BURN_IN_RFAC+3)) {
	  			rfac_timer ++;
	  		}
	  		//STS_YunhornSTSEventRFAC_Process();
	   		UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), CFG_SEQ_Prio_0);
	}
	UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer);
#endif
}
#endif

/**
  * @brief  Yunhorn STS  Sensor Live Heart Beat Periodicity/interval Change callback function
  * @param  context ptr of STS Live Heart Beat context
  * YL x x x
  * */


/**
  * @brief  Yunhorn STS  Sensor Sampling Periodicity/interval Change callback function
  * @param  context ptr of STS RSS WakeUp context
  */

void OnYunhornSTSSamplingPeriodicityChanged(uint32_t periodicity)
{
  /* USER CODE BEGIN OnTxPeriodicityChanged_1 */

  /* USER CODE END OnTxPeriodicityChanged_1 */

  if (periodicity == 0)
  {
    /* Revert to application default periodicity */
	  periodicity = APP_TX_DUTYCYCLE;
  }

  /* Update timer periodicity */

#if	defined(STS_O6)||defined(STS_O7)
	  UTIL_TIMER_Stop(&YunhornSTSRSSWakeUpTimer);
	  UTIL_TIMER_SetPeriod(&YunhornSTSRSSWakeUpTimer, periodicity);
	  UTIL_TIMER_Start(&YunhornSTSRSSWakeUpTimer);
	  APP_LOG(TS_OFF, VLEVEL_M,"**************** Sampling Timer Periodicity = %u (sec)\r\n", (SamplingPeriodicity/1000) );
#else
#ifdef	STS_E2
  UTIL_TIMER_Stop(&YunhornSTSSamplingCheckTimer);
  UTIL_TIMER_SetPeriod(&YunhornSTSSamplingCheckTimer, periodicity);
  UTIL_TIMER_Start(&YunhornSTSSamplingCheckTimer);
  APP_LOG(TS_OFF, VLEVEL_M,"**************** SamplingPeriodicity = %u (sec)\r\n", (SamplingPeriodicity/1000) );
#endif
#endif
  /* USER CODE BEGIN OnTxPeriodicityChanged_2 */

  /* USER CODE END OnTxPeriodicityChanged_2 */
}


/* USER CODE BEGIN EF */

/* USER CODE END EF */

/* Private Functions Definition -----------------------------------------------*/
/* USER CODE BEGIN PrFD */

/* USER CODE END PrFD */
