aboutsummaryrefslogtreecommitdiff
path: root/src/app/google_rcu/rcu_application.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/google_rcu/rcu_application.c')
-rw-r--r--src/app/google_rcu/rcu_application.c1722
1 files changed, 1722 insertions, 0 deletions
diff --git a/src/app/google_rcu/rcu_application.c b/src/app/google_rcu/rcu_application.c
new file mode 100644
index 0000000..507d5a3
--- /dev/null
+++ b/src/app/google_rcu/rcu_application.c
@@ -0,0 +1,1722 @@
+/**
+*********************************************************************************************************
+* Copyright(c) 2020, Realtek Semiconductor Corporation. All rights reserved.
+*********************************************************************************************************
+* @file rcu_application.c
+* @brief rcu application implementation
+* @details including callbacks of handle functions for users to implement customization requirements
+* @author barry_bian
+* @date 2020-02-24
+* @version v1.0
+* *********************************************************************************************************
+*/
+
+/*============================================================================*
+ * Header Files
+ *============================================================================*/
+#include <trace.h>
+#include <string.h>
+#include <gap.h>
+#include <gap_adv.h>
+#include <gap_bond_le.h>
+#include "rcu_gap.h"
+#include <profile_server.h>
+#include <gap_msg.h>
+#include "board.h"
+#include <app_task.h>
+#include <app_msg.h>
+#include <rcu_application.h>
+#include "hids_rmc.h"
+#include "bas.h"
+#include "dis.h"
+#include "key_handle.h"
+#include "os_timer.h"
+#include "swtimer.h"
+#include "voice.h"
+#include "version.h"
+#include "voice_driver.h"
+#include "gap_conn_le.h"
+#include "vendor_service.h"
+#include "ota_service.h"
+#include "rtl876x_wdg.h"
+#include "dfu_api.h"
+#include "ftl.h"
+#include "mp_test.h"
+#include "hids_rmc.h"
+#include "dfu_service.h"
+#include "dfu_flash.h"
+#include "patch_header_check.h"
+#include "gatt_builtin_services.h"
+#include "led_driver.h"
+#include "battery_driver.h"
+#include "app_section.h"
+#include "ir_service.h"
+#include <rcu_link_mgr.h>
+#if SUPPORT_IR_TX_FEATURE
+#include "ir_send_handle.h"
+#endif
+#if FEATURE_SUPPORT_MP_TEST_MODE
+#include "data_uart_test.h"
+#endif
+#include "atvv_service.h"
+#include "frm_define.h"
+#if FEAUTRE_SUPPORT_IR_OVER_BLE
+#include "ir_service_handle.h"
+#endif
+#if SUPPORT_BUZZER_FEATURE
+#include "fms.h"
+#include "fms_service_handle.h"
+#include "buzzer_driver.h"
+#endif
+
+/*============================================================================*
+ * Functions Declaration
+ *============================================================================*/
+void app_handle_io_msg(T_IO_MSG io_driver_msg_recv) DATA_RAM_FUNCTION;
+extern T_GAP_CAUSE client_send_exchange_mtu_req(uint8_t conn_id);
+
+/*============================================================================*
+ * Global Variables
+ *============================================================================*/
+const uint8_t Default_PnP_ID[] = {0x02, LO_WORD(VID), HI_WORD(VID), LO_WORD(PID), HI_WORD(PID), 0x01, 0x00};
+const uint8_t Default_FW_Rev [] = {'V', '1', '.', '1', '0', '1'};
+const uint8_t Default_SW_Rev [] = {'V', '1', '.', '0', '2'};
+const uint8_t Default_HW_Rev [] = {'V', '1', '.', '0'};
+const uint8_t Default_Manu_Name [] = {'R', 'e', 'a', 'l', 't', 'e', 'k'};
+
+T_APP_GLOBAL_DATA app_global_data;
+#if FEATURE_SUPPORT_PRIVACY
+T_PRIVACY_STATE app_privacy_state = PRIVACY_STATE_INIT;
+T_PRIVACY_ADDR_RESOLUTION_STATE app_privacy_resolution_state = PRIVACY_ADDR_RESOLUTION_DISABLED;
+#endif
+/*============================================================================*
+ * External Variables
+ *============================================================================*/
+
+/*============================================================================*
+ * Local Functions
+ *============================================================================*/
+/******************************************************************
+ * @brief handler stop adverting reason
+ * @param T_STOP_ADV_REASON reason.
+ * @return none
+ * @retval void
+ */
+static void app_stop_adv_reason_handler(T_STOP_ADV_REASON reason)
+{
+ switch (reason)
+ {
+ case STOP_ADV_REASON_RESTART_RECONNECT_ADV:
+ if ((app_global_data.adv_type == ADV_DIRECT_LDC) || (app_global_data.adv_type == ADV_DIRECT_LDC_LT))
+ {
+ APP_PRINT_INFO0("STOP_ADV_REASON_RESTART_RECONNECT_ADV!");
+ rcu_start_adv(ADV_DIRECT_LDC);
+ }
+ break;
+ case STOP_ADV_REASON_WAKEUPKEY:
+ APP_PRINT_INFO0("STOP_ADV_REASON_WAKEUPKEY!");
+ rcu_start_adv(ADV_UNDIRECT_WAKEUP);
+ break;
+ case STOP_ADV_REASON_BACKKEY:
+ APP_PRINT_INFO0("STOP_ADV_REASON_BACKKEY!");
+ break;
+ case STOP_ADV_REASON_PAIRING:
+ APP_PRINT_INFO0("STOP_ADV_REASON_PAIRING!");
+ rcu_start_adv(ADV_UNDIRECT_PAIRING);
+ break;
+ case STOP_ADV_REASON_TIMEOUT:
+ APP_PRINT_INFO0("STOP_ADV_REASON_TIMEOUT!");
+ if (app_global_data.adv_type == ADV_UNDIRECT_PAIRING)
+ {
+ rcu_start_adv(ADV_UNDIRECT_PAIRING_LT);
+ }
+ else if (app_global_data.adv_type == ADV_UNDIRECT_PAIRING_LT)
+ {
+#if SUPPORT_LED_INDICATION_FEATURE
+ LED_BLINK_EXIT(LED_TYPE_BLINK_PAIR_ADV);
+ LED_BLINK(LED_TYPE_BLINK_ERROR, 4);
+#endif
+ }
+ else if (app_global_data.adv_type == ADV_UNDIRECT_WAKEUP)
+ {
+ rcu_start_adv(ADV_DIRECT_LDC);
+ }
+ else if (app_global_data.adv_type == ADV_DIRECT_LDC)
+ {
+ rcu_start_adv(ADV_DIRECT_LDC_LT);
+ }
+ else if (app_global_data.adv_type == ADV_DIRECT_LDC_LT)
+ {
+ key_handle_reset_key_pressed_cache_fifo();
+ }
+ break;
+ case STOP_ADV_REASON_LOWPOWER:
+ APP_PRINT_INFO0("STOP_ADV_REASON_LOWPOWER!");
+ app_global_data.rcu_status = RCU_STATUS_LOW_POWER;
+ break;
+ case STOP_ADV_REASON_UART_CMD:
+ APP_PRINT_INFO0("STOP_ADV_REASON_UART_CMD!");
+ break;
+ case STOP_ADV_REASON_IDLE:
+ APP_PRINT_INFO0("STOP_ADV_REASON_IDLE!");
+ if (app_global_data.adv_type == ADV_DIRECT_HDC)
+ {
+ APP_PRINT_INFO1("[STOP_ADV_REASON_IDLE] retry cnt is %d", app_global_data.direct_adv_cnt);
+ if (app_global_data.direct_adv_cnt < MAX_DIRECT_ADV_RETRY_CNT)
+ {
+ rcu_start_adv(ADV_DIRECT_HDC);
+ app_global_data.direct_adv_cnt++;
+ return;
+ }
+ else
+ {
+ app_global_data.direct_adv_cnt = 0; /* reset direct_adv_cnt to 0 */
+ }
+
+ key_handle_reset_key_pressed_cache_fifo();
+ }
+ break;
+ default:
+ APP_PRINT_WARN1("Unknown stop_adv_reason: %d", app_global_data.stop_adv_reason);
+ break;
+ }
+}
+
+/******************************************************************
+ * @brief handler disconnect reason
+ * @param T_DISCONN_REASON reason.
+ * @return none
+ * @retval void
+ */
+static void app_disconn_reason_handler(T_DISCONN_REASON reason)
+{
+ switch (reason)
+ {
+ case DISCONN_REASON_PAIRING:
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_PAIRING");
+ rcu_start_adv(ADV_UNDIRECT_PAIRING);
+ break;
+ case DISCONN_REASON_TIMEOUT:
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_TIMEOUT");
+ break;
+ case DISCONN_REASON_PAIR_FAILED:
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_PAIR_FAILED");
+ if (false == app_global_data.is_link_key_existed)
+ {
+ APP_PRINT_INFO1("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_PAIR_FAILED, retry cnt is %d",
+ app_global_data.pair_failed_retry_cnt);
+ if (app_global_data.pair_failed_retry_cnt < MAX_PAIR_FAILED_RETRY_CNT)
+ {
+ app_global_data.pair_failed_retry_cnt++;
+ rcu_start_adv(ADV_UNDIRECT_PAIRING);
+ }
+ }
+ break;
+ case DISCONN_REASON_LOW_POWER:
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_LOW_POWER");
+ app_global_data.rcu_status = RCU_STATUS_LOW_POWER;
+ break;
+ case DISCONN_REASON_UART_CMD:
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_UART_CMD");
+ break;
+#if SUPPORT_NORMAL_OTA
+ case DISCONN_REASON_OTA:
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] DISCONN_REASON_OTA");
+ /* switch to OTA and reboot */
+ dfu_switch_to_ota_mode();
+ break;
+#endif
+#if SUPPORT_SILENT_OTA
+ case DISCONN_REASON_SILENT_OTA:
+ dfu_fw_reboot(true);
+ break;
+#endif
+ default:
+ APP_PRINT_WARN1("[GAP_CONN_STATE_DISCONNECTED] unknown reason: %d", app_global_data.disconn_reason);
+ break;
+ }
+}
+
+/******************************************************************
+ * @fn app_general_srv_cb
+ * @brief General service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+static T_APP_RESULT app_general_srv_cb(T_SERVER_APP_CB_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ switch (p_data->eventId)
+ {
+ case PROFILE_EVT_SRV_REG_COMPLETE:
+ APP_PRINT_INFO1("PROFILE_EVT_SRV_REG_COMPLETE: result %d",
+ p_data->event_data.service_reg_result);
+ break;
+
+ case PROFILE_EVT_SEND_DATA_COMPLETE:
+ APP_PRINT_INFO5("PROFILE_EVT_SEND_DATA_COMPLETE: conn_id %d, cause 0x%x, service_id %d, attrib_idx 0x%x, credits = %d",
+ p_data->event_data.send_data_result.conn_id,
+ p_data->event_data.send_data_result.cause,
+ p_data->event_data.send_data_result.service_id,
+ p_data->event_data.send_data_result.attrib_idx,
+ p_data->event_data.send_data_result.credits);
+ if (p_data->event_data.send_data_result.cause == GAP_SUCCESS)
+ {
+ APP_PRINT_INFO0("PROFILE_EVT_SEND_DATA_COMPLETE success");
+#if SUPPORT_VOICE_FEATURE
+ if (voice_driver_global_data.is_voice_driver_working)
+ {
+ voice_handle_messages(VOICE_MSG_BT_SEND_COMPLETE, NULL);
+ }
+#endif
+ }
+ else
+ {
+ APP_PRINT_ERROR0("PROFILE_EVT_SEND_DATA_COMPLETE failed");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return cb_result;
+}
+
+/******************************************************************
+ * @fn app_bas_srv_cb
+ * @brief BAS service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+static T_APP_RESULT app_bas_srv_cb(T_BAS_CALLBACK_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ switch (p_data->msg_type)
+ {
+ case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION:
+ {
+ if (p_data->msg_data.notification_indification_index == BAS_NOTIFY_BATTERY_LEVEL_ENABLE)
+ {
+ APP_PRINT_INFO0("[app_bas_srv_cb] Battery level notification enable");
+ }
+ else if (p_data->msg_data.notification_indification_index ==
+ BAS_NOTIFY_BATTERY_LEVEL_DISABLE)
+ {
+ APP_PRINT_INFO0("[app_bas_srv_cb] Battery level notification disable");
+ }
+ }
+ break;
+ case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE:
+ {
+ uint8_t bat_level = 100;
+#if SUPPORT_BAT_DETECT_FEATURE
+ if (BAT_STATUS_SUCCESS == bat_update_battery_info())
+ {
+ bat_level = bat_get_current_voltage_level();
+ }
+ else
+ {
+ cb_result = APP_RESULT_APP_ERR;
+ }
+#endif
+ bas_set_parameter(BAS_PARAM_BATTERY_LEVEL, 1, &bat_level);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return cb_result;
+}
+
+/******************************************************************
+ * @fn app_dis_srv_cb
+ * @brief DIS service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+static T_APP_RESULT app_dis_srv_cb(T_DIS_CALLBACK_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ switch (p_data->msg_type)
+ {
+ case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE:
+ {
+ if (p_data->msg_data.read_value_index == DIS_READ_MANU_NAME_INDEX)
+ {
+ dis_set_parameter(DIS_PARAM_MANUFACTURER_NAME,
+ sizeof(Default_Manu_Name),
+ (void *)Default_Manu_Name);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_MODEL_NUM_INDEX)
+ {
+ const uint8_t DISModelNumber[] = "Google RCU";
+ dis_set_parameter(DIS_PARAM_MODEL_NUMBER,
+ sizeof(DISModelNumber) - 1,
+ (void *)DISModelNumber);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_SERIAL_NUM_INDEX)
+ {
+ const uint8_t DISSerialNumber[] = "123456";
+ dis_set_parameter(DIS_PARAM_SERIAL_NUMBER,
+ sizeof(DISSerialNumber) - 1,
+ (void *)DISSerialNumber);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_HARDWARE_REV_INDEX)
+ {
+ dis_set_parameter(DIS_PARAM_HARDWARE_REVISION,
+ sizeof(Default_HW_Rev),
+ (void *)Default_HW_Rev);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_FIRMWARE_REV_INDEX)
+ {
+ dis_set_parameter(DIS_PARAM_FIRMWARE_REVISION,
+ sizeof(app_global_data.fw_version),
+ (void *)app_global_data.fw_version);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_SOFTWARE_REV_INDEX)
+ {
+ dis_set_parameter(DIS_PARAM_SOFTWARE_REVISION,
+ sizeof(app_global_data.sw_version),
+ (void *)app_global_data.sw_version);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_SYSTEM_ID_INDEX)
+ {
+ const uint8_t DISSystemID[DIS_SYSTEM_ID_LENGTH] = {0, 1, 2, 0, 0, 3, 4, 5};
+ dis_set_parameter(DIS_PARAM_SYSTEM_ID,
+ sizeof(DISSystemID),
+ (void *)DISSystemID);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_IEEE_CERT_STR_INDEX)
+ {
+ const uint8_t DISIEEEDataList[] = "RTKBeeIEEEDatalist";
+ dis_set_parameter(DIS_PARAM_IEEE_DATA_LIST,
+ sizeof(DISIEEEDataList) - 1,
+ (void *)DISIEEEDataList);
+ }
+ else if (p_data->msg_data.read_value_index == DIS_READ_PNP_ID_INDEX)
+ {
+ dis_set_parameter(DIS_PARAM_PNP_ID,
+ sizeof(app_global_data.pnp_id),
+ app_global_data.pnp_id);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (temp_off_latency_timer != NULL)
+ {
+ /* turn off latency to speed up process */
+ app_set_latency_status(LATENCY_TEMP_OFF_BIT, LANTENCY_OFF);
+ /* start temp_off_latency_timer */
+ os_timer_restart(&temp_off_latency_timer, TEMP_OFF_LANTENCY_TIMEOUT);
+ }
+
+ return cb_result;
+}
+
+/******************************************************************
+ * @fn app_hid_srv_cb
+ * @brief HID service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+static T_APP_RESULT app_hid_srv_cb(T_HID_CALLBACK_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ APP_PRINT_INFO1("[app_hid_srv_cb] msg_type %d", p_data->msg_type);
+ switch (p_data->msg_type)
+ {
+ case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION:
+ {
+ switch (p_data->msg_data.notification_indification_index)
+ {
+ case HID_NOTIFY_INDICATE_KB_ENABLE:
+ APP_PRINT_INFO0("[app_hid_srv_cb] HID_NOTIFY_INDICATE_KB_ENABLE");
+ app_global_data.is_keyboard_notify_en = true;
+ break;
+ case HID_NOTIFY_INDICATE_KB_DISABLE:
+ APP_PRINT_INFO0("[app_hid_srv_cb] HID_NOTIFY_INDICATE_KB_DISABLE");
+ app_global_data.is_keyboard_notify_en = false;
+ break;
+ case HID_NOTIFY_INDICATE_MM_KB_ENABLE:
+ APP_PRINT_INFO0("[app_hid_srv_cb] HID_NOTIFY_INDICATE_MM_KB_ENABLE");
+ app_global_data.is_mm_keyboard_notify_en = true;
+ break;
+ case HID_NOTIFY_INDICATE_MM_KB_DISABLE:
+ APP_PRINT_INFO0("[app_hid_srv_cb] HID_NOTIFY_INDICATE_MM_KB_DISABLE");
+ app_global_data.is_mm_keyboard_notify_en = false;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE:
+ {
+ APP_PRINT_INFO0("SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE\n");
+ }
+ break;
+ default:
+ break;
+ }
+
+ return cb_result;
+}
+
+/******************************************************************
+ * @fn app_vendor_srv_cb
+ * @brief Vendor service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+static T_APP_RESULT app_vendor_srv_cb(T_VENDOR_CALLBACK_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ APP_PRINT_INFO1("[app_vendor_srv_cb] msg_type %d", p_data->msg_type);
+ switch (p_data->msg_type)
+ {
+ case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION:
+ {
+ if (p_data->msg_data.notification_indification_index == VENDOR_NOTIFY_ENABLE)
+ {
+ APP_PRINT_INFO0("[app_vendor_srv_cb] VENDOR_NOTIFY_ENABLE");
+ server_send_data(0, app_global_data.vendor_srv_id,
+ BLE_SERVICE_CHAR_VENDOR_HANDSHAKE_INDEX,
+ (uint8_t *)vendor_svc_handshake_values,
+ 16,
+ GATT_PDU_TYPE_NOTIFICATION);
+ }
+ else if (p_data->msg_data.notification_indification_index == VENDOR_NOTIFY_DISABLE)
+ {
+ APP_PRINT_INFO0("[app_vendor_srv_cb] VENDOR_NOTIFY_DISABLE");
+ }
+ }
+ break;
+ case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE:
+ {
+ if (p_data->msg_data.write_msg.write_type == VENDOR_WRITE_HANDSHAKE)
+ {
+ APP_PRINT_INFO0("[app_vendor_srv_cb] SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE");
+ memcpy(vendor_svc_handshake_values, p_data->msg_data.write_msg.write_parameter.report_data.report,
+ 16);
+ if (!BTIF_VendorGetResponse(vendor_svc_handshake_values, 16))
+ {
+ APP_PRINT_WARN0("[app_vendor_srv_cb] blueAPI_HandShakeGetResponse failed!");
+ cb_result = APP_RESULT_APP_ERR;
+ }
+ }
+#if FEATURE_SUPPORT_MP_TEST_MODE
+ else if (p_data->msg_data.write_msg.write_type == VENDOR_WRITE_TEST_MODE)
+ {
+ mp_test_clear_bond_info();
+
+ if (mp_test_disable_test_mode_flag())
+ {
+ APP_PRINT_INFO0("[app_vendor_srv_cb] disable test mode flag success!");
+
+ /* notify 8-0x00 HID key notification */
+ uint8_t notify_buffer[8];
+ memset(notify_buffer, 0, sizeof(notify_buffer));
+ server_send_data(0, app_global_data.hid_srv_id, GATT_SRV_HID_KB_INPUT_INDEX,
+ notify_buffer, sizeof(notify_buffer), GATT_PDU_TYPE_NOTIFICATION);
+ }
+ else
+ {
+ APP_PRINT_WARN0("[app_vendor_srv_cb] disable test mode flag failed!");
+ cb_result = APP_RESULT_APP_ERR;
+ }
+ }
+#endif
+ else
+ {
+ cb_result = APP_RESULT_APP_ERR;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return cb_result;
+}
+
+/******************************************************************
+ * @fn app_ota_srv_cb
+ * @brief OTA service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+static T_APP_RESULT app_ota_srv_cb(T_OTA_CALLBACK_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ switch (p_data->msg_type)
+ {
+ case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE:
+ if (OTA_WRITE_CHAR_VAL == p_data->msg_data.write.opcode &&
+ OTA_VALUE_ENTER == p_data->msg_data.write.u.value)
+ {
+#if SUPPORT_NORMAL_OTA
+#if SUPPORT_BAT_DETECT_FEATURE
+ bat_update_battery_info();
+ uint16_t bat_value = bat_get_current_voltage_value();
+
+ if (bat_value < BAT_ENTER_OTA_MODE_THRESHOLD)
+ {
+ APP_PRINT_INFO1("[app_ota_srv_cb] Cannot switch into OTA mode, battery voltage is too low %d",
+ bat_value);
+ cb_result = APP_RESULT_APP_ERR;
+ }
+ else
+#endif
+ {
+ APP_PRINT_INFO0("[app_ota_srv_cb] Preparing switch into OTA mode");
+ /* disconnect and prepare to enter OTA mode */
+ rcu_terminate_connection(DISCONN_REASON_OTA);
+ }
+#endif
+ }
+#if FEATURE_SUPPORT_MP_TEST_MODE
+ else if (OTA_WRITE_TEST_MODE_CHAR_VAL == p_data->msg_data.write.opcode)
+ {
+ APP_PRINT_INFO1("[MP] Test mode clear operation action: (%d)\n",
+ p_data->msg_data.write.u.value);
+ if (true == mp_test_clear_bond_info())
+ {
+ APP_PRINT_INFO0("[MP] Exit MP test mode.");
+ uint8_t exitTestModeData[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ exitTestModeData[2] = 0xFF;
+ server_send_data(0, app_global_data.hid_srv_id, GATT_SRV_HID_KB_INPUT_INDEX,
+ exitTestModeData, sizeof(exitTestModeData), GATT_PDU_TYPE_NOTIFICATION);
+ }
+ }
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ return cb_result;
+}
+
+/******************************************************************
+ * @fn app_dfu_srv_cb
+ * @brief DFU service callbacks are handled in this function.
+ * @param p_data - pointer to callback data
+ * @return cb_result
+ * @retval T_APP_RESULT
+ */
+#if SUPPORT_SILENT_OTA
+static T_APP_RESULT app_dfu_srv_cb(T_DFU_CALLBACK_DATA *p_data)
+{
+ T_APP_RESULT cb_result = APP_RESULT_SUCCESS;
+
+ switch (p_data->msg_type)
+ {
+ case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE:
+ {
+ if (p_data->msg_data.write.opcode == DFU_WRITE_START)
+ {
+ if (p_data->msg_data.write.write_attrib_index == INDEX_DFU_CONTROL_POINT_CHAR_VALUE)
+ {
+#if SUPPORT_BAT_DETECT_FEATURE
+ bat_update_battery_info();
+ if (bat_get_current_voltage_value() < BAT_ENTER_OTA_MODE_THRESHOLD)
+ {
+ APP_PRINT_INFO0("battery voltage value < BAT_ENTER_OTA_MODE_THRESHOLD, can't start OTA");
+ cb_result = APP_RESULT_REJECT;
+ break;
+ }
+#endif
+ app_set_latency_status(LATENCY_DFU_PROC_BIT, LANTENCY_OFF);
+ }
+ }
+ else if (p_data->msg_data.write.opcode == DFU_WRITE_ATTR_EXIT)
+ {
+ if (p_data->msg_data.write.write_attrib_index == INDEX_DFU_CONTROL_POINT_CHAR_VALUE)
+ {
+ uint8_t control_point_opcode = *p_data->msg_data.write.p_value;
+ switch (control_point_opcode)
+ {
+ case DFU_OPCODE_VALID_FW:
+ {
+ T_IO_MSG dfu_valid_fw_msg;
+ dfu_valid_fw_msg.type = IO_MSG_TYPE_DFU_VALID_FW;
+ dfu_valid_fw_msg.u.param = p_data->conn_id;
+ if (app_send_msg_to_apptask(&dfu_valid_fw_msg) == false)
+ {
+ DBG_DIRECT("DFU send Valid FW msg fail!");
+ }
+ }
+ break;
+ case DFU_OPCODE_ACTIVE_IMAGE_RESET:
+ {
+ rcu_terminate_connection(DISCONN_REASON_SILENT_OTA);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if (p_data->msg_data.write.opcode == DFU_WRITE_ATTR_ENTER)
+ {
+#if FEATURE_SUPPORT_NO_ACTION_DISCONN
+ os_timer_restart(&no_act_disconn_timer, NO_ACTION_DISCON_TIMEOUT);
+#endif
+
+ /*check rcu state*/
+ uint8_t notif_data[9] = {0};
+ uint8_t control_point_opcode = *p_data->msg_data.write.p_value;
+ if (RCU_STATUS_PAIRED != app_global_data.rcu_status)
+ {
+ APP_PRINT_INFO0("[app_dfu_srv_cb] err: rcu is not paired.");
+
+ notif_data[0] = DFU_OPCODE_NOTIFICATION;
+ notif_data[1] = control_point_opcode;
+ notif_data[2] = DFU_ARV_FAIL_SYS_VERSION_ERROR;
+ server_send_data(0, app_global_data.dfu_srv_id, INDEX_DFU_CONTROL_POINT_CHAR_VALUE, \
+ notif_data, 3, GATT_PDU_TYPE_NOTIFICATION);
+ cb_result = APP_RESULT_REJECT;
+ }
+ }
+ }
+ break;
+ case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION:
+ {
+ if (p_data->msg_data.notification_indification_index == DFU_NOTIFY_ENABLE)
+ {
+ APP_PRINT_INFO0("dfu notification enable");
+ }
+ else if (p_data->msg_data.notification_indification_index ==
+ DFU_NOTIFY_DISABLE)
+ {
+ APP_PRINT_INFO0("dfu notification disable");
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+ return cb_result;
+}
+#endif
+
+/******************************************************************
+ * @fn peripheral_HandleBtDevStateChangeEvt
+ * @brief All the gaprole_States_t events are pre-handled in this function.
+ * Then the event handling function shall be called according to the newState.
+ *
+ * @param new_state - new gap state
+ * @param uint16_t cause
+ * @return none
+ * @retval void
+ */
+static void periph_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause)
+{
+ APP_PRINT_INFO4("periph_handle_dev_state_evt: init state %d, adv state %d, conn state %d, cause 0x%x",
+ new_state.gap_init_state, new_state.gap_adv_state,
+ new_state.gap_conn_state, cause);
+
+#if FEATURE_SUPPORT_PRIVACY
+ if ((new_state.gap_init_state == GAP_INIT_STATE_STACK_READY)
+ && (new_state.gap_adv_state == GAP_ADV_STATE_IDLE)
+ && (new_state.gap_conn_state == GAP_CONN_DEV_STATE_IDLE))
+ {
+ privacy_handle_resolv_list();
+ }
+#endif
+
+ if (app_global_data.gap_dev_state.gap_init_state != new_state.gap_init_state)
+ {
+ if (new_state.gap_init_state == GAP_INIT_STATE_STACK_READY)
+ {
+ APP_PRINT_INFO0("GAP stack ready");
+
+ /* set PPCP, otherwise may cause connection update failed case */
+ gaps_set_peripheral_preferred_conn_param(PPCP_CONN_INTERVAL_MIN, PPCP_CONN_INTERVAL_MAX,
+ PPCP_SLAVE_LATENCY, PPCP_SUP_TIMEOUT / 10);
+
+ app_global_data.rcu_status = RCU_STATUS_IDLE;
+
+#if SUPPORT_BAT_DETECT_FEATURE
+ /* update battery after stack ready */
+ bat_update_battery_info();
+#endif
+
+ T_LE_KEY_ENTRY *p_le_key_entry;
+ p_le_key_entry = le_get_high_priority_bond();
+ if ((p_le_key_entry != NULL) && (p_le_key_entry->is_used))
+ {
+ app_global_data.is_link_key_existed = true;
+ /* add paired device in white list */
+ le_modify_white_list(GAP_WHITE_LIST_OP_ADD, p_le_key_entry->remote_bd.addr,
+ (T_GAP_REMOTE_ADDR_TYPE)(p_le_key_entry->remote_bd.remote_bd_type));
+
+ /* attempt to reconnect with master if ont in low power*/
+ if (BAT_MODE_POWER_DOWN != bat_get_current_mode())
+ {
+ rcu_start_adv(ADV_DIRECT_LDC);
+ }
+ }
+ else
+ {
+ app_global_data.is_link_key_existed = false;
+
+ if (app_global_data.reset_reason != RESET_REASON_FACTORY_RESET)
+ {
+ if (BAT_MODE_POWER_DOWN != bat_get_current_mode())
+ {
+ rcu_start_adv(ADV_UNDIRECT_PAIRING);
+ }
+ }
+ }
+
+ app_nvic_config(); /* enable peripheral NVIC after GAP stack ready */
+ if (app_global_data.reset_reason == RESET_REASON_HW)
+ {
+ APP_PRINT_INFO0("start timer for back key when reset");
+ app_global_data.is_allow_to_factory_reset_for_back_key = 1;
+ os_timer_restart(&back_key_pressed_when_HW_reset_timer,
+ CHECK_BACK_KEY_PRESSED_WHEN_HW_RESET_TIMEOUT);
+ }
+ }
+ }
+
+ if (app_global_data.gap_dev_state.gap_adv_state != new_state.gap_adv_state)
+ {
+ if (new_state.gap_adv_state == GAP_ADV_STATE_IDLE)
+ {
+ /* sync rcu status to idle */
+ app_global_data.rcu_status = RCU_STATUS_IDLE;
+ os_timer_stop(&adv_timer);
+ os_timer_stop(&adv_change_data_timer);
+
+ if (new_state.gap_adv_sub_state == GAP_ADV_TO_IDLE_CAUSE_STOP)
+ {
+ APP_PRINT_INFO0("Advertisng is stopped by user stop or timeouot");
+ /* check adv stop reason */
+ app_stop_adv_reason_handler(app_global_data.stop_adv_reason);
+ app_global_data.stop_adv_reason = STOP_ADV_REASON_IDLE; /* reset stop_adv_reason */
+ }
+ else if (new_state.gap_adv_sub_state == GAP_ADV_TO_IDLE_CAUSE_CONN)
+ {
+ APP_PRINT_INFO0("Advertisng is stopped for link establishment");
+ }
+ }
+ else if (new_state.gap_adv_state == GAP_ADV_STATE_ADVERTISING)
+ {
+ APP_PRINT_INFO0("GAP adv start");
+ app_global_data.rcu_status = RCU_STATUS_ADVERTISING;
+ }
+ }
+
+ if (app_global_data.gap_dev_state.gap_conn_state != new_state.gap_conn_state)
+ {
+ APP_PRINT_INFO2("conn state: %d -> %d",
+ app_global_data.gap_dev_state.gap_conn_state,
+ new_state.gap_conn_state);
+ }
+ app_global_data.gap_dev_state = new_state;
+}
+
+/******************************************************************
+ * @fn peripheral_HandleBtDevStateChangeEvt
+ * @brief Handle connection status change event.
+ *
+ * @param uint8_t conn_id
+ * @param T_GAP_CONN_STATE new_state
+ * @param uint16_t disc_cause
+ * @return none
+ * @retval void
+ */
+static void periph_handle_conn_state_evt(uint8_t conn_id, T_GAP_CONN_STATE new_state,
+ uint16_t disc_cause)
+{
+ APP_PRINT_INFO3("periph_handle_conn_state_evt: conn_id = %d old_state = %d new_state = %d",
+ conn_id, app_global_data.gap_conn_state, new_state);
+ switch (new_state)
+ {
+ case GAP_CONN_STATE_DISCONNECTED:
+ {
+ app_global_data.rcu_status = RCU_STATUS_IDLE;
+ app_global_data.is_keyboard_notify_en = false;
+ app_global_data.is_mm_keyboard_notify_en = false;
+ app_global_data.is_atv_voice_notify_en = false;
+ LED_BLINK_EXIT(LED_TYPE_BLINK_PAIR_ADV);
+#if FEATURE_SUPPORT_NO_ACTION_DISCONN
+ /* stop no_act_disconn_timer if disconnection detected */
+ os_timer_stop(&no_act_disconn_timer);
+#endif
+ os_timer_stop(&next_state_check_timer); /* ensure pair_fail_disconn_timer is stopped */
+#if FEAUTRE_SUPPORT_IR_OVER_BLE
+ ir_service_handle_disconnect_event();
+#endif
+#if SUPPORT_BUZZER_FEATURE
+ fms_handle_disconnect_event();
+#endif
+ key_handle_disconnect_event();
+#if SUPPORT_VOICE_FEATURE
+ if (voice_driver_global_data.is_voice_driver_working == true)
+ {
+ voice_global_data.is_allowed_to_notify_voice_data = false;
+ voice_handle_stop_mic();
+ }
+#endif
+ if (disc_cause == (HCI_ERR | HCI_ERR_REMOTE_USER_TERMINATE))
+ {
+ APP_PRINT_INFO0("[GAP_CONN_STATE_DISCONNECTED] REMOTE_USER_TERMINATE");
+
+ if (app_global_data.is_link_key_existed == false)
+ {
+ if (app_global_data.pair_failed_retry_cnt < MAX_PAIR_FAILED_RETRY_CNT)
+ {
+ app_global_data.pair_failed_retry_cnt++;
+ rcu_start_adv(ADV_UNDIRECT_PAIRING);
+ }
+ }
+ else
+ {
+ rcu_start_adv(ADV_DIRECT_LDC);
+ }
+ }
+ else if (disc_cause == (HCI_ERR | HCI_ERR_LOCAL_HOST_TERMINATE))
+ {
+ /* handle APP disconection reason */
+ app_disconn_reason_handler(app_global_data.disconn_reason);
+ }
+ else
+ {
+ APP_PRINT_WARN1("[GAP_CONN_STATE_DISCONNECTED] Connection lost: cause 0x%x", disc_cause);
+
+ if (true == app_global_data.is_link_key_existed)
+ {
+ rcu_start_adv(ADV_DIRECT_LDC);
+ }
+ }
+
+ app_global_data.disconn_reason = DISCONN_REASON_IDLE; /* reset disconn_reason */
+ }
+ break;
+
+ case GAP_CONN_STATE_CONNECTED:
+ {
+ app_global_data.rcu_status = RCU_STATUS_CONNECTED;
+ os_timer_restart(&next_state_check_timer, PAIRING_EXCEPTION_TIMEOUT);
+
+ /* reset latency_status to default after connect */
+ memset(&app_global_data.latency_status, 0, sizeof(app_global_data.latency_status));
+ /* turn off slave latency to speed up pairing process, have to turn on latency later */
+ app_set_latency_status(LATENCY_SYS_UPDATE_BIT, LANTENCY_OFF);
+#if FEATURE_SUPPORT_DATA_LENGTH_EXTENSION
+ uint16_t gap_param_data_len_tx_oct = 251;
+ uint16_t gap_param_data_len_tx_time = 2120; /* tx max time: 2.12ms */
+ le_set_data_len(conn_id, gap_param_data_len_tx_oct, gap_param_data_len_tx_time);
+#endif
+#if SUPPORT_BUZZER_FEATURE
+ fms_handle_connect_event();
+#endif
+ /* print remote device information */
+ uint16_t conn_interval;
+ uint16_t conn_latency;
+ uint16_t conn_supervision_timeout;
+ uint8_t remote_bd[6];
+ uint8_t remote_bd_type;
+ le_get_conn_param(GAP_PARAM_CONN_INTERVAL, &conn_interval, conn_id);
+ le_get_conn_param(GAP_PARAM_CONN_LATENCY, &conn_latency, conn_id);
+ le_get_conn_param(GAP_PARAM_CONN_TIMEOUT, &conn_supervision_timeout, conn_id);
+ le_get_conn_addr(conn_id, remote_bd, &remote_bd_type);
+ APP_PRINT_INFO5("GAP_CONN_STATE_CONNECTED:remote_bd %s, remote_addr_type %d, conn_interval 0x%x, conn_latency 0x%x, conn_supervision_timeout 0x%x",
+ TRACE_BDADDR(remote_bd), remote_bd_type,
+ conn_interval, conn_latency, conn_supervision_timeout);
+ }
+ break;
+
+ default:
+ break;
+ }
+ app_global_data.gap_conn_state = new_state;
+}
+
+/******************************************************************
+ * @fn peripheral_HandleBtGapAuthenStateChangeEvt
+ * @brief All the bonding state change events are pre-handled in this function.
+ * Then the event handling function shall be called according to the newState.
+ *
+ * @param uint8_t conn_id
+ * @param T_GAP_CONN_STATE new_state
+ * @param uint16_t cause
+ * @return none
+ * @retval void
+ */
+static void periph_handle_authen_state_evt(uint8_t conn_id, uint8_t new_state, uint16_t cause)
+{
+ APP_PRINT_INFO1("periph_handle_authen_state_evt:conn_id %d", conn_id);
+
+ switch (new_state)
+ {
+ case GAP_AUTHEN_STATE_STARTED:
+ {
+ APP_PRINT_INFO0("GAP_AUTHEN_STATE_STARTED");
+ os_timer_restart(&next_state_check_timer, PAIRING_EXCEPTION_TIMEOUT);
+ /* slave init MTU size exchange process */
+ client_send_exchange_mtu_req(conn_id);
+ }
+ break;
+
+ case GAP_AUTHEN_STATE_COMPLETE:
+ {
+ if (cause == GAP_CAUSE_SUCCESS)
+ {
+ APP_PRINT_INFO0("[GAP_AUTHEN_STATE_COMPLETE] pairing success");
+ app_global_data.is_link_key_existed = true;
+ app_global_data.rcu_status = RCU_STATUS_PAIRED;
+ app_global_data.pair_failed_retry_cnt = 0;
+ app_global_data.updt_conn_params_retry_cnt = 0; /* reset retry cnt */
+
+ os_timer_stop(&next_state_check_timer);
+#if FEATURE_SUPPORT_NO_ACTION_DISCONN
+ os_timer_restart(&no_act_disconn_timer, NO_ACTION_DISCON_TIMEOUT);
+#endif
+
+ if ((app_global_data.adv_type == ADV_DIRECT_HDC)
+ || (app_global_data.adv_type == ADV_UNDIRECT_RECONNECT)
+ || (app_global_data.adv_type == ADV_UNDIRECT_WAKEUP)
+ || (app_global_data.adv_type == ADV_DIRECT_LDC))
+ {
+ os_timer_restart(&notify_key_data_after_reconn_timer, NOTIFY_KEY_DATA_TIMEOUT);
+
+ /* update connection parameter 1s delay */
+ os_timer_restart(&update_conn_params_timer, UPDATE_CONN_PARAMS_SHORT_TIMEOUT);
+ }
+ else
+ {
+ LED_BLINK_EXIT(LED_TYPE_BLINK_PAIR_ADV);
+ LED_BLINK(LED_TYPE_BLINK_CONFIRMATION, 2);
+
+ key_handle_reset_key_pressed_cache_fifo();
+ /* start timer to update connection parameter, postpone with timer to accelate GATT process */
+ os_timer_restart(&update_conn_params_timer, UPDATE_CONN_PARAMS_TIMEOUT);
+ }
+ }
+ else
+ {
+#if SUPPORT_LED_INDICATION_FEATURE
+ LED_BLINK_EXIT(LED_TYPE_BLINK_PAIR_ADV);
+ LED_BLINK(LED_TYPE_BLINK_ERROR, 4);
+#endif
+ if (cause == (SM_ERR | SM_ERR_KEY_SAVE_FAILED))
+ {
+ le_bond_clear_all_keys();
+ }
+
+ else if (cause == (SM_ERR | SM_ERR_LINK_KEY_MISSING))
+ {
+ APP_PRINT_INFO0("G20 - key missing");
+ }
+ APP_PRINT_INFO0("[GAP_AUTHEN_STATE_COMPLETE] pair failed");
+
+ os_timer_restart(&next_state_check_timer, PAIR_FAIL_DISCONN_TIMEOUT);
+ }
+ }
+ break;
+
+ default:
+ {
+ APP_PRINT_INFO1("GAP_MSG_LE_AUTHEN_STATE_CHANGE:(unknown newstate: %d)", new_state);
+ }
+ break;
+ }
+}
+
+/******************************************************************
+ * @fn peripheral_HandleBtGapConnParaChangeEvt
+ * @brief All the connection parameter update change events are pre-handled in this function.
+ * Then the event handling function shall be called according to the status.
+ *
+ * @param uint8_t conn_id
+ * @param uint8_t status - connection parameter result, 0 - success, otherwise fail.
+ * @param uint16_t cause
+ * @return none
+ * @retval void
+ */
+static void periph_conn_param_update_evt(uint8_t conn_id, uint8_t status, uint16_t cause)
+{
+ switch (status)
+ {
+ case GAP_CONN_PARAM_UPDATE_STATUS_SUCCESS:
+ {
+ /* reset updt_conn_params_retry_cnt */
+ app_global_data.updt_conn_params_retry_cnt = 0;
+
+ le_get_conn_param(GAP_PARAM_CONN_INTERVAL, &app_global_data.conn_interval, conn_id);
+ le_get_conn_param(GAP_PARAM_CONN_LATENCY, &app_global_data.conn_latency, conn_id);
+ le_get_conn_param(GAP_PARAM_CONN_TIMEOUT, &app_global_data.conn_supervision_timeout, conn_id);
+
+ APP_PRINT_INFO3("GAP_MSG_LE_CONN_PARAM_UPDATE update success:conn_interval 0x%x, conn_slave_latency 0x%x, conn_supervision_timeout 0x%x",
+ app_global_data.conn_interval, app_global_data.conn_latency,
+ app_global_data.conn_supervision_timeout);
+ }
+ break;
+
+ case GAP_CONN_PARAM_UPDATE_STATUS_FAIL:
+ {
+ APP_PRINT_ERROR1("GAP_MSG_LE_CONN_PARAM_UPDATE failed: cause 0x%x", cause);
+ if (app_global_data.updt_conn_params_retry_cnt < MAX_UPDATE_CONN_PARAMS_RETRY_CNT)
+ {
+ app_global_data.updt_conn_params_retry_cnt++;
+ APP_PRINT_WARN0("[rcu_update_conn_params] GAP_CONN_PARAM_UPDATE_STATUS_FAIL retry");
+ os_timer_restart(&update_conn_params_timer, UPDATE_CONN_PARAMS_TIMEOUT);
+ }
+ else
+ {
+ APP_PRINT_WARN0("[rcu_update_conn_params] GAP_CONN_PARAM_UPDATE_STATUS_FAIL failed");
+ }
+ }
+ break;
+
+ case GAP_CONN_PARAM_UPDATE_STATUS_PENDING:
+ {
+ APP_PRINT_INFO0("GAP_CONN_PARAM_UPDATE_STATUS_PENDING");
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/******************************************************************
+ * @fn peripheral_HandleBtGapMessage
+ * @brief All the bt gap msg events are pre-handled in this function.
+ * Then the event handling function shall be called according to the subType
+ * of BEE_IO_MSG.
+ *
+ * @param p_gap_msg - pointer to bee io msg
+ * @return none
+ * @retval void
+ */
+static void periph_handle_gap_msg(T_IO_MSG *p_gap_msg)
+{
+ T_LE_GAP_MSG gap_msg;
+ uint8_t conn_id;
+ memcpy(&gap_msg, &p_gap_msg->u.param, sizeof(p_gap_msg->u.param));
+
+ APP_PRINT_TRACE1("periph_handle_gap_msg subType = %d", p_gap_msg->subtype);
+ switch (p_gap_msg->subtype)
+ {
+ case GAP_MSG_LE_DEV_STATE_CHANGE:
+ {
+ periph_handle_dev_state_evt(gap_msg.msg_data.gap_dev_state_change.new_state,
+ gap_msg.msg_data.gap_dev_state_change.cause);
+ }
+ break;
+
+ case GAP_MSG_LE_CONN_STATE_CHANGE:
+ {
+ periph_handle_conn_state_evt(gap_msg.msg_data.gap_conn_state_change.conn_id,
+ (T_GAP_CONN_STATE)gap_msg.msg_data.gap_conn_state_change.new_state,
+ gap_msg.msg_data.gap_conn_state_change.disc_cause);
+ }
+ break;
+
+ case GAP_MSG_LE_AUTHEN_STATE_CHANGE:
+ {
+ periph_handle_authen_state_evt(gap_msg.msg_data.gap_authen_state.conn_id,
+ gap_msg.msg_data.gap_authen_state.new_state,
+ gap_msg.msg_data.gap_authen_state.status);
+ }
+ break;
+
+ case GAP_MSG_LE_BOND_JUST_WORK:
+ {
+ conn_id = gap_msg.msg_data.gap_bond_just_work_conf.conn_id;
+ le_bond_just_work_confirm(conn_id, GAP_CFM_CAUSE_ACCEPT);
+ APP_PRINT_INFO0("GAP_MSG_LE_BOND_JUST_WORK");
+ }
+ break;
+
+ case GAP_MSG_LE_BOND_PASSKEY_DISPLAY:
+ {
+ uint32_t display_value = 0;
+ conn_id = gap_msg.msg_data.gap_bond_passkey_display.conn_id;
+ le_bond_get_display_key(conn_id, &display_value);
+ APP_PRINT_INFO1("GAP_MSG_LE_BOND_PASSKEY_DISPLAY:passkey %d", display_value);
+ }
+ break;
+
+ case GAP_MSG_LE_BOND_USER_CONFIRMATION:
+ {
+ uint32_t display_value = 0;
+ conn_id = gap_msg.msg_data.gap_bond_user_conf.conn_id;
+ le_bond_get_display_key(conn_id, &display_value);
+ APP_PRINT_INFO1("GAP_MSG_LE_BOND_USER_CONFIRMATION: passkey %d", display_value);
+ le_bond_user_confirm(conn_id, GAP_CFM_CAUSE_ACCEPT);
+ }
+ break;
+
+ case GAP_MSG_LE_BOND_PASSKEY_INPUT:
+ {
+ uint32_t passkey = 888888;
+ conn_id = gap_msg.msg_data.gap_bond_passkey_input.conn_id;
+ APP_PRINT_INFO1("GAP_MSG_LE_BOND_PASSKEY_INPUT: conn_id %d", conn_id);
+ le_bond_passkey_input_confirm(conn_id, passkey, GAP_CFM_CAUSE_ACCEPT);
+ }
+ break;
+
+ case GAP_MSG_LE_BOND_OOB_INPUT:
+ {
+ uint8_t oob_data[GAP_OOB_LEN] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ conn_id = gap_msg.msg_data.gap_bond_oob_input.conn_id;
+ APP_PRINT_INFO0("GAP_MSG_LE_BOND_OOB_INPUT");
+ le_bond_set_param(GAP_PARAM_BOND_OOB_DATA, GAP_OOB_LEN, oob_data);
+ le_bond_oob_input_confirm(conn_id, GAP_CFM_CAUSE_ACCEPT);
+ }
+ break;
+
+ case GAP_MSG_LE_CONN_PARAM_UPDATE:
+ {
+ periph_conn_param_update_evt(gap_msg.msg_data.gap_conn_param_update.conn_id,
+ gap_msg.msg_data.gap_conn_param_update.status,
+ gap_msg.msg_data.gap_conn_param_update.cause);
+ }
+ break;
+ case GAP_MSG_LE_CONN_MTU_INFO:
+ {
+ uint8_t mtu_size = 0;
+ le_get_conn_param(GAP_PARAM_CONN_MTU_SIZE, &mtu_size,
+ gap_msg.msg_data.gap_conn_mtu_info.conn_id);
+
+ if (mtu_size >= 23)
+ {
+ /* update mtu size */
+ app_global_data.mtu_size = mtu_size;
+ APP_PRINT_INFO1("[periph_handle_gap_msg] update mtu size to %d", mtu_size);
+ }
+ }
+ break;
+
+ default:
+ APP_PRINT_ERROR1("periph_handle_gap_msg: unknown subtype %d", p_gap_msg->subtype);
+ break;
+ }
+}
+
+/*============================================================================*
+ * Global Functions
+ *============================================================================*/
+#if !FEATURE_SUPPORT_PRIVACY
+/******************************************************************
+ * @brief handle bond modify message.
+ * @param T_LE_BOND_MODIFY_TYPE type
+ * @param T_LE_KEY_ENTRY *p_entry
+ * @return none
+ * @retval void
+ */
+void app_handle_bond_modify_msg(T_LE_BOND_MODIFY_TYPE type, T_LE_KEY_ENTRY *p_entry)
+{
+ APP_PRINT_INFO1("app_handle_bond_modify_msg GAP_MSG_LE_BOND_MODIFY_INFO:type=0x%x",
+ type);
+
+ switch (type)
+ {
+ case LE_BOND_DELETE:
+ {
+ le_modify_white_list(GAP_WHITE_LIST_OP_REMOVE, p_entry->remote_bd.addr,
+ (T_GAP_REMOTE_ADDR_TYPE)(p_entry->remote_bd.remote_bd_type));
+ }
+ break;
+ case LE_BOND_ADD:
+ {
+ le_modify_white_list(GAP_WHITE_LIST_OP_ADD, p_entry->remote_bd.addr,
+ (T_GAP_REMOTE_ADDR_TYPE)(p_entry->remote_bd.remote_bd_type));
+ }
+ break;
+ case LE_BOND_CLEAR:
+ {
+ le_modify_white_list(GAP_WHITE_LIST_OP_CLEAR, p_entry->remote_bd.addr,
+ (T_GAP_REMOTE_ADDR_TYPE)(p_entry->remote_bd.remote_bd_type));
+ }
+ break;
+ default:
+ break;
+ }
+}
+#endif
+
+/******************************************************************
+ * @brief set or get rcu app latency status.
+ * @param index_bit - module index
+ * @param new_status - LANTENCY_ON or LANTENCY_OFF
+ * @return none
+ * @retval void
+ */
+void app_set_latency_status(T_APP_LATENCY_MASK index_bit, T_LATENCY_STATE new_state)
+{
+ uint8_t retry_cnt = 0;
+ bool latency_update_value = true;
+
+ APP_PRINT_INFO2("[app_set_latency_status] module index = %d, new_state is %d", index_bit,
+ new_state);
+
+ /*0. check new state valid or not */
+ if ((new_state != LANTENCY_ON) && (new_state != LANTENCY_OFF))
+ {
+ APP_PRINT_WARN0("[app_set_latency_status] new_state is invalid");
+ return;
+ }
+
+ /*1. check latency state is updating */
+ if (app_global_data.latency_status.is_updating == true)
+ {
+ APP_PRINT_INFO0("[app_set_latency_status] latency_status is pending!");
+ /* update pending latency status */
+ app_global_data.latency_status.is_pending = true;
+ app_global_data.latency_status.pending_status = new_state;
+ app_global_data.latency_status.pending_index_bit = index_bit;
+ return ;
+ }
+
+ /*2. update latency data value */
+ if (new_state == LANTENCY_OFF)
+ {
+ app_global_data.latency_status.latency_bits_map |= (1 << index_bit);
+ }
+ else
+ {
+ app_global_data.latency_status.latency_bits_map &= ~(1 << index_bit);
+ }
+
+ /*3. check whether need update according to latency value*/
+ if (0 == app_global_data.latency_status.latency_bits_map)
+ {
+ /* need enable latency*/
+ if (LANTENCY_ON == app_global_data.latency_status.cur_status)
+ {
+ APP_PRINT_INFO0("[app_set_latency_status] latency_status is already enabled!");
+ return;
+ }
+ latency_update_value = false;
+ }
+ else
+ {
+ /* need disable latency */
+ if (LANTENCY_OFF == app_global_data.latency_status.cur_status)
+ {
+ APP_PRINT_INFO0("[app_set_latency_status] latency_status is already disabled!");
+ return;
+ }
+ latency_update_value = true;
+ }
+
+ /*4. process latency update*/
+ while (retry_cnt < MAX_ONOFF_LATENCY_SEND_RETRY_CNT)
+ {
+ if (le_disable_slave_latency(0, latency_update_value) == GAP_CAUSE_SUCCESS)
+ {
+ APP_PRINT_INFO1("[app_set_latency_status] call le_disable_slave_latency successfully, latency bit map: %#x",
+ app_global_data.latency_status.latency_bits_map);
+ app_global_data.latency_status.is_pending = false;
+ app_global_data.latency_status.is_updating = true;
+ app_global_data.latency_status.cur_status = new_state;
+ app_global_data.latency_status.cur_index_bit = index_bit;
+ return;
+ }
+ retry_cnt++;
+ }
+
+ /*5. check update success or not*/
+ if (retry_cnt >= MAX_ONOFF_LATENCY_SEND_RETRY_CNT)
+ {
+ /* all retry failed */
+ APP_PRINT_WARN0("[app_set_latency_status] all retry failed");
+ /* TBD: how to handle this scenario */
+ }
+}
+
+/******************************************************************
+ * @fn app_init_global_data
+ * @brief Initialize global APP data
+ * @param void
+ * @return none
+ * @retval void
+ */
+void app_init_global_data(void)
+{
+ memset(&app_global_data, 0, sizeof(app_global_data));
+ app_global_data.mtu_size = 23;
+ app_global_data.device_type = REMOTE_G20;
+ app_global_data.en_ble_feature = 1;
+ app_global_data.en_powerkey_cache = 1;
+ app_global_data.en_google_wakeuppack = 1;
+ memcpy(app_global_data.pnp_id, Default_PnP_ID, sizeof(Default_PnP_ID));
+ memcpy(app_global_data.fw_version, Default_FW_Rev, sizeof(Default_FW_Rev));
+ app_global_data.fw_version[1] = VERSION_MAJOR + 0x30;
+ memcpy(app_global_data.sw_version, Default_SW_Rev, sizeof(Default_SW_Rev));
+ app_global_data.sw_version[1] = VERSION_MINOR + 0x30;
+ app_global_data.sw_version[3] = VERSION_REVISION + 0x30;
+ app_global_data.sw_version[4] = VERSION_BUILDNUM + 0x30;
+ memset(app_global_data.wakeup_key1, 0xFF, sizeof(app_global_data.wakeup_key1));
+ app_global_data.wakeup_key1[0] = KEY_ID_Power;
+ memset(app_global_data.wakeup_key2, 0xFF, sizeof(app_global_data.wakeup_key2));
+ app_global_data.wakeup_adv_format = WAKEUP_FORMAT_GOOGLE_ONLY;
+ app_load_wakeup_key_cnt(&app_global_data.wakeup_key_count);
+ app_global_data.wakeup_key_index = KEY_ID_NONE;
+}
+
+/******************************************************************
+ * @fn app_handle_io_msg
+ * @brief All the application events are pre-handled in this function.
+ * All the IO MSGs are sent to this function, Then the event handling function
+ * shall be called according to the MSG type.
+ *
+ * @param io_msg - bee io msg data
+ * @return none
+ * @retval void
+ */
+void app_handle_io_msg(T_IO_MSG io_msg)
+{
+ uint16_t msg_type = io_msg.type;
+
+ APP_PRINT_INFO1("[app_handle_io_msg] msg_type is %d", msg_type);
+
+ switch (msg_type)
+ {
+ case IO_MSG_TYPE_BT_STATUS:
+ {
+ periph_handle_gap_msg(&io_msg);
+ }
+ break;
+ case IO_MSG_TYPE_KEYSCAN:
+ {
+#if FEATURE_SUPPORT_NO_ACTION_DISCONN
+ /* key event to restart no_act_disconn_timer */
+ os_timer_restart(&no_act_disconn_timer, NO_ACTION_DISCON_TIMEOUT);
+#endif
+ if (key_handle_global_data.combine_keys_status != INVALID_COMBINE_KEYS_BIT_MASK)
+ {
+ /* reset combine keys bit mask and timer */
+ key_handle_global_data.combine_keys_status = INVALID_COMBINE_KEYS_BIT_MASK;
+ os_timer_stop(&combine_keys_detection_timer);
+ LED_BLINK_EXIT(LED_TYPE_BLINK_COMB_KEY_PRESS);
+ }
+
+ if (io_msg.subtype == IO_MSG_KEYSCAN_ALLKEYRELEASE)
+ {
+ key_handle_release_event();
+ }
+ else if (io_msg.subtype == IO_MSG_KEYSCAN_RX_PKT)
+ {
+#if FEATURE_SUPPORT_KEY_LONG_PRESS_PROTECT
+ if (false == key_handle_global_data.is_key_long_pressed)
+#endif
+ {
+ key_handle_pressed_event(io_msg.u.buf);
+ }
+ }
+ }
+ break;
+#if SUPPORT_VOICE_FEATURE
+ case IO_MSG_TYPE_GDMA:
+ APP_PRINT_INFO0("[Voice] GDMA Voice data MSG.");
+#if MP_TEST_MODE_SUPPORT_DATA_UART_TEST
+ if (app_global_data.test_mode == DATA_UART_TEST_MODE)
+ {
+ uart_test_handle_gdma_msg(io_msg);
+ }
+ else
+#endif
+ {
+ voice_handle_messages(VOICE_MSG_PERIPHERAL_GDMA, &io_msg);
+ }
+ break;
+#endif
+#if SUPPORT_IR_TX_FEATURE
+ case IO_MSG_TYPE_IR:
+ {
+ ir_send_msg_proc(io_msg.subtype);
+ }
+ break;
+#endif
+ case IO_MSG_TYPE_IR_FLASH:
+ {
+ ir_service_handle_flash_save_event();
+ }
+ break;
+#if (FEATURE_SUPPORT_MP_TEST_MODE && MP_TEST_MODE_SUPPORT_DATA_UART_TEST)
+ case IO_MSG_TYPE_UART:
+ {
+ uart_test_handle_uart_msg(io_msg);
+ }
+ break;
+#endif
+#if SUPPORT_BAT_DETECT_FEATURE
+ case IO_MSG_TYPE_BAT_DETECT:
+ {
+ bat_msg_handle(io_msg.subtype);
+ }
+ break;
+#endif
+ case IO_MSG_TYPE_RESET_WDG_TIMER:
+ {
+ APP_PRINT_INFO0("[WDG] Watch Dog Rset Timer");
+ WDG_Restart();
+ }
+ break;
+#if SUPPORT_SILENT_OTA
+ case IO_MSG_TYPE_DFU_VALID_FW:
+ {
+ dfu_service_handle_valid_fw(io_msg.u.param);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+/******************************************************************
+ * @fn app_gap_callback
+ * @brief All the application gap events are pre-handled in this function.
+ *
+ * @param cb_type - event type
+ * @param p_cb_data - point to datas
+ * @return result
+ * @retval T_APP_RESULT
+ */
+T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data)
+{
+ T_APP_RESULT result = APP_RESULT_SUCCESS;
+ T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data;
+
+ switch (cb_type)
+ {
+ case GAP_MSG_LE_DATA_LEN_CHANGE_INFO:
+ APP_PRINT_INFO3("GAP_MSG_LE_DATA_LEN_CHANGE_INFO: conn_id %d, tx octets 0x%x, max_tx_time 0x%x",
+ p_data->p_le_data_len_change_info->conn_id,
+ p_data->p_le_data_len_change_info->max_tx_octets,
+ p_data->p_le_data_len_change_info->max_tx_time);
+ break;
+
+ case GAP_MSG_LE_BOND_MODIFY_INFO:
+ APP_PRINT_INFO1("GAP_MSG_LE_BOND_MODIFY_INFO: type 0x%x",
+ p_data->p_le_bond_modify_info->type);
+#if FEATURE_SUPPORT_PRIVACY
+ privacy_handle_bond_modify_msg(p_data->p_le_bond_modify_info->type,
+ p_data->p_le_bond_modify_info->p_entry, true);
+#else
+ app_handle_bond_modify_msg(p_data->p_le_bond_modify_info->type,
+ p_data->p_le_bond_modify_info->p_entry);
+#endif
+ break;
+
+ case GAP_MSG_LE_MODIFY_WHITE_LIST:
+ APP_PRINT_INFO2("GAP_MSG_LE_MODIFY_WHITE_LIST: operation %d, cause 0x%x",
+ p_data->p_le_modify_white_list_rsp->operation,
+ p_data->p_le_modify_white_list_rsp->cause);
+ break;
+
+ case GAP_MSG_LE_DISABLE_SLAVE_LATENCY:
+ APP_PRINT_INFO1("GAP_MSG_LE_DISABLE_SLAVE_LATENCY: cause 0x%x",
+ p_data->p_le_disable_slave_latency_rsp->cause);
+ /* restore is_updating to false */
+ app_global_data.latency_status.is_updating = false;
+ if (p_data->p_le_disable_slave_latency_rsp->cause == GAP_CAUSE_SUCCESS)
+ {
+ app_global_data.latency_status.retry_cnt = 0;
+ /* check if has any pending status */
+ if (app_global_data.latency_status.is_pending == true)
+ {
+ APP_PRINT_INFO0("[app_gap_callback] handle onoff latency pending status");
+ app_set_latency_status(app_global_data.latency_status.pending_index_bit,
+ app_global_data.latency_status.pending_status);
+ }
+ }
+ else
+ {
+ if (app_global_data.latency_status.retry_cnt < MAX_ONOFF_LATENCY_FAILED_RETRY_CNT)
+ {
+ APP_PRINT_WARN0("[app_gap_callback] retry onoff latency");
+ app_global_data.latency_status.retry_cnt++;
+ app_set_latency_status(app_global_data.latency_status.cur_index_bit,
+ app_global_data.latency_status.cur_status);
+ }
+ else
+ {
+ APP_PRINT_ERROR0("[app_gap_callback] OnOff latency failed!");
+ /* TBD: how to handle this scenario */
+ }
+ }
+ break;
+
+ default:
+ APP_PRINT_INFO1("app_gap_callback: unhandled cb_type 0x%x", cb_type);
+ break;
+ }
+ return result;
+}
+
+#if FEATURE_SUPPORT_PRIVACY
+/******************************************************************
+ * @fn app_privacy_callback
+ * @brief All the privacy events are pre-handled in this function.
+ *
+ * @param type - event type
+ * @param cb_data - point to datas
+ * @return none
+ * @retval void
+ */
+void app_privacy_callback(T_PRIVACY_CB_TYPE type, T_PRIVACY_CB_DATA cb_data)
+{
+ APP_PRINT_INFO1("app_privacy_callback: type %d", type);
+ switch (type)
+ {
+ case PRIVACY_STATE_MSGTYPE:
+ app_privacy_state = cb_data.privacy_state;
+ break;
+
+ case PRIVACY_RESOLUTION_STATUS_MSGTYPE:
+ app_privacy_resolution_state = cb_data.resolution_state;
+ break;
+
+ default:
+ break;
+ }
+}
+#endif
+
+/******************************************************************
+ * @fn app_profile_callback
+ * @brief All the bt profile callbacks are handled in this function.
+ * Then the event handling function shall be called according to the serviceID
+ * of BEE_IO_MSG.
+ *
+ * @param service_id - service id of profile
+ * @param p_data - pointer to callback data
+ * @return app_result
+ * @retval T_APP_RESULT
+ */
+T_APP_RESULT app_profile_callback(T_SERVER_ID service_id, void *p_data)
+{
+ T_APP_RESULT app_result = APP_RESULT_SUCCESS;
+ if (service_id == SERVICE_PROFILE_GENERAL_ID)
+ {
+ app_general_srv_cb((T_SERVER_APP_CB_DATA *)p_data);
+ }
+ else if (service_id == app_global_data.bas_srv_id)
+ {
+ app_result = app_bas_srv_cb((T_BAS_CALLBACK_DATA *)p_data);
+ }
+ else if (service_id == app_global_data.dis_srv_id)
+ {
+ app_result = app_dis_srv_cb((T_DIS_CALLBACK_DATA *)p_data);
+ }
+ else if (service_id == app_global_data.hid_srv_id)
+ {
+ app_result = app_hid_srv_cb((T_HID_CALLBACK_DATA *)p_data);
+ }
+ else if (service_id == app_global_data.ir_srv_id)
+ {
+#if FEAUTRE_SUPPORT_IR_OVER_BLE
+ app_result = ir_service_handle_srv_cb((T_IR_CALLBACK_DATA *)p_data);
+#endif
+ }
+ else if (service_id == app_global_data.vendor_srv_id)
+ {
+ app_result = app_vendor_srv_cb((T_VENDOR_CALLBACK_DATA *)p_data);
+ }
+ else if (service_id == app_global_data.ota_srv_id)
+ {
+ app_result = app_ota_srv_cb((T_OTA_CALLBACK_DATA *)p_data);
+ }
+#if SUPPORT_SILENT_OTA
+ else if (service_id == app_global_data.dfu_srv_id)
+ {
+ app_result = app_dfu_srv_cb((T_DFU_CALLBACK_DATA *)p_data);
+ }
+#endif
+#if SUPPORT_VOICE_FEATURE
+ else if (service_id == app_global_data.atvv_srv_id)
+ {
+ app_result = voice_handle_atvv_srv_cb((T_ATVV_CALLBACK_DATA *)p_data);
+ }
+#endif
+#if SUPPORT_BUZZER_FEATURE
+ else if (service_id == app_global_data.fms_srv_id)
+ {
+ app_result = fms_handle_srv_cb((T_FMS_CALLBACK_DATA *)p_data);
+ }
+#endif
+ return app_result;
+}
+
+/******************************************************************
+ * @fn app_load_wakeup_key_cnt
+ * @brief Load the wakeup key count from FTL
+ *
+ * @param p_count - point of count
+ * @return bool
+ * @retval true or false
+ */
+bool app_load_wakeup_key_cnt(uint32_t *p_count)
+{
+ bool result = false;
+
+ if (0 == ftl_load(p_count, FTL_WAKEUP_KEY_COUNT_ADDR, FTL_WAKEUP_KEY_COUNT_LEN))
+ {
+ result = true;
+ }
+ else
+ {
+ *p_count = 0;
+ result = false;
+ }
+
+ APP_PRINT_INFO2("[app_load_wakeup_key_cnt] count = %d, result = %d", *p_count, result);
+ return result;
+}
+
+/******************************************************************
+ * @fn app_save_wakeup_key_cnt
+ * @brief Load the wakeup key count from FTL
+ *
+ * @param save_count - save count
+ * @return bool
+ * @retval true or false
+ */
+bool app_save_wakeup_key_cnt(uint32_t save_count)
+{
+ bool result = false;
+
+ if (0 == ftl_save(&save_count, FTL_WAKEUP_KEY_COUNT_ADDR, FTL_WAKEUP_KEY_COUNT_LEN))
+ {
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+
+ APP_PRINT_INFO2("[app_save_wakeup_key_cnt] count = %d, result = %d", save_count, result);
+ return result;
+}
+
+/******************* (C) COPYRIGHT 2020 Realtek Semiconductor Corporation *****END OF FILE****/