/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file lora_app.c * @author Yunhorn (r) Technology Limited Application Team * @brief Application of the LRWAN Middleware ****************************************************************************** * @attention * * Copyright (c) 2023 Yunhorn Technology Limited. * Copyright (c) 2023 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 "platform.h" #include "sys_app.h" #include "lora_app.h" #include "stm32_seq.h" #include "stm32_timer.h" #include "utilities_def.h" #include "app_version.h" #include "lorawan_version.h" #include "subghz_phy_version.h" #include "lora_info.h" #include "LmHandler.h" #include "adc_if.h" #include "CayenneLpp.h" #include "sys_sensors.h" #include "flash_if.h" #include "main.h" #ifdef CLOCK_SYNC #include "LmhpClockSync.h" #endif /* USER CODE BEGIN Includes */ #include "tim.h" #include "sts_lamp_bar.h" #include "yunhorn_sts_sensors.h" #include "sts_cmox_hmac_sha.h" /* USER CODE END Includes */ /* External variables ---------------------------------------------------------*/ /* USER CODE BEGIN EV */ extern volatile uint8_t sts_service_mask; extern volatile uint32_t rfac_timer; volatile uint8_t sts_ac_code[YUNHORN_STS_AC_CODE_SIZE]={0x0}; extern hmac_result_t hmac_result; extern volatile uint8_t sts_hall1_read, sts_hall2_read, sts_hall3_read, sts_hall4_read; volatile uint8_t last_sts_hall1_read=STS_Status_Door_Open, last_sts_hall2_read=STS_Status_SOS_Release, last_sts_hall3_read=STS_Status_Door_Open, last_sts_hall4_read=STS_Status_Door_Open ; volatile uint8_t sts_reed_hall_result =0, sts_emergency_button_pushed=0; // inital 0 = close extern volatile uint8_t sts_work_mode, sts_cloud_netcolor, sts_lamp_bar_color, sts_status_color; extern volatile uint8_t sts_lamp_bar_flashing_color; volatile uint8_t last_sts_lamp_bar_color=STS_DARK; extern volatile uint8_t sts_rss_result; extern volatile uint8_t sts_rss_result_changed_flag, sts_hall1_changed_flag, sts_hall2_changed_flag, sts_reed_hall_changed_flag; volatile uint8_t sts_fall_detection_acc_threshold = 10, sts_fall_detection_depth_threshold=20, sts_fall_confirm_threshold_in_10sec=1, sts_occupancy_overtime_threshold_in_10min=2; volatile uint8_t sts_unconscious_or_motionless_level_threshold=6; //6*128 volatile uint8_t sts_motionless_duration_threshold_in_min=1; // test mode, 1 min, normal 10 min. long occupation 30 min volatile uint16_t sts_unconscious_level_threshold=600; volatile uint8_t sts_alarm_mute_reset_timer_in_10sec=6; extern volatile uint8_t sts_fall_rising_detected_result; extern volatile uint32_t event_start_time, event_stop_time; extern volatile uint16_t sts_unconscious_threshold; volatile uint8_t sts_occupancy_overtime_state = 0; volatile uint8_t sts_presence_fall_detection=TRUE; volatile uint32_t SamplingPeriodicity = 3000; //unit ms volatile uint32_t HeartBeatPeriodicity = 120000; //unit ms volatile uint8_t STS_LoRa_WAN_Joined = 0; volatile uint8_t upload_message_timer=0; volatile uint8_t heart_beat_timer =0; volatile uint32_t wcnt=0; volatile bool p2_work_finished=true; uint8_t outbuf[255]={0x0}; volatile static bool r_b=true; volatile sts_cfg_nvm_t sts_cfg_nvm = { sts_mtmcode1, sts_mtmcode2, sts_version, sts_hardware_ver, 0x05, 'M', //Uplink data interval for heart-beat uplink 0x03, 'S', //Sampling sensor interval for real-time sensing of MEMS 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 0x00, //intra frame weight, 0x00=[0]*0.1=0.0F 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 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} }; #if defined(STS_O6)||defined(STS_O7) extern volatile uint8_t sensor_data_ready; extern volatile STS_OO_SensorStatusDataTypeDef sts_o7_sensorData; extern volatile float sts_distance_rss_distance, sts_sensor_install_height; //#define STS_Status_Door_Close (1) //Normal Close NC:Open **2024-07-15 changed //#define STS_Status_Door_Open (0) //Normal Close NC:Close **2024-07-15 changed char sts_door_status_code[2][10]={ "Close", "Open " }; char sts_sos_status_code[2][10]={ "PushDown", "No_Push" }; char sts_lamp_color_code[15][15]={ "Dark", "Green", "Red", "Blue", "Yellow", "Pink", "Cyan", "White", "color_max", //8 "Green_Flash", //0x10 ==16 "Red_Flash", // 0x20 ==32 "Blue_Flash", // 0x30 == 48 "Red_Blue_Flash" //0x23 = 35 }; char sts_work_mode_code[15][25] ={ "NETWORK_MODE", "WIRED_MODE", "REEDSWITCH_MODE", "RSS_MODE", "DUAL_MODE", "UNI_MODE", "REMOTE_REED_RSS_MODE", "DUAL_RSS_MODE", "TOF_RSS_MODE", "TOF_DISTANCE_MODE", "TOF_PRESENCE_MODE", "TOF_IN_OUT_MODE", "FALL_DETECTION_MODE", "OTHER_MODE1", "OTHER_MODE2", }; char sts_fall_mode_code[8][25] = { "State_Normal", "State_Fall_Down", "State_Rising_Up", "State_Laydown", "State_Unconscious", "State_StayStill", "State_No_Movement" }; #endif /* 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 */ #define YUNHORN_STS_RSS_WAKEUP_CHECK_TIME SamplingPeriodicity //3000 ms #define YUNHORN_STS_SAMPLING_CHECK_TIME SamplingPeriodicity #define YUNHORN_STS_HEART_BEAT_CHECK_TIME 300000 //300 sec, 5 min /* 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 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); /** * @brief Yunhorn STS AC Code handle Process * @param void */ static void STS_YUNHORN_RFAC_HANDLE_PROCESS(void); /* USER CODE END PFP */ /* Private variables ---------------------------------------------------------*/ /** * @brief LoRaWAN default activation type */ static ActivationType_t ActivationType = LORAWAN_DEFAULT_ACTIVATION_TYPE; /** * @brief LoRaWAN force rejoin even if the NVM context is restored */ static bool ForceRejoin = LORAWAN_FORCE_REJOIN_AT_BOOT; /** * @brief LoRaWAN handler Callbacks */ static LmHandlerCallbacks_t LmHandlerCallbacks = { .GetBatteryLevel = GetBatteryLevel, .GetTemperature = GetTemperatureLevel, .GetUniqueId = GetUniqueId, .GetDevAddr = GetDevAddr, .OnRestoreContextRequest = OnRestoreContextRequest, .OnStoreContextRequest = OnStoreContextRequest, .OnMacProcess = OnMacProcessNotify, .OnNvmDataChange = OnNvmDataChange, .OnJoinRequest = OnJoinRequest, .OnTxData = OnTxData, .OnRxData = OnRxData, .OnBeaconStatusChange = OnBeaconStatusChange, .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; //TX_ON_TIMER;//TX_ON_EVENT; /** * @brief Timer to handle the application Tx */ static UTIL_TIMER_Object_t TxTimer; /** * @brief Tx Timer period */ static UTIL_TIMER_Time_t TxPeriodicity = APP_TX_DUTYCYCLE; /** * @brief Join Timer period */ static UTIL_TIMER_Object_t StopJoinTimer; /* USER CODE BEGIN PV */ /** * @brief User application buffer */ static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; /** * @brief User application data structure */ static LmHandlerAppData_t AppData = { 0, 0, AppDataBuffer }; /** * @brief Specifies the state of the application LED */ static uint8_t AppLedStateOn = RESET; /** * @brief Timer to handle the application Tx Led to toggle */ static UTIL_TIMER_Object_t TxLedTimer; /** * @brief Timer to handle the application Rx Led to toggle */ static UTIL_TIMER_Object_t RxLedTimer; /** * @brief Timer to handle the application Join Led to toggle */ static UTIL_TIMER_Object_t JoinLedTimer; static volatile bool IsClockSynched = false; /** * @brief Timer to handle the Yunhorn STS Lamp Bar Color Led to toggle */ static UTIL_TIMER_Object_t STSLampBarColorTimer; /** * @brief Timer to handle the Yunhorn STS Lamp Bar Color Led to toggle */ static UTIL_TIMER_Object_t STSDurationCheckTimer; /** * @brief Timer to handle the YunHorn STS RSS WakeUP Checking */ static UTIL_TIMER_Object_t YunhornSTSRSSWakeUpTimer; /** * @brief Timer to handle the YunHorn STS Sensor Sampling Process */ //static UTIL_TIMER_Object_t YunhornSTSSamplingCheckTimer; /** * @brief Timer to handle the YunHorn STS Sensor Heart Beat Process */ static UTIL_TIMER_Object_t YunhornSTSHeartBeatTimer; /* USER CODE END PV */ /* Exported functions ---------------------------------------------------------*/ /* USER CODE BEGIN EF */ /* USER CODE END EF */ void LoRaWAN_Init(void) { /* USER CODE BEGIN LoRaWAN_Init_LV */ uint32_t feature_version = 0UL; /* USER CODE END LoRaWAN_Init_LV */ /* USER CODE BEGIN LoRaWAN_Init_1 */ APP_LOG(TS_OFF, VLEVEL_M, "\r\n\n\n##### YUNHORN_STS_SWV%d HWV:%d MTM:%d.%d R:%d.%d.%d####\r\n\n\n", sts_version, sts_hardware_ver, sts_mtmcode1,sts_mtmcode2, MajorVer, MinorVer, SubMinorVer); /* 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, LED_PERIOD_TIME, UTIL_TIMER_PERIODIC, OnYunhornSTSLampBarColorTimerEvent, NULL); UTIL_TIMER_Create(&STSDurationCheckTimer, 20*LED_PERIOD_TIME, UTIL_TIMER_PERIODIC, 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); // TODO XXX 2024-06-04 #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 */ /// **************************************************************************** TO-DO LIST STS_REBOOT_CONFIG_Init(); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), UTIL_SEQ_RFU, STS_YunhornSTSEventRFAC_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), UTIL_SEQ_RFU, STS_YunhornSTSEventP1_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP2), UTIL_SEQ_RFU, STS_YunhornSTSEventP2_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP3), UTIL_SEQ_RFU, STS_YunhornSTSEventP3_Process); #if 0 UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP4), UTIL_SEQ_RFU, STS_YunhornSTSEventP4_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP5), UTIL_SEQ_RFU, STS_YunhornSTSEventP5_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP6), UTIL_SEQ_RFU, STS_YunhornSTSEventP6_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP7), UTIL_SEQ_RFU, STS_YunhornSTSEventP7_Process); UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_YunhornSTSEventP8), UTIL_SEQ_RFU, STS_YunhornSTSEventP8_Process); #endif #if defined(STS_O7)||defined(STS_O6) UTIL_TIMER_Create(&YunhornSTSRSSWakeUpTimer, YUNHORN_STS_RSS_WAKEUP_CHECK_TIME, UTIL_TIMER_PERIODIC, OnYunhornSTSOORSSWakeUpTimerEvent, NULL); //UTIL_TIMER_Start(&YunhornSTSRSSWakeUpTimer); UTIL_TIMER_Create(&YunhornSTSHeartBeatTimer, YUNHORN_STS_HEART_BEAT_CHECK_TIME, UTIL_TIMER_PERIODIC, OnYunhornSTSHeartBeatTimerEvent, NULL); //UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer); UTIL_TIMER_Start(&STSLampBarColorTimer); UTIL_TIMER_Start(&STSDurationCheckTimer); #else UTIL_TIMER_Create(&YunhornSTSSamplingCheckTimer, YUNHORN_STS_SAMPLING_CHECK_TIME, UTIL_TIMER_PERIODIC, OnYunhornSTSSamplingCheckTimerEvent, NULL); UTIL_TIMER_Start(&YunhornSTSSamplingCheckTimer); #endif /* USER CODE END LoRaWAN_Init_Last */ } /* USER CODE BEGIN PB_Callbacks */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { switch (GPIO_Pin) { #if defined(STS_O6)||defined(STS_O7) case HALL1_Pin: sts_hall1_read = HALL1_STATE; HAL_Delay(30); //de-bouncing if ((sts_hall1_read == HALL1_STATE)) // && (sts_hall1_read == STS_Status_Door_Close)) 2024-07-22 only process door close event { APP_LOG(TS_OFF, VLEVEL_L, "\n\n Door Contact Read = %02x --%s\r\n", sts_hall1_read, sts_door_status_code[sts_hall1_read]); OnSensor1StateChanged(); /* Note: when "EventType == TX_ON_TIMER" this GPIO is not initialized */ // if (EventType == TX_ON_EVENT) { STS_YunhornSTSEventP1_Process(); UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); //SendTxData(); } last_sts_hall1_read = sts_hall1_read; } break; case HALL2_Pin: sts_hall2_read = HALL2_STATE; HAL_Delay(30); //de-bouncing if (sts_hall2_read == HALL2_STATE) { APP_LOG(TS_OFF, VLEVEL_L, "\n\n SOS Button Read = %02x --%s\r\n", sts_hall2_read, sts_sos_status_code[sts_hall2_read]); OnSensor2StateChanged(); //sensor_data_ready =1; //UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), CFG_SEQ_Prio_0); { STS_YunhornSTSEventP1_Process(); UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } last_sts_hall2_read = sts_hall2_read; } break; case HALL3_Pin: sts_hall3_read = HALL3_STATE; HAL_Delay(30); //de-bouncing if (sts_hall3_read == HALL3_STATE) { APP_LOG(TS_OFF, VLEVEL_L, "\n\n ALARM MUTE Button Read = %02x --%s\r\n", sts_hall3_read, sts_sos_status_code[sts_hall3_read]); OnSensor3StateChanged(); //sensor_data_ready =1; //UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), CFG_SEQ_Prio_0); { STS_YunhornSTSEventP1_Process(); UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } last_sts_hall3_read = sts_hall3_read; } break; case HALL4_Pin: sts_hall4_read = HALL4_STATE; HAL_Delay(30); //de-bouncing if (sts_hall4_read == HALL4_STATE) { APP_LOG(TS_OFF, VLEVEL_L, "\n\n ALARM RESET Button Read = %02x --%s\r\n", sts_hall4_read, sts_sos_status_code[sts_hall4_read]); OnSensor4StateChanged(); //sensor_data_ready =1; //UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), CFG_SEQ_Prio_0); { STS_YunhornSTSEventP1_Process(); UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } last_sts_hall4_read = sts_hall4_read; } break; #else case BUT1_Pin: HAL_Delay(20); //de-bouncing UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP1), CFG_SEQ_Prio_0); /* Note: when "EventType == TX_ON_TIMER" this GPIO is not initialized */ // if (EventType == TX_ON_EVENT) { UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } break; case BUT2_Pin: UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStopJoinEvent), CFG_SEQ_Prio_0); break; case BUT3_Pin: UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaStoreContextEvent), CFG_SEQ_Prio_0); break; #endif default: break; } } /* USER CODE END PB_Callbacks */ /* Private functions ---------------------------------------------------------*/ /* USER CODE BEGIN PrFD */ /* USER CODE END PrFD */ static void OnRxData(LmHandlerAppData_t *appData, LmHandlerRxParams_t *params) { /* USER CODE BEGIN OnRxData_1 */ uint8_t RxPort = 0; if (params != NULL) { #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; } } 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(LORAWAN_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 LORAWAN_USER_APP_CTRL_PORT: if (appData->BufferSize != 1) { if (appData->BufferSize < 128) { USER_APP_AUTO_RESPONDER_Parse((char*)appData->Buffer, appData->BufferSize); } } break; default: break; } } } } if (params->RxSlot < RX_SLOT_NONE) { APP_LOG(TS_OFF, VLEVEL_H, "###### D/L FRAME:%04d | PORT:%d | DR:%d | SLOT:%s | RSSI:%d | SNR:%d\r\n", params->DownlinkCounter, RxPort, params->Datarate, slotStrings[params->RxSlot], params->Rssi, params->Snr); } } /* USER CODE END OnRxData_1 */ } static void SendTxData(void) { /* USER CODE BEGIN SendTxData_1 */ LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR; uint8_t batteryLevel = GetBatteryLevel(); //sensor_t sensor_data; STS_OO_SensorStatusDataTypeDef sensorData; UTIL_TIMER_Time_t nextTxIn = 0; if (LmHandlerIsBusy() == false) { uint32_t i = 0; STS_PRESENCE_SENSOR_Prepare_Send_Data(&sensorData); if (sts_work_mode == STS_DUAL_MODE) { AppData.Port = (uint8_t)YUNHORN_STS_O6_LORA_APP_DATA_PORT; } else if (sts_work_mode == STS_UNI_MODE) { AppData.Port = (uint8_t)YUNHORN_STS_O7_LORA_APP_DATA_PORT; } else if ((sts_work_mode == STS_RSS_MODE)||(sts_work_mode == STS_REEDSWITCH_MODE)) { AppData.Port = (uint8_t)YUNHORN_STS_O2_LORA_APP_DATA_PORT; } AppLedStateOn = LED1_STATE; if ((heart_beat_timer != 0L)) // sensor data OVERWRITE heart-beat message, 2024-05-12 { heart_beat_timer=0; if (sts_work_mode == STS_DUAL_MODE) AppData.Port = (uint8_t)YUNHORN_STS_O6_LORA_APP_HTBT_PORT; //LORAWAN_USER_APP_PORT+1; else if (sts_work_mode == STS_UNI_MODE) AppData.Port = (uint8_t)YUNHORN_STS_O7_LORA_APP_HTBT_PORT; //LORAWAN_USER_APP_PORT+1; else if ((sts_work_mode == STS_RSS_MODE)||(sts_work_mode == STS_REEDSWITCH_MODE)) AppData.Port = (uint8_t)YUNHORN_STS_O2_LORA_APP_HTBT_PORT; //LORAWAN_USER_APP_PORT+1; //AppData.Port = (uint8_t)sts_sendhtbtport; //LORAWAN_USER_APP_PORT+1; AppData.Buffer[i++] = (uint8_t)(AppLedStateOn|0x80)&0x0ff; AppData.Buffer[i++] = (uint8_t)(99*batteryLevel/254)&0xff; //#05 } else if ((sensor_data_ready!= 0U)) //sensor_data_ready for manual push button-1 trigger) { sensor_data_ready =0; if (sts_work_mode > STS_RSS_MODE) // keep compatible with previous version, PIXEL-NETWORK { AppData.Buffer[i++] = (uint8_t)(AppLedStateOn|0x80)&0x0ff; //00 ************ MUST KEEP IT HERE, NON-ZERO ****** } AppData.Buffer[i++] = (uint8_t)(sensorData.lamp_bar_color)&0xff; //01 AppData.Buffer[i++] = (uint8_t)(sensorData.workmode)&0xff; //02 WORK MODE if (sts_work_mode == STS_REEDSWITCH_MODE) { AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor1_on_off)&0xff; //03 Sensor head #1 status reed switch AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor2_on_off)&0xff; //04 Sensor head #2 status reed switch } else if (sts_work_mode == STS_RSS_MODE) { AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor1_on_off)&0xff; //03 Sensor head #1 status reed switch AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor3_on_off)&0xff; //04 Sensor head #3 status RSS motion } else if (sts_work_mode == STS_DUAL_MODE) { AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor1_on_off)&0xff; //03 Sensor head #1 status reed switch AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor2_on_off)&0xff; //04 Sensor head #2 status SOS button AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor3_on_off)&0xff; //05 Sensor head #3 status RSS motion AppData.Buffer[i++] = (uint8_t)(sensorData.over_stay_state)&0xff; //06 occupancy over time or not AppData.Buffer[i++] = (uint8_t)(sensorData.over_stay_duration>>8)&0xff; //07 occupancy over stay duration MSB AppData.Buffer[i++] = (uint8_t)(sensorData.over_stay_duration)&0xff; //08 occupancy over stay duration LSB } else if (sts_work_mode == STS_UNI_MODE) { AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor1_on_off)&0xff; //03 Sensor head #1 status reedswitch AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor2_on_off)&0xff; //04 Sensor head #2 status SOS button AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor3_on_off)&0xff; //05 Sensor head #3 status RSS motion AppData.Buffer[i++] = (uint8_t)(sensorData.state_sensor4_on_off)&0xff; //06 Sensor head #4 status reserved AppData.Buffer[i++] = (uint8_t)(sensorData.rss_presence_distance>>8)&0xff; //07 MSB distance AppData.Buffer[i++] = (uint8_t)(sensorData.rss_presence_distance)&0xff; //08 LSB distance AppData.Buffer[i++] = (uint8_t)(sensorData.rss_presence_score>>8)&0xff; //09 MSB score AppData.Buffer[i++] = (uint8_t)(sensorData.rss_presence_score)&0xff; //10 LSB score AppData.Buffer[i++] = (uint8_t)(sensorData.unconscious_state)&0xff; //11 unconscious state detected or not AppData.Buffer[i++] = (uint8_t)(sensorData.fall_state)&0xff; //12 fall detected or not AppData.Buffer[i++] = (uint8_t)(sensorData.over_stay_state)&0xff; //13 occupancy over time or not AppData.Buffer[i++] = (uint8_t)(sensorData.over_stay_duration>>8)&0xff; //14 occupancy over stay duration MSB AppData.Buffer[i++] = (uint8_t)(sensorData.over_stay_duration)&0xff; //15 occupancy over stay duration LSB AppData.Buffer[i++] = (uint8_t)(sensorData.no_movement_duration>>8)&0xff; //16 occupancy over stay duration LSB AppData.Buffer[i++] = (uint8_t)(sensorData.no_movement_duration)&0xff; //17 occupancy over stay duration LSB AppData.Buffer[i++] = (uint8_t)(sensorData.fall_speed)&0xff; //18 fall detected speed AppData.Buffer[i++] = (uint8_t)(sensorData.fall_gravity)&0xff; //19 fall detected gravity AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_start_timestamp>>24)&0xff; //20 SOS start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_start_timestamp>>16)&0xff; //21 SOS start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_start_timestamp>>8)&0xff; //22 SOS start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_start_timestamp)&0xff; //23 SOS start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_stop_timestamp>>24)&0xff; //24 SOS stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_stop_timestamp>>16)&0xff; //25 SOS stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_stop_timestamp>>8)&0xff; //26 SOS stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor2_stop_timestamp)&0xff; //27 SOS stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_start_time_stamp>>24)&0xff; //28 fall start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_start_time_stamp>>16)&0xff; //29 fall start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_start_time_stamp>>8)&0xff; //30 fall start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_start_time_stamp)&0xff; //31 fall start time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_stop_time_stamp>>24)&0xff; //32 fall stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_stop_time_stamp>>16)&0xff; //33 fall stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_stop_time_stamp>>8)&0xff; //34 fall stop time stamp AppData.Buffer[i++] = (uint8_t)(sensorData.event_sensor3_fall_stop_time_stamp)&0xff; //35 fall stop time stamp } uint8_t ich= (sts_lamp_bar_color>>4 & 0x0f); uint8_t icl= (sts_lamp_bar_color & 0x0f); char colorshow[30]=""; strcpy(colorshow, (ich==0)?"":sts_lamp_color_code[ich]); APP_LOG(TS_OFF, VLEVEL_L, "\r\n######| Color = %s%s | Mode = %5s |\r\n",(char *)colorshow, sts_lamp_color_code[icl], (char*)sts_work_mode_code[sensorData.workmode]); if (sts_work_mode == STS_UNI_MODE) { APP_LOG(TS_OFF, VLEVEL_L, "\r\n######| S1-Door | S2-SOS | S3-Motion | S4 |Distance(mm) | MotionScore| Unconscious | Over_Stay_(min) | Fall Detected|" "\r\n######| %s | %s | %d | %1d | %04d | %04d | %1d | %4d | %s |\r\n", sts_door_status_code[sensorData.state_sensor1_on_off], sts_sos_status_code[sensorData.state_sensor2_on_off], sensorData.state_sensor3_on_off, sensorData.state_sensor4_on_off, (uint16_t)sensorData.rss_presence_distance,(uint16_t)sensorData.rss_presence_score, sensorData.unconscious_state, sensorData.over_stay_duration, sts_fall_mode_code[sensorData.fall_state]); } else if (sts_work_mode == STS_DUAL_MODE) { APP_LOG(TS_OFF, VLEVEL_L, "\r\n######| S1-Door | S2-SOS | S3-Motion |\r\n" "\r\n######| %s | %s | %d |\r\n", sts_door_status_code[sensorData.state_sensor1_on_off], sts_sos_status_code[sensorData.state_sensor2_on_off], sensorData.state_sensor3_on_off); } } 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); #ifndef STM32WLE5xx HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */ #endif } status = LmHandlerSend(&AppData, LmHandlerParams.IsTxConfirmed, false); if (LORAMAC_HANDLER_SUCCESS == status) { APP_LOG(TS_ON, VLEVEL_M, "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)); } } } if (EventType == TX_ON_TIMER) { UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, MAX(nextTxIn, TxPeriodicity)); UTIL_TIMER_Start(&TxTimer); } /* USER CODE END SendTxData_1 */ } static void OnTxTimerEvent(void *context) { /* USER CODE BEGIN OnTxTimerEvent_1 */ /* USER CODE END OnTxTimerEvent_1 */ UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); /*Wait for next tx slot*/ UTIL_TIMER_Start(&TxTimer); /* USER CODE BEGIN OnTxTimerEvent_2 */ /* USER CODE END OnTxTimerEvent_2 */ } /* USER CODE BEGIN PrFD_LedEvents */ static void OnTxTimerLedEvent(void *context) { #ifndef STM32WLE5xx HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); /* LED_GREEN */ #endif } static void OnRxTimerLedEvent(void *context) { #ifndef STM32WLE5xx HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); /* LED_BLUE */ #endif } static void OnJoinTimerLedEvent(void *context) { #ifndef STM32WLE5xx HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin); /* LED_RED */ #endif //HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); /* STS GREEN */ if ((sts_work_mode != STS_WIRED_MODE)) UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP3), CFG_SEQ_Prio_0); } /* USER CODE END PrFD_LedEvents */ static void OnYunhornSTSLampBarColorTimerEvent(void *context) { //uint8_t lum=DEFAULT_LUMINANCE_LEVEL; //HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); /* STS GREEN */ //if ((sts_work_mode != STS_WIRED_MODE)) uint8_t high4=(sts_lamp_bar_color>>4)&0x0f, low4=sts_lamp_bar_color&0x0f; if (high4==0) { if (last_sts_lamp_bar_color != sts_lamp_bar_color) { __disable_irq(); STS_Lamp_Bar_Set_STS_RGB_Color(sts_lamp_bar_color, DEFAULT_LUMINANCE_LEVEL); __enable_irq(); //STS_WS2812B_Refresh(); last_sts_lamp_bar_color = sts_lamp_bar_color; } } else { if (r_b) { //__disable_irq(); STS_Lamp_Bar_Set_STS_RGB_Color(high4, DEFAULT_LUMINANCE_LEVEL); //__enable_irq(); last_sts_lamp_bar_color = high4; //STS_WS2812B_Refresh(); } else { //__disable_irq(); STS_Lamp_Bar_Set_STS_RGB_Color(low4, DEFAULT_LUMINANCE_LEVEL); //__enable_irq(); last_sts_lamp_bar_color = low4; //STS_WS2812B_Refresh(); } r_b = !r_b; } } static void OnYunhornSTSDurationCheckTimerEvent(void *context) { static bool over_threshold = FALSE; SysTime_t current_time = SysTimeGetMcuTime(); if (STS_Status_Door_Close==sts_hall1_read) { sts_o7_sensorData.event_sensor1_duration = current_time.Seconds - sts_o7_sensorData.event_sensor1_start_time; //if (sts_o7_sensorData.event_sensor1_duration > sts_occupancy_overtime_threshold_in_10min*600) if (sts_o7_sensorData.event_sensor1_duration > (sts_occupancy_overtime_threshold_in_10min*60)) //for debug { sts_o7_sensorData.over_stay_state = 1; sts_o7_sensorData.over_stay_duration = sts_o7_sensorData.event_sensor1_duration; over_threshold = TRUE; APP_LOG(TS_OFF, VLEVEL_L, "\r\nSensor 1 Over Stay State=%d, Duration= %d Sec, Threshold =%u \r\n", sts_o7_sensorData.over_stay_state, (sts_o7_sensorData.over_stay_duration), (sts_occupancy_overtime_threshold_in_10min*60) ); sts_lamp_bar_color = STS_RED_DARK; //sts_lamp_bar_flashing_color = 0x20; //volatile uint8_t sts_lamp_bar_color = STS_GREEN; //puColor //volatile uint8_t sts_lamp_bar_flashing_color = 0x23; // RED_BLUE; } } else { sts_o7_sensorData.event_sensor1_duration =0; sts_o7_sensorData.over_stay_state = 0; } // to be defined later for SOS threshold TODO XXXX if (STS_Status_SOS_Pushdown==sts_hall2_read) { sts_o7_sensorData.event_sensor2_duration = current_time.Seconds - sts_o7_sensorData.event_sensor2_start_time; if (sts_o7_sensorData.event_sensor2_duration > sts_occupancy_overtime_threshold_in_10min*60) //for debug { sts_o7_sensorData.over_stay_state = 1; // 2024-07-15 update, no overwrite sensor1 duration value //sts_o7_sensorData.over_stay_duration = sts_o7_sensorData.event_sensor2_duration; // over_threshold = TRUE; } // to be defiend later for SOS threshold TODO XXXX } else { sts_o7_sensorData.event_sensor2_duration =0; //sts_o7_sensorData.over_stay_state = 0; } if (sts_rss_result==STS_RESULT_MOTION) { sts_o7_sensorData.event_sensor3_motion_duration = current_time.Seconds - sts_o7_sensorData.event_sensor3_motion_start_time; //if (sts_o7_sensorData.event_sensor3_motion_duration > sts_occupancy_overtime_threshold_in_10min*600) if (sts_o7_sensorData.event_sensor3_motion_duration > sts_occupancy_overtime_threshold_in_10min*60) //for debug { sts_o7_sensorData.occupancy_over_stay_state = 1; sts_o7_sensorData.occupancy_duration =sts_o7_sensorData.event_sensor3_motion_duration; over_threshold = TRUE; } } else { sts_o7_sensorData.event_sensor3_motion_duration =0; //sts_o7_sensorData.occupancy_over_stay_state = 0; } /* STS_PRESENCE_NONE=0, STS_PRESENCE_FALL, STS_PRESENCE_RISING, STS_PRESENCE_LAYDOWN, STS_PRESENCE_UNCONSCIOUS, STS_PRESENCE_STAYSTILL */ uint32_t time_stamp=STS_Get_Date_Time_Stamp(); //uint8_t datetimestamp[8]={0}; //(&time_stamp, datetimestamp); switch (sts_fall_rising_detected_result){ case STS_PRESENCE_NORMAL: sts_o7_sensorData.fall_state = STS_PRESENCE_NORMAL; sts_o7_sensorData.fall_laydown_duration=0; sts_o7_sensorData.unconscious_state =STS_PRESENCE_NORMAL; sts_o7_sensorData.unconscious_duration =0; sts_o7_sensorData.no_movement_duration =0; break; case STS_PRESENCE_FALL: // sts_fall_confirm_threshold_in_10sec sts_o7_sensorData.event_sensor3_fall_duration = current_time.Seconds - sts_o7_sensorData.event_sensor3_fall_start_time; if (sts_o7_sensorData.event_sensor3_fall_duration > 10*sts_cfg_nvm.fall_confirm_threshold_in_10sec) { //sts_o7_sensorData.occupancy_over_stay_state = 1; //sts_o7_sensorData.event_sensor3_fall_start_time_stamp = time_stamp; sts_o7_sensorData.fall_state = sts_fall_rising_detected_result; sts_o7_sensorData.fall_laydown_duration =sts_o7_sensorData.event_sensor3_fall_duration; over_threshold = TRUE; } else { // still laydown, but not over fall down confirmation threshold sts_o7_sensorData.fall_state = STS_PRESENCE_LAYDOWN; sts_o7_sensorData.fall_laydown_duration =sts_o7_sensorData.event_sensor3_fall_duration; over_threshold = FALSE; } break; case STS_PRESENCE_RISING: sts_o7_sensorData.event_sensor3_fall_stop_time_stamp = time_stamp; over_threshold = FALSE; break; case STS_PRESENCE_LAYDOWN: break; case STS_PRESENCE_UNCONSCIOUS: case STS_PRESENCE_STAYSTILL: case STS_PRESENCE_NO_MOVEMENT: sts_o7_sensorData.fall_state = sts_fall_rising_detected_result; sts_o7_sensorData.event_sensor3_no_movement_duration = current_time.Seconds - sts_o7_sensorData.event_sensor3_no_movement_start_time; sts_o7_sensorData.event_sensor3_unconcious_duration = current_time.Seconds - sts_o7_sensorData.event_sensor3_unconcious_start_time; // sts_motionless_duration_threshold_in_min if ((sts_o7_sensorData.event_sensor3_no_movement_duration > sts_cfg_nvm.motionless_duration_threshold_in_min*60)|| (sts_o7_sensorData.unconscious_duration > sts_cfg_nvm.motionless_duration_threshold_in_min*60)) { sts_o7_sensorData.unconscious_state = 1; over_threshold = TRUE; } break; } #if 0 if (sts_xxx_result == xxx) sts_o7_sensorData.event_sensor3_event_duration = sensor_event_time.Seconds - sts_o7_sensorData.event_sensor4_start_time; #endif if (over_threshold == TRUE) { if (sts_o7_sensorData.fall_state == STS_PRESENCE_LAYDOWN) { sts_status_color = sts_lamp_bar_flashing_color; //STS_RED_BLUE; sts_lamp_bar_color = sts_lamp_bar_flashing_color; //STS_RED_BLUE; } else { sts_status_color = STS_RED_DARK; sts_lamp_bar_color = STS_RED_DARK; //sts_lamp_bar_flashing_color; } sensor_data_ready = 1; UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); over_threshold = FALSE; } } 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) { #ifndef STM32WLE5xx HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); /* LED_GREEN */ #endif 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); sts_lamp_bar_color = STS_GREEN; #ifndef STM32WLE5xx HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */ #endif APP_LOG(TS_OFF, VLEVEL_M, "\r\n###### = JOINED = "); if (joinParams->Mode == ACTIVATION_TYPE_ABP) { APP_LOG(TS_OFF, VLEVEL_M, "ABP ======================\r\n"); } else { APP_LOG(TS_OFF, VLEVEL_M, "OTAA =====================\r\n"); } STS_LoRa_WAN_Joined = (uint8_t) joinParams->Mode; APP_LOG(TS_OFF, VLEVEL_L,"\r\n STS_LoRa_WAN_Joined = %s \r\n", (STS_LoRa_WAN_Joined == 1)?"ABP":"OTAA"); } 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); } heart_beat_timer = 1; //SendTxData(); UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); UTIL_TIMER_Start(&YunhornSTSRSSWakeUpTimer); //UTIL_TIMER_Start(&TxTimer); //UTIL_TIMER_Start(&STSDurationCheckTimer); OnYunhornSTSHeartBeatPeriodicityChanged(HeartBeatPeriodicity); /* 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_H, "Switch to Class %c done\r\n", "ABC"[deviceClass]); /* USER CODE END OnClassChange_1 */ } static void OnMacProcessNotify(void) { /* USER CODE BEGIN OnMacProcessNotify_1 */ /* USER CODE END OnMacProcessNotify_1 */ UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LmHandlerProcess), CFG_SEQ_Prio_0); /* USER CODE BEGIN OnMacProcessNotify_2 */ /* USER CODE END OnMacProcessNotify_2 */ } static void OnTxPeriodicityChanged(uint32_t periodicity) { /* USER CODE BEGIN OnTxPeriodicityChanged_1 */ /* USER CODE END OnTxPeriodicityChanged_1 */ TxPeriodicity = periodicity; if (TxPeriodicity == 0) { /* Revert to application default periodicity */ TxPeriodicity = APP_TX_DUTYCYCLE; } /* Update timer periodicity */ UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, TxPeriodicity); UTIL_TIMER_Start(&TxTimer); /* USER CODE BEGIN OnTxPeriodicityChanged_2 */ APP_LOG(TS_OFF, VLEVEL_H,"**************** TxPeriodicity = %u (sec)\r\n", (TxPeriodicity/1000) ); /* 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 */ #ifndef STM32WLE5xx 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 */ #endif /* 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 Yunhorn STS Occupancy RSS WakeUP timer callback function, act as sampling process * @param context ptr of STS RSS WakeUp context */ static void OnYunhornSTSOORSSWakeUpTimerEvent(void *context) { UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP2), CFG_SEQ_Prio_0); //APP_LOG(TS_OFF,VLEVEL_L,"\r\n RSS result changed flag=%d \r\n", sts_rss_result_changed_flag); if ((STS_LoRa_WAN_Joined != 0)&&(sts_rss_result_changed_flag==1)) { sts_rss_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); } /** * @brief Yunhorn STS Sensor Heart Beat Timer callback function * @param context ptr of STS Sampling Check context */ static void OnYunhornSTSHeartBeatTimerEvent(void *context) { heart_beat_timer = 1; UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); if ((STS_LoRa_WAN_Joined ) && (sts_ac_code[0]==0x0) && (sts_ac_code[19]==0x0)) { /* RFAC Challenge */ if (rfac_timer < (STS_BURN_IN_RFAC+3)) { rfac_timer ++; } UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventRFAC), CFG_SEQ_Prio_0); } UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer); } /** * @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 * */ static void OnYunhornSTSHeartBeatPeriodicityChanged(uint32_t periodicity) { /* USER CODE BEGIN OnTxPeriodicityChanged_1 */ /* USER CODE END OnTxPeriodicityChanged_1 */ HeartBeatPeriodicity = periodicity; if (HeartBeatPeriodicity == 0) { /* Revert to application default periodicity */ HeartBeatPeriodicity = 10*APP_TX_DUTYCYCLE; } /* Update timer periodicity */ UTIL_TIMER_Stop(&YunhornSTSHeartBeatTimer); UTIL_TIMER_SetPeriod(&YunhornSTSHeartBeatTimer, HeartBeatPeriodicity); UTIL_TIMER_Start(&YunhornSTSHeartBeatTimer); /* USER CODE BEGIN OnTxPeriodicityChanged_2 */ APP_LOG(TS_OFF, VLEVEL_H,"**************** HeartBeatPeriodicity = %u (sec)\r\n", HeartBeatPeriodicity/1000 ); /* USER CODE END OnTxPeriodicityChanged_2 */ } /** * @brief Yunhorn STS Sensor Sampling Periodicity/interval Change callback function * @param context ptr of STS RSS WakeUp context */ static void OnYunhornSTSSamplingPeriodicityChanged(uint32_t periodicity) { /* USER CODE BEGIN OnTxPeriodicityChanged_1 */ /* USER CODE END OnTxPeriodicityChanged_1 */ SamplingPeriodicity = periodicity; if (SamplingPeriodicity == 0) { /* Revert to application default periodicity */ SamplingPeriodicity = APP_TX_DUTYCYCLE; } /* Update timer periodicity */ #if defined(STS_O6)||defined(STS_O7) UTIL_TIMER_Stop(&YunhornSTSRSSWakeUpTimer); UTIL_TIMER_SetPeriod(&YunhornSTSRSSWakeUpTimer, SamplingPeriodicity); UTIL_TIMER_Start(&YunhornSTSRSSWakeUpTimer); APP_LOG(TS_OFF, VLEVEL_M,"**************** Sampling Timer Periodicity = %u (sec)\r\n", (SamplingPeriodicity/1000) ); #else UTIL_TIMER_Stop(&YunhornSTSSamplingCheckTimer); UTIL_TIMER_SetPeriod(&YunhornSTSSamplingCheckTimer, SamplingPeriodicity); UTIL_TIMER_Start(&YunhornSTSSamplingCheckTimer); APP_LOG(TS_OFF, VLEVEL_M,"**************** SamplingPeriodicity = %u (sec)\r\n", (SamplingPeriodicity/1000) ); #endif /* USER CODE BEGIN OnTxPeriodicityChanged_2 */ /* USER CODE END OnTxPeriodicityChanged_2 */ } /** * @brief Yunhorn STS Sensor Sampling Check Timer callback function * @param context ptr of STS Sampling Check context */ /* static void OnYunhornSTSSamplingCheckTimerEvent(void *context) { // P1 --- REEDSWITCH, HALL ELEMENT, WATER LEAKAGE, ********** NOT FOR THIS EVENT TRIGGER PROCESS // 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 ****** NOT FOR THIS REAL-TIME FULL BLOCKED DETECTION // P6 --- // P7 --- // P8 --- AIR QUALITY AND ODOR LEVEL, SMOKING DETECTION UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_YunhornSTSEventP2), CFG_SEQ_Prio_0); if (STS_LoRa_WAN_Joined != 0) { UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LoRaSendOnTxTimerOrButtonEvent), CFG_SEQ_Prio_0); } } */ /* * 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 * */ void USER_APP_AUTO_RESPONDER_Parse(char *tlv_buf, uint8_t tlv_buf_size) { uint8_t i=0, mems_ver, invalid_flag=1; UTIL_MEM_set_8((void*)outbuf,0x0, sizeof(outbuf)); if (((char)tlv_buf[CFG_CMD1] == 'Y') && (tlv_buf_size <=5)) // BEGIN OF *** BOARD LEVEL CONTROL OR REPORT { switch ((char)tlv_buf[CFG_CMD2]) { case 'Z': //"YZ" if ((char)tlv_buf[CFG_CMD3] == 'H') { //BOARD SOFT RESET, REVIVE "YZH" //BOARD REVIVE STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, 20, (uint8_t*)"!YunHorn STS Revive!"); HAL_Delay(5000); APP_LOG(TS_OFF, VLEVEL_H, "\r\n Yunhorn STS Node Revive ... \r\n"); HAL_Delay(3000); __set_FAULTMASK(1); OnSystemReset(); } else if ((char)tlv_buf[CFG_CMD3] == 'S') { // Self Function Testing "YZS" i=0; //outbuf[i++] = (uint8_t) 'Y'; //outbuf[i++] = (uint8_t) 'Z'; //outbuf[i++] = (uint8_t) 'S'; //STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); i=0; STS_SENSOR_Function_Test_Process(); #if 0 HAL_Delay(5000); i=21; STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); #endif } else if ((char)tlv_buf[CFG_CMD3] == 'C') { // Lora-WAN Class "YZC" LORAWAN CLASS A/B/C DeviceClass_t deviceClass = CLASS_A; LmHandlerGetCurrentClass( &deviceClass ); i=0; outbuf[i++] = (uint8_t) 'L'; outbuf[i++] = (uint8_t) sts_mtmcode1; outbuf[i++] = (uint8_t) sts_mtmcode2; outbuf[i++] = (uint8_t) sts_version; outbuf[i++] = (uint8_t) (0x41+ deviceClass); //translate to 'A','B','C' STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } else if ((char)tlv_buf[CFG_CMD3] == 'D') { // Distance Measure "YZD" //i=0; //outbuf[i++] = (uint8_t) 'Y'; //outbuf[i++] = (uint8_t) 'Z'; //outbuf[i++] = (uint8_t) 'D'; //STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); STS_SENSOR_Distance_Test_Process(); APP_LOG(TS_OFF, VLEVEL_H, "\r\nRSS Measured Distance=[%u] mm \r\n", (uint16_t)sts_distance_rss_distance); // Store valid installation height value 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; sts_cfg_nvm.sensor_install_height_in_10cm = sts_sensor_install_height/100; //in 10 cm OnStoreSTSCFGContextRequest(); i=0; //memset((void*)outbuf,0x0, sizeof(outbuf)); 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)); #if defined(STS_O7)||defined(STS_O6) outbuf[i++] = (uint8_t)0x04; //length of following data outbuf[i++] = (uint8_t) ((((uint16_t)sts_distance_rss_distance)/1000)%10+0x30)&0xff; outbuf[i++] = (uint8_t) ((((uint16_t)sts_distance_rss_distance)/100)%10+0x30)&0xff; outbuf[i++] = (uint8_t) ((((uint16_t)sts_distance_rss_distance)/10)%10+0x30)&0xff; outbuf[i++] = (uint8_t) (((uint16_t)sts_distance_rss_distance)%10+0x30)&0xff; #endif #if (defined(YUNHORN_STS_R0_ENABLED)||defined(YUNHORN_STS_R5_ENABLED)||defined(YUNHORN_STS_R1_ENABLED)) #ifdef TOF_1 outbuf[i++] = (uint8_t) (((uint16_t)sts_tof_distance_data[0])/100)&0xff; outbuf[i++] = (uint8_t) (((uint16_t)sts_tof_distance_data[0])%100)&0xff; #endif #ifdef TOF_2 outbuf[i++] = (uint8_t) (((uint16_t)sts_tof_distance_data[1])/100)&0xff; outbuf[i++] = (uint8_t) (((uint16_t)sts_tof_distance_data[1])%100)&0xff; #endif #ifdef TOF_3 outbuf[i++] = (uint8_t) (((uint16_t)sts_tof_distance_data[2])/100)&0xff; outbuf[i++] = (uint8_t) (((uint16_t)sts_tof_distance_data[2])%100)&0xff; #endif #endif STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } break; case 'M': //"YM" if ((char)tlv_buf[CFG_CMD3] >= '0' && (char)tlv_buf[CFG_CMD3]<='9') // Service Mask "YZM" { i=0; sts_service_mask = (uint8_t)(tlv_buf[CFG_CMD3]-0x30)&0xFF; sts_cfg_nvm.sts_service_mask = (uint8_t)sts_service_mask; outbuf[i++] = (uint8_t) 'Y'; outbuf[i++] = (uint8_t) 'M'; outbuf[i++] = (uint8_t) (sts_service_mask+0x30); STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); APP_LOG(TS_OFF, VLEVEL_L, ">>>>>>>>>>>>>>>>>>>>> Mask = [ %02x ] \r\n", sts_service_mask); OnStoreSTSCFGContextRequest(); if (sts_service_mask != STS_SERVICE_MASK_L0) STS_Lamp_Bar_Set_Dark(); //STS_Combined_Status_Processing(); } break; case 'V': //"YV" if ((char)tlv_buf[CFG_CMD3] == 'H') { // "YVH" REPORT FIRMWARE VERSION "YVH" // FIRMWARE VERSION REPORT i=0; outbuf[i++] = (uint8_t) 'V'; outbuf[i++] = (uint8_t) sts_mtmcode1; outbuf[i++] = (uint8_t) sts_mtmcode2; outbuf[i++] = (uint8_t) sts_version; outbuf[i++] = (uint8_t) sts_hardware_ver; outbuf[i++] = (uint8_t) MajorVer; outbuf[i++] = (uint8_t) MinorVer; outbuf[i++] = (uint8_t) SubMinorVer; 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); #if 0 LmhPackage_t LmhpClockSyncPackageFactory; LmhpClockSyncPackageFactory.Init; if (LmhpClockSyncPackageFactory.IsInitialized) LmhpClockSyncPackageFactory.Process; if (LORAMAC_HANDLER_SUCCESS == LmhpClockSyncAppTimeReq()) { APP_LOG(TS_OFF, VLEVEL_M, "\r\n Clock Sync Success \r\n"); } SysTime_t mytime=SysTimeGet(); struct tm mylocal; SysTimeLocalTime((uint32_t)mytime.Seconds, &mylocal); APP_LOG(TS_OFF, VLEVEL_M, "\r\nTime YYYYMMDD=%4d:%2d:%2d HHMMSS=%2d:%2d:%2d \r\n", mylocal.tm_year, mylocal.tm_mon, mylocal.tm_mday, mylocal.tm_hour, mylocal.tm_min, mylocal.tm_sec); #endif 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; 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(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); APP_LOG(TS_OFF, VLEVEL_M, "###### YUNHORN Report Version [ %10x ] \r\n", (uint8_t *)outbuf); } else if ((char)tlv_buf[CFG_CMD3] == 'C') { // "YVC" REPORT NVM STORED CONFIG PARAMETERS "YVC" uint8_t cfg_in_nvm[YUNHORN_STS_MAX_NVM_CFG_SIZE]=""; OnRestoreSTSCFGContextRequest((uint8_t *)cfg_in_nvm); i=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]); } STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } break; // "YO#","YF#","YH#","YD##L" ##={0,9} L={S,M,H} case 'O': // TODO # of modules if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) { //STS_SENSOR_Power_ON((uint8_t)(tlv_buf[CFG_CMD3]-0x30)); PME_ON; // 2024-07-31 UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf)); UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf,tlv_buf_size); i = tlv_buf_size; STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } else { STS_SENSOR_Upload_Config_Invalid_Message(); } break; case 'F': // TODO # of modules if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) { //STS_SENSOR_Power_OFF((tlv_buf[CFG_CMD3]-0x30)); PME_OFF; // 2024-07-31 UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf)); UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf,tlv_buf_size); i = tlv_buf_size; STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } else { STS_SENSOR_Upload_Config_Invalid_Message(); } break; case 'H': // TODO # of modules if (((uint8_t)(tlv_buf[CFG_CMD3]-0x30) >= 0) && ((uint8_t)tlv_buf[CFG_CMD3]-0x30) <=9) { 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,tlv_buf_size); i = tlv_buf_size; STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } else { STS_SENSOR_Upload_Config_Invalid_Message(); } break; case 'D': //periodicity UPLINK, ACT AS HEART-BEAT MESSAGE 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; } periodicity_length = periodicity_length*1000; //translate to 1000ms=1s //OnTxPeriodicityChanged(TxPeriodicity); #if defined(STS_O6)||defined(STS_O7) HeartBeatPeriodicity = periodicity_length; OnYunhornSTSHeartBeatPeriodicityChanged(periodicity_length); #endif // 2024-07-31 UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf)); UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf,tlv_buf_size); i = tlv_buf_size; STS_SENSOR_Upload_Message(LORAWAN_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; case 'S': // SAMPLING INTERVAL OR DURATION 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; } #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) HeartBeatPeriodicity = heart_beat_or_sampling_periodicity_length*1000; //translate to 1000ms=1s OnYunhornSTSHeartBeatPeriodicityChanged(HeartBeatPeriodicity); #endif #if defined(STS_O6)||defined(STS_O7) SamplingPeriodicity = heart_beat_or_sampling_periodicity_length*1000; //translate to 1000ms=1s OnYunhornSTSSamplingPeriodicityChanged(SamplingPeriodicity); #endif // 2024-07-31 UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf)); UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf,tlv_buf_size); i = tlv_buf_size; STS_SENSOR_Upload_Message(LORAWAN_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; default: //STS_SENSOR_Upload_Config_Invalid_Message(); break; } // END OF switch switch ((char)tlv_buf[CFG_CMD2]) } // end of if END OF *** BOARD LEVEL CONTROL OR REPORT else if (((char)tlv_buf[CFG_CMD1] == 'P') && (tlv_buf_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)tlv_buf[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 mems_ver = (uint8_t)(tlv_buf[CFG_CMD3]-0x30); uint8_t j=0; if (mems_ver == sts_version) { // Firmware version or Variation of MEMS/component if (tlv_buf_size == 5 && tlv_buf[CFG_CMD4]=='0') //switch network mode color { invalid_flag = 0; sts_work_mode = (uint8_t)(tlv_buf[CFG_CMD4] - 0x30); if (sts_work_mode == STS_NETWORK_MODE) { //network mode sts_cloud_netcolor = (uint8_t)(tlv_buf[CFG_CMD5]-0x30); APP_LOG(TS_OFF, VLEVEL_L, "\r\n Cloud Color Set to %u \r\n", sts_cloud_netcolor); } sts_service_mask = STS_SERVICE_MASK_L0; sts_lamp_bar_color = sts_cloud_netcolor; 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*)tlv_buf, tlv_buf_size); i = tlv_buf_size; STS_Combined_Status_Processing(); } else if (tlv_buf_size == 7 && tlv_buf[CFG_CMD4]=='F') // Change fall detection { invalid_flag = 0; // P 1 1 F A B C if (((tlv_buf[CFG_CMD5] >='0') && (tlv_buf[CFG_CMD5]<='9')) && ((tlv_buf[CFG_CMD6]<='9') && (tlv_buf[CFG_CMD6]>='0')) && ((tlv_buf[CFG_CMD7]<='9') && (tlv_buf[CFG_CMD7]>='0'))) //&& ((tlv_buf[CFG_CMD8]<='9') && (tlv_buf[CFG_CMD8]>='0'))) { sts_fall_detection_acc_threshold = (uint8_t)(tlv_buf[CFG_CMD5] - 0x30)*10; //A: acc *10 mg/s2 sts_fall_detection_depth_threshold = (uint8_t)(tlv_buf[CFG_CMD6] - 0x30)*10; //D: depth *10 in cm sts_fall_confirm_threshold_in_10sec = (uint8_t)(tlv_buf[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)(tlv_buf[CFG_CMD5] - 0x30); sts_cfg_nvm.fall_detection_depth_threshold = (uint8_t)(tlv_buf[CFG_CMD6] - 0x30); sts_cfg_nvm.fall_confirm_threshold_in_10sec = (uint8_t)(tlv_buf[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; } } 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*)tlv_buf, tlv_buf_size); i = tlv_buf_size; APP_LOG(TS_OFF, VLEVEL_L, "###### Fall detection CFG = %s\r\n",(char*)outbuf); STS_Combined_Status_Processing(); } }else if (tlv_buf_size == 8 && tlv_buf[CFG_CMD4]=='O') // Change occupancy/motionless/ unconscious overtime threshold { invalid_flag = 0; // P 1 1 O A B C D if (((tlv_buf[CFG_CMD5] >='0') && (tlv_buf[CFG_CMD5]<='9')) && ((tlv_buf[CFG_CMD6]<='9') && (tlv_buf[CFG_CMD6]>='0')) && ((tlv_buf[CFG_CMD7]<='9') && (tlv_buf[CFG_CMD7]>='0'))&& ((tlv_buf[CFG_CMD8]<='9') && (tlv_buf[CFG_CMD8]>='0'))) { sts_motionless_duration_threshold_in_min = (uint8_t)(tlv_buf[CFG_CMD5] - 0x30); //Motionless duration in min sts_occupancy_overtime_threshold_in_10min = (uint8_t)(tlv_buf[CFG_CMD6] - 0x30)*10; //Long occupation in min sts_unconscious_level_threshold = (uint8_t)(tlv_buf[CFG_CMD7] - 0x30+1)*128; //motion level threshold less than 1280 sts_alarm_mute_reset_timer_in_10sec = (uint8_t)(tlv_buf[CFG_CMD8] - 0x30)*10; //alarm mute reset timer in 10 sec sts_cfg_nvm.motionless_duration_threshold_in_min = (uint8_t)(tlv_buf[CFG_CMD5] - 0x30); sts_cfg_nvm.occupancy_overtime_threshold_in_10min = (uint8_t)(tlv_buf[CFG_CMD6] - 0x30); sts_cfg_nvm.unconscious_or_motionless_level_threshold = (uint8_t)(tlv_buf[CFG_CMD7] - 0x30+1); sts_cfg_nvm.alarm_mute_reset_timer_in_10sec = (uint8_t)(tlv_buf[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*)tlv_buf, tlv_buf_size); i = tlv_buf_size; APP_LOG(TS_OFF, VLEVEL_L, "###### Occupancy/Overstay/unconscious config changed =%s\r\n",(char *)outbuf); STS_Combined_Status_Processing(); } } else if (tlv_buf_size == 4 ) // P WORK mode switch { invalid_flag = 0; if (((tlv_buf[CFG_CMD4] >='0') && (tlv_buf[CFG_CMD4]<='9')) || ((tlv_buf[CFG_CMD4]<='Z') && (tlv_buf[CFG_CMD4]>='A'))) { if ((tlv_buf[CFG_CMD4] >='0') && (tlv_buf[CFG_CMD4]<='9')) { sts_work_mode = (uint8_t)((tlv_buf[CFG_CMD4] - 0x30)); } else if ((tlv_buf[CFG_CMD4]<='Z') && (tlv_buf[CFG_CMD4]>='A')) { sts_work_mode = (uint8_t)((tlv_buf[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*)tlv_buf, tlv_buf_size); i = tlv_buf_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_cfg_nvm.work_mode = (uint8_t)sts_work_mode; if (sts_work_mode == STS_UNI_MODE) { sts_presence_fall_detection=TRUE; } else { sts_presence_fall_detection=FALSE; } 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 (tlv_buf_size >= CFG_CMD_RSS_FULL_SIZE) { invalid_flag = 0; for (j =0; j < CFG_CMD_RSS_FULL_SIZE; j++) { if ((tlv_buf[CFG_CMD4+j] >='0') && (tlv_buf[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; } } if (invalid_flag != 1) { 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*)tlv_buf, tlv_buf_size); i = tlv_buf_size; APP_LOG(TS_OFF, VLEVEL_L, "###### 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; for (j =0; j < CFG_CMD_RSS_SIMPLE_SIZE; j++) { if ((tlv_buf[CFG_CMD4+j] >='0') && (tlv_buf[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; } } if (invalid_flag != 1) { 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*)tlv_buf, tlv_buf_size); i = tlv_buf_size; APP_LOG(TS_OFF, VLEVEL_L, "###### 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 } else if (((char)tlv_buf[CFG_CMD1] == 'A') && ((char)tlv_buf[CFG_CMD2] == 'C') && (tlv_buf_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_YUNHORN_RFAC_HANDLE_PROCESS(); if ((hmac_result.ac_pass == 1U)) { //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; } i=0; UTIL_MEM_set_8((void*)outbuf, 0x0, sizeof(outbuf)); UTIL_MEM_cpy_8((void*)outbuf,(void*)tlv_buf, tlv_buf_size); STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t *)outbuf); } } // END OF USER_APP_AUTO_RESPONDER_Parse void STS_SENSOR_Upload_Config_Invalid_Message(void) { if (sts_service_mask == STS_SERVICE_MASK_L0) STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, 5, (uint8_t*)"PVXXX"); } static void STS_YUNHORN_RFAC_HANDLE_PROCESS(void) { STS_YunhornAuthenticationCode_Process(); } 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; i1 ?0:appBufferSize); APP_LOG(TS_OFF, VLEVEL_L, "###########Service Mask = %d Buffer Size =%d \r\n", sts_service_mask, AppData.BufferSize); if ((JoinLedTimer.IsRunning) && (LmHandlerJoinStatus() == LORAMAC_HANDLER_SET)) { UTIL_TIMER_Stop(&JoinLedTimer); #ifndef STM32WLE5xx HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); /* LED_RED */ #endif } 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)); } } } if (EventType == TX_ON_TIMER) { UTIL_TIMER_Stop(&TxTimer); UTIL_TIMER_SetPeriod(&TxTimer, MAX(nextTxIn, TxPeriodicity)); UTIL_TIMER_Start(&TxTimer); } } void OnStoreSTSCFGContextRequest(void) { /* USER CODE BEGIN OnStoreContextRequest_1 */ uint8_t i=0,j=0,nvm_store_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0}; //#if (defined(STS_O7)||defined(STS_O5) || defined(STS_O6) || defined(STS_R0) || defined(STS_R5)|| defined(STS_R4)|| defined(STS_R1D)) sts_cfg_nvm.length = STS_O7_NVM_CFG_SIZE; nvm_store_value[i++] = sts_cfg_nvm.mtmcode1; nvm_store_value[i++] = sts_cfg_nvm.mtmcode2; nvm_store_value[i++] = sts_cfg_nvm.version; nvm_store_value[i++] = sts_cfg_nvm.hardware_ver; nvm_store_value[i++] = sts_cfg_nvm.periodicity; nvm_store_value[i++] = sts_cfg_nvm.unit; nvm_store_value[i++] = sts_cfg_nvm.sampling; nvm_store_value[i++] = sts_cfg_nvm.s_unit; nvm_store_value[i++] = sts_cfg_nvm.work_mode; nvm_store_value[i++] = sts_cfg_nvm.sts_service_mask; nvm_store_value[i++] = sts_cfg_nvm.sts_ioc_mask; nvm_store_value[i++] = sts_cfg_nvm.length; //(uint8_t) STS_O7_NVM_CFG_SIZE; //sts_cfg_nvm.length; for (j = 0; j < STS_O7_CFG_PCFG_SIZE; j++) { nvm_store_value[i++] = (sts_cfg_nvm.p[j]); } nvm_store_value[i++] = sts_cfg_nvm.reserve02; nvm_store_value[i++] = sts_cfg_nvm.reserve03; nvm_store_value[i++] = sts_cfg_nvm.sensor_install_height_in_10cm; nvm_store_value[i++] = sts_cfg_nvm.alarm_parameter05; nvm_store_value[i++] = sts_cfg_nvm.alarm_mute_reset_timer_in_10sec; nvm_store_value[i++] = sts_cfg_nvm.alarm_lamp_bar_flashing_color; nvm_store_value[i++] = sts_cfg_nvm.occupancy_overtime_threshold_in_10min; nvm_store_value[i++] = sts_cfg_nvm.motionless_duration_threshold_in_min; nvm_store_value[i++] = sts_cfg_nvm.unconscious_or_motionless_level_threshold; nvm_store_value[i++] = sts_cfg_nvm.fall_detection_acc_threshold; nvm_store_value[i++] = sts_cfg_nvm.fall_detection_depth_threshold; nvm_store_value[i++] = sts_cfg_nvm.fall_confirm_threshold_in_10sec; if ((sts_cfg_nvm.ac[0]!=0x0) && (sts_cfg_nvm.ac[19]!=0x0)) { for (j = 0; j < YUNHORN_STS_AC_CODE_SIZE; j++) { nvm_store_value[i++] = (sts_cfg_nvm.ac[j]); } } //#endif /* USER CODE END OnStoreContextRequest_1 */ /* store nvm in flash */ if (FLASH_IF_Erase(STS_CONFIG_NVM_BASE_ADDRESS, FLASH_PAGE_SIZE) == FLASH_IF_OK) { FLASH_IF_Write(STS_CONFIG_NVM_BASE_ADDRESS, (const void *)nvm_store_value, YUNHORN_STS_MAX_NVM_CFG_SIZE); } /* USER CODE BEGIN OnStoreContextRequest_Last */ /* USER CODE END OnStoreContextRequest_Last */ } void OnRestoreSTSCFGContextRequest(void *cfg_in_nvm) { /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_1 */ // uint8_t nvm_store_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]="", nvm_store_size=YUNHORN_STS_MAX_NVM_CFG_SIZE; APP_LOG(TS_OFF, VLEVEL_M, "Restore NVM start\r\n"); /* USER CODE END OnRestoreSTSCFGContextRequest_1 */ FLASH_IF_Read(cfg_in_nvm, STS_CONFIG_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE); //UTIL_MEM_cpy_8(cfg_in_nvm, (void *)STS_CONFIG_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE); /* USER CODE BEGIN OnRestoreSTSCFGContextRequest_Last */ //memcpy(cfg_in_nvm, nvm_store_value, YUNHORN_STS_MAX_NVM_CFG_SIZE); /* USER CODE END OnRestoreSTSCFGContextRequest_Last */ } void STS_REBOOT_CONFIG_Init(void) { /* USER CODE BEGIN OnRestoreContextRequest_1 */ uint8_t nvm_stored_value[YUNHORN_STS_MAX_NVM_CFG_SIZE]={0x0}; /* USER CODE END OnRestoreContextRequest_1 */ //UTIL_MEM_cpy_8(nvm_stored_value, (void *)STS_CONFIG_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE); FLASH_IF_Read(nvm_stored_value, STS_CONFIG_NVM_BASE_ADDRESS, YUNHORN_STS_MAX_NVM_CFG_SIZE); /* USER CODE BEGIN OnRestoreContextRequest_Last */ //#if (defined(STS_O7)||defined(STS_O5) || defined(STS_O6) || defined(STS_R0) || defined(STS_R5)|| defined(STS_R4)|| defined(STS_R1D)) 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"); OnStoreSTSCFGContextRequest(); //UTIL_MEM_set_8((void *)sts_ac_code, 0x00, YUNHORN_STS_AC_CODE_SIZE); HAL_Delay(1000); } else { 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]); sts_cfg_nvm.unit = (uint8_t)(nvm_stored_value[NVM_UNIT]); sts_cfg_nvm.sampling = (uint8_t)(nvm_stored_value[NVM_SAMPLING]); 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_O7_CFG_PCFG_SIZE; j++) { // P RSS CONFIG SIZE= 20U sts_cfg_nvm.p[j] = (uint8_t)nvm_stored_value[NVM_CFG_START+j]; } sts_cfg_nvm.reserve02 =(uint8_t)nvm_stored_value[NVM_RESERVE02]; sts_cfg_nvm.reserve03 =(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]; //sts_cfg_nvm.occupancy_overtime_threshold = (uint8_t)nvm_stored_value[NVM_OCCUPANCY_OVERTIME_THRESHOLD]; for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++) { sts_cfg_nvm.ac[j] = (uint8_t)nvm_stored_value[NVM_AC_CODE_START +j]; } } //#endif OnRestoreSTSCFGContextProcess(); /* USER CODE END OnRestoreContextRequest_Last */ } void OnRestoreSTSCFGContextProcess(void) { uint32_t periodicity = (sts_cfg_nvm.periodicity); 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 *= 1000; // to ms uint32_t sampling = (sts_cfg_nvm.sampling); if ((char)sts_cfg_nvm.s_unit =='M') { sampling *= 60; } else if ((char) sts_cfg_nvm.s_unit =='H') { sampling *= 3600; } else if ((char) sts_cfg_nvm.s_unit =='S') { sampling *= 1; } sampling= sampling*1000; // to ms if ((sts_cfg_nvm.ac[0] ==0x0 )&& (sts_cfg_nvm.ac[19]==0x0)) { // ensure it's not in production yet OnTxPeriodicityChanged(APP_TX_DUTYCYCLE); // in msec unit OnYunhornSTSHeartBeatPeriodicityChanged(HeartBeatPeriodicity); OnYunhornSTSSamplingPeriodicityChanged(sampling); // in m-sec unit } else { //OnTxPeriodicityChanged(TxPeriodicity); // in msec unit //Heart-beat or Sampling interval #ifdef STS_E0 samplingperiodicity = (samplingperiodicity > 0)? samplingperiodicity : 1; // in seconds unit HeartBeatPeriodicity = samplingperiodicity*1000; #endif #if defined(STS_O7)|| defined(STS_O6) ||defined(STS_O5) HeartBeatPeriodicity = periodicity; OnYunhornSTSHeartBeatPeriodicityChanged(HeartBeatPeriodicity); OnYunhornSTSSamplingPeriodicityChanged(sampling); // in m-sec unit #endif #if defined(YUNHORN_STS_R0_ENABLED)||defined(YUNHORN_STS_R5_ENABLED)||defined(YUNHORN_STS_R4_ENABLED) OnYunhornSTSHeartBeatPeriodicityChanged(HeartBeatPeriodicity); #endif } sts_work_mode = sts_cfg_nvm.work_mode; sts_lamp_bar_color = STS_GREEN; sts_service_mask = sts_cfg_nvm.sts_service_mask; sts_lamp_bar_flashing_color = sts_cfg_nvm.alarm_lamp_bar_flashing_color; if (sts_work_mode == STS_UNI_MODE){ sts_presence_fall_detection =TRUE; } else { sts_presence_fall_detection =FALSE; } sts_sensor_install_height = sts_cfg_nvm.sensor_install_height_in_10cm*100; //10cm translate to mm 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_fall_confirm_threshold_in_10sec = (uint8_t)sts_cfg_nvm.fall_confirm_threshold_in_10sec*10; sts_unconscious_or_motionless_level_threshold = (uint8_t)(sts_cfg_nvm.unconscious_or_motionless_level_threshold+1)*128; // unconscious threshold sts_motionless_duration_threshold_in_min = (uint8_t)sts_cfg_nvm.motionless_duration_threshold_in_min; sts_occupancy_overtime_threshold_in_10min = (uint8_t)sts_cfg_nvm.occupancy_overtime_threshold_in_10min; // minutes for (uint8_t j=0; j< YUNHORN_STS_AC_CODE_SIZE; j++) { sts_ac_code[j] = sts_cfg_nvm.ac[j]; } #if defined(STS_O7)||defined(STS_O6) 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 } void STS_SENSOR_Distance_Test_Process(void) { #if defined(STS_O6)||defined(STS_O7) //sts_distance_rss_distance =0; uint8_t i=0; //do { STS_PRESENCE_SENSOR_Distance_Measure_Process(); // HAL_Delay(200); // i++; // } while((sts_distance_rss_distance == 0)&&(i<2)); APP_LOG(TS_OFF, VLEVEL_L, "\r\nSensor Function Test: Distance Measured =%u mm\r\n", (uint16_t)sts_distance_rss_distance); #endif #if defined(YUNHORN_STS_R0_ENABLED)||defined(YUNHORN_STS_R5_ENABLED) MX_TOF_Process(); #endif } void STS_SENSOR_Function_Test_Process(void) { char tstbuf[128] =""; uint8_t i=0, count = 1; uint8_t mems_Dev_ID[2] = {0x0}; 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)); APP_LOG(TS_OFF, VLEVEL_H, "\r\nStart Function Test \r\n"); STS_SENSOR_MEMS_Get_ID(mems_Dev_ID); if ((mems_Dev_ID[0]==0X0) && (mems_Dev_ID[1]==0x0)) { tstbuf[i++] = (uint8_t) 'X'; // Slave MEMS Not Avaliable } else { tstbuf[i++] = (uint8_t)14; //length of following data #if defined(STS_O7)||defined(STS_O6) uint8_t self_test_result[10]={0x0}; STS_PRESENCE_SENSOR_Function_Test_Process(self_test_result, 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(YUNHORN_STS_R0_ENABLED)||defined(YUNHORN_STS_R5_ENABLED)||defined(YUNHORN_STS_R1_ENABLED)) tstbuf[i++] = (uint8_t) (count)&0xff; //MX_TOF_Process(); STS_TOF_VL53L0X_Range_Process(); #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 #endif } //memset((void*)outbuf,0x0, sizeof(outbuf)); UTIL_MEM_cpy_8((void*)outbuf, (void*)tstbuf, i); STS_SENSOR_Upload_Message(LORAWAN_USER_APP_CTRL_REPLY_PORT, i, (uint8_t*)outbuf); } uint32_t STS_Get_Date_Time_Stamp(void) { struct tm localtime; SysTime_t UnixEpoch = SysTimeGet(); UnixEpoch.Seconds -= 18; /*removing leap seconds*/ SysTimeLocalTime(UnixEpoch.Seconds, &localtime); APP_LOG(TS_OFF, VLEVEL_M, "UTC TIME:%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); return (uint32_t)UnixEpoch.Seconds; }