diff options
Diffstat (limited to 'src/sample/io_sample/KEYSCAN/Keyscan_Manual')
12 files changed, 2422 insertions, 0 deletions
diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/app_timer.c b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/app_timer.c new file mode 100644 index 0000000..d190f57 --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/app_timer.c @@ -0,0 +1,23 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file app_timer.c +* @brief +* @details +* @author yuan +* @date 2018-12-07 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "app_task.h" +#include "app_timer.h" + + +void sw_timer_init(void) +{ + timer_keyscan_init(); +} + diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/app_timer.h b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/app_timer.h new file mode 100644 index 0000000..43908ea --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/app_timer.h @@ -0,0 +1,43 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file app_timer.h +* @brief +* @details +* @author yuan +* @date 2018-12-07 +* @version v1.0 +********************************************************************************************************* +*/ + +#ifndef __APP_TIMER_H +#define __APP_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include <string.h> + +//#include "os_msg.h" +//#include "os_queue.h" +//#include "os_sched.h" +//#include "os_task.h" +#include "os_timer.h" + +#include "app_msg.h" + +#include "trace.h" + +#include "io_keyscan.h" + +//void timer_keyscan_callback(void *xTimer); +void sw_timer_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/ancs.c b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/ancs.c new file mode 100644 index 0000000..ac3254e --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/ancs.c @@ -0,0 +1,662 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file ancs.c + * @brief This file handles ANCS Client routines. + * @author jane + * @date 2017-06-06 + * @version v1.0 + ************************************************************************************** + * @attention + * <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> + ************************************************************************************** + */ + +/*============================================================================* + * Header Files + *============================================================================*/ +#if F_BT_ANCS_CLIENT_SUPPORT +#include <trace.h> +#include <string.h> +#include <os_msg.h> +#include <os_mem.h> +#include <ancs.h> +#include <ancs_client.h> + +/** @defgroup PERIPH_ANCS Peripheral ANCS + * @brief Apple ANCS service modulization + * @{ + */ +/*============================================================================* + * Types + *============================================================================*/ +typedef struct +{ + uint8_t m_parse_state; + uint8_t app_type; + uint16_t current_len; + void *ancs_queue_handle; + uint8_t *ptr; + T_DS_NOTIFICATION_ATTR notification_attr; +#if F_BT_ANCS_GET_APP_ATTR + T_DS_APP_ATTR app_attr; +#endif +} T_APP_ANCS_LINK; + +/*============================================================================* + * Variables + *============================================================================*/ +/** @defgroup PERIPH_ANCS_Exported_Variables ANCS Exported Variables + * @brief app register ancs client to upperstack, and return ancs client id + * @{ + */ +T_CLIENT_ID ancs_client; /**< ancs client id*/ + +T_APP_ANCS_LINK *ancs_link_table; +uint8_t ancs_link_number; + +/** End of PERIPH_ANCS_Exported_Variables + * @} + */ +extern void *evt_queue_handle; //!< Event queue handle +extern void *io_queue_handle; //!< IO queue handle +/*============================================================================* + * Functions + *============================================================================*/ +/** @defgroup PERIPH_ANCS_Exported_Functions ANCS Exported Functions + * @{ + */ +void ancs_send_msg_to_app(uint8_t conn_id) +{ + T_IO_MSG io_msg; + uint8_t event = EVENT_IO_TO_APP; + io_msg.type = IO_MSG_TYPE_ANCS; + io_msg.subtype = 0; + io_msg.u.param = conn_id; + + if (os_msg_send(io_queue_handle, &io_msg, 0) == false) + { + GAP_PRINT_ERROR0("ancs_send_msg_to_app fail1"); + } + else if (os_msg_send(evt_queue_handle, &event, 0) == false) + { + GAP_PRINT_ERROR0("ancs_send_msg_to_app fail2"); + } +} + +void app_handle_notification_attribute_data(T_APP_ANCS_LINK *p_ancs_link) +{ + if (p_ancs_link->notification_attr.attribute_id != DS_NOTIFICATION_ATTR_ID_NEGATIVE_ACTION_LABEL) + { + p_ancs_link->m_parse_state = DS_PARSE_ATTRIBUTE_ID; + uint8_t *p_value = p_ancs_link->notification_attr.data; + +#if F_BT_ANCS_APP_FILTER + //filter QQ , wechat , short message and incoming call + if (p_ancs_link->notification_attr.attribute_id == DS_NOTIFICATION_ATTR_ID_APP_IDENTIFIER) + { +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO1("parse notify attr: app identifiter %s", TRACE_STRING(p_value)); +#endif + //wechat + if (0 == memcmp(p_value, "com.tencent.xin", 16)) + { + p_ancs_link->app_type = 1; + } + else if (0 == memcmp(p_value, "com.apple.MobileSMS", 20)) + { + p_ancs_link->app_type = 2; + } + else if (0 == memcmp(p_value, "com.apple.mobilephone", 22)) + { + p_ancs_link->app_type = 3; + } + else if (0 == memcmp(p_value, "com.tencent.mqq", 16)) + { + p_ancs_link->app_type = 4; + } + else if (0 == memcmp(p_value, "com.tencent.qq", 15)) + { + p_ancs_link->app_type = 5; + } + } + if (p_ancs_link->notification_attr.attribute_id == DS_NOTIFICATION_ATTR_ID_MESSAGE) + { + if (p_ancs_link->app_type == 2) + { + APP_PRINT_INFO1("MobileSMS: message %s", TRACE_STRING(p_value)); + } + else if (p_ancs_link->app_type == 5) + { + APP_PRINT_INFO1("QQ: message %s", TRACE_STRING(p_value)); + } + } + if (p_ancs_link->notification_attr.attribute_id == DS_NOTIFICATION_ATTR_ID_DATE) + { +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO1("parse notify attr: date %s", TRACE_STRING(p_value)); +#endif + } +#endif + } + else/* All attributes has been parased*/ + { +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO0("parse notify attr: parse done"); +#endif + p_ancs_link->m_parse_state = DS_PARSE_NOT_START; + memset(&p_ancs_link->notification_attr, 0, sizeof(T_DS_NOTIFICATION_ATTR)); + } +} + +void app_parse_notification_attribute(T_APP_ANCS_LINK *p_ancs_link, uint8_t *p_data, uint8_t len) +{ + int i; + + for (i = 0; i < len; i++) + { + switch (p_ancs_link->m_parse_state) + { + case DS_PARSE_GET_NOTIFICATION_COMMAND_ID: + p_ancs_link->notification_attr.command_id = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_UID1; + break; + + case DS_PARSE_UID1: + p_ancs_link->notification_attr.notification_uid[0] = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_UID2; + break; + + case DS_PARSE_UID2: + p_ancs_link->notification_attr.notification_uid[1] = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_UID3; + break; + + case DS_PARSE_UID3: + p_ancs_link->notification_attr.notification_uid[2] = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_UID4; + break; + + case DS_PARSE_UID4: + p_ancs_link->notification_attr.notification_uid[3] = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_ATTRIBUTE_ID; + break; + + case DS_PARSE_ATTRIBUTE_ID: + p_ancs_link->notification_attr.attribute_id = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_ATTRIBUTE_LEN1; + break; + + case DS_PARSE_ATTRIBUTE_LEN1: + p_ancs_link->notification_attr.attribute_len = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_ATTRIBUTE_LEN2; + break; + + case DS_PARSE_ATTRIBUTE_LEN2: + p_ancs_link->notification_attr.attribute_len |= (p_data[i] << 8); + p_ancs_link->m_parse_state = DS_PARSE_ATTRIBUTE_READY; + p_ancs_link->ptr = p_ancs_link->notification_attr.data; + p_ancs_link->current_len = 0; +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO2("parse notify attr: attribute_id %d, attribute_len %d", + p_ancs_link->notification_attr.attribute_id, + p_ancs_link->notification_attr.attribute_len + ); +#endif + if (p_ancs_link->notification_attr.attribute_len == 0) + { + p_ancs_link->m_parse_state = DS_PARSE_ATTRIBUTE_ID; + } + if (p_ancs_link->notification_attr.attribute_len > ANCS_MAX_ATTR_LEN) + { +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_ERROR2("parse notify attr: error, attribute_len %d > max length %d", + p_ancs_link->notification_attr.attribute_len, + ANCS_MAX_ATTR_LEN + ); +#endif + p_ancs_link->m_parse_state = DS_PARSE_NOT_START; + memset(&p_ancs_link->notification_attr, 0, sizeof(T_DS_NOTIFICATION_ATTR)); + } + break; + + case DS_PARSE_ATTRIBUTE_READY: + *p_ancs_link->ptr++ = p_data[i]; + p_ancs_link->current_len++; + + if (p_ancs_link->current_len == p_ancs_link->notification_attr.attribute_len) + { + /*An attribute is always a string whose length in bytes is provided in the tuple but that is not NULL-terminated.*/ + *p_ancs_link->ptr++ = 0; +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO1("parse notify attr: data %b", + TRACE_BINARY(p_ancs_link->notification_attr.attribute_len, + p_ancs_link->notification_attr.data)); +#endif + app_handle_notification_attribute_data(p_ancs_link); + } + break; + } + } +} + +#if F_BT_ANCS_GET_APP_ATTR +void app_parse_app_attribute(T_APP_ANCS_LINK *p_ancs_link, uint8_t *p_data, uint8_t len) +{ + int i; + for (i = 0; i < len; i++) + { + switch (p_ancs_link->m_parse_state) + { + case DS_PARSE_GET_APP_COMMAND_ID: + p_ancs_link->app_attr.command_id = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_APP_IDENTIFIER_START; + break; + + case DS_PARSE_APP_IDENTIFIER_START: + if (p_data[i] == 0x00) + { + p_ancs_link->m_parse_state = DS_PARSE_APP_IDENTIFIER_END; + + if (i + 1 == len) + { + p_ancs_link->m_parse_state = DS_PARSE_NOT_START; + } + else + { + p_ancs_link->m_parse_state = DS_PARSE_APP_ATTRIBUTE_ID; + } + + } + break; + + case DS_PARSE_APP_ATTRIBUTE_ID: + p_ancs_link->app_attr.attribute_id = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_APP_ATTRIBUTE_LEN1; + break; + + case DS_PARSE_APP_ATTRIBUTE_LEN1: + p_ancs_link->app_attr.attribute_len = p_data[i]; + p_ancs_link->m_parse_state = DS_PARSE_APP_ATTRIBUTE_LEN2; + break; + + case DS_PARSE_APP_ATTRIBUTE_LEN2: + p_ancs_link->app_attr.attribute_len |= (p_data[i] << 8); + p_ancs_link->m_parse_state = DS_PARSE_APP_ATTRIBUTE_READY; + p_ancs_link->ptr = p_ancs_link->app_attr.data; + p_ancs_link->current_len = 0; +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO2("parse app attr: attribute_id %d, attribute_len %d", + p_ancs_link->app_attr.attribute_id, + p_ancs_link->app_attr.attribute_len + ); +#endif + if (p_ancs_link->app_attr.attribute_len == 0) + { + p_ancs_link->m_parse_state = DS_PARSE_APP_ATTRIBUTE_ID; + + } + if (p_ancs_link->app_attr.attribute_len > ANCS_MAX_ATTR_LEN) + { +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_ERROR2("parse app attr: error, attribute_len %d > max length %d", + p_ancs_link->app_attr.attribute_len, + ANCS_MAX_ATTR_LEN + ); +#endif + p_ancs_link->m_parse_state = DS_PARSE_NOT_START; + } + break; + + case DS_PARSE_APP_ATTRIBUTE_READY: + *p_ancs_link->ptr++ = p_data[i]; + p_ancs_link->current_len++; + + if (p_ancs_link->current_len == p_ancs_link->app_attr.attribute_len) + { + *p_ancs_link->ptr++ = 0; +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO4("parse app attr: command_id 0x%x, attribute_id 0x%x, attribute_len %d, data %s", + p_ancs_link->app_attr.command_id, + p_ancs_link->app_attr.attribute_id, + p_ancs_link->app_attr.attribute_len, + TRACE_STRING(p_ancs_link->app_attr.data)); +#endif + p_ancs_link->m_parse_state = DS_PARSE_NOT_START; + + } + break; + } + } +} +#endif + +/** + * @brief Parse ancs data source notification + * @param[in] conn_id connection identifier + * @param[in] *p_data point to data buffer + * @param[in] len data length + * @return void + */ +void app_parse_data_soucre_notifications(uint8_t conn_id, uint8_t *p_data, uint8_t len) +{ + APP_PRINT_INFO2("ANCS_FROM_DATA_SOURCE: conn_id %d, len =%d", conn_id, len); +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO1("data = %b", TRACE_BINARY(len, p_data)); +#endif + T_APP_ANCS_LINK *p_ancs_link = &ancs_link_table[conn_id]; + +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO1("m_parse_state %d", p_ancs_link->m_parse_state); +#endif + if (p_ancs_link->m_parse_state == DS_PARSE_NOT_START) + { + if (len >= 1 && p_data[0] == CP_CMD_ID_GET_NOTIFICATION_ATTR) + { + p_ancs_link->m_parse_state = DS_PARSE_GET_NOTIFICATION_COMMAND_ID; + } +#if F_BT_ANCS_GET_APP_ATTR + else if (len >= 1 && p_data[0] == CP_CMD_ID_GET_APP_ATTR) + { + p_ancs_link->m_parse_state = DS_PARSE_GET_APP_COMMAND_ID; + } +#endif + } + + if (p_ancs_link->m_parse_state < DS_PARSE_GET_APP_COMMAND_ID) + { + app_parse_notification_attribute(p_ancs_link, p_data, len); + } +#if F_BT_ANCS_GET_APP_ATTR + else + { + app_parse_app_attribute(p_ancs_link, p_data, len); + } +#endif +} + +void app_parse_notification_source_data(uint8_t conn_id, uint8_t *p_data, uint8_t len) +{ + if (8 == len) + { + T_NS_DATA ns_data; + + memcpy(&ns_data, p_data, len); +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO5("app_parse_notification_source_data: event_id %d, event_flags 0x%02x, category_id %d, category_count %d, notification_uid 0x%08x", + ns_data.event_id, + ns_data.event_flags, + ns_data.category_id, + ns_data.category_count, + ns_data.notification_uid + ); + APP_PRINT_INFO5("event_flags: slient %d, important %d, pre existing %d, positive action %d, negative action %d ", + ns_data.event_flags & NS_EVENT_FLAG_SILENT, + ns_data.event_flags & NS_EVENT_FLAG_IMPORTANT, + ns_data.event_flags & NS_EVENT_FLAG_PRE_EXISTING, + ns_data.event_flags & NS_EVENT_FLAG_POSITIVE_ACTION, + ns_data.event_flags & NS_EVENT_FLAG_NEGATIVE_ACTION + ); +#endif + //you can filter by category_id here, for demo purpose, we didn't filter any CategoryID here. +#if F_BT_ANCS_APP_FILTER + //filter social and other category & phone category & email category + if (ns_data.category_id == NS_CATEGORY_ID_SOCIAL || + ns_data.category_id == NS_CATEGORY_ID_OTHER || + ns_data.category_id == NS_CATEGORY_ID_INCOMING_CALL || + ns_data.category_id == NS_CATEGORY_ID_EMAIL) + { +#endif + if (ns_data.event_id != NS_EVENT_ID_NOTIFICATION_REMOVED) + { + uint32_t msg_num; + T_ANCS_MSG ancs_msg; + uint8_t attr_id_list[14]; + uint8_t cur_index = 0; + + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_APP_IDENTIFIER; + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_TITLE; + attr_id_list[cur_index++] = LO_WORD(ANCS_MAX_ATTR_LEN); + attr_id_list[cur_index++] = HI_WORD(ANCS_MAX_ATTR_LEN); + + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_SUB_TITLE; + attr_id_list[cur_index++] = LO_WORD(ANCS_MAX_ATTR_LEN); + attr_id_list[cur_index++] = HI_WORD(ANCS_MAX_ATTR_LEN); + + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_MESSAGE; + attr_id_list[cur_index++] = LO_WORD(ANCS_MAX_ATTR_LEN); + attr_id_list[cur_index++] = HI_WORD(ANCS_MAX_ATTR_LEN); + + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_MESSAGE_SIZE; + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_DATE; + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_POSITIVE_ACTION_LABEL; + attr_id_list[cur_index++] = DS_NOTIFICATION_ATTR_ID_NEGATIVE_ACTION_LABEL; + + os_msg_queue_peek(ancs_link_table[conn_id].ancs_queue_handle, &msg_num); +#if F_BT_ANCS_CLIENT_DEBUG + APP_PRINT_INFO1("app_parse_notification_source_data: msg_num %d", msg_num); +#endif + if (msg_num == 0) + { + if (ancs_get_notification_attr(conn_id, ns_data.notification_uid, attr_id_list, + cur_index) == true) + { + return; + } + } + + ancs_msg.type = ANCS_MSG_TYPE_GET_NOTIFI_ATTR; + ancs_msg.data.notifi_attr.conn_id = conn_id; + ancs_msg.data.notifi_attr.notification_uid = ns_data.notification_uid; + ancs_msg.data.notifi_attr.attribute_ids_len = cur_index; + memcpy(ancs_msg.data.notifi_attr.attribute_ids, attr_id_list, cur_index); + if (os_msg_send(ancs_link_table[conn_id].ancs_queue_handle, &ancs_msg, 0) == false) + { + APP_PRINT_ERROR0("app_parse_notification_source_data: discard, msg queue is full"); + } + } +#if F_BT_ANCS_APP_FILTER + } +#endif + } +} + +/** + * @brief Ancs client callback handle message from upperstack + * @param[in] client_id client identifier + * @param[in] conn_id connection identifier + * @param[in] *p_data point to data buffer + * @return @ref T_APP_RESULT + */ +T_APP_RESULT ancs_client_cb(T_CLIENT_ID client_id, uint8_t conn_id, void *p_data) +{ + T_APP_RESULT result = APP_RESULT_SUCCESS; + T_ANCS_CB_DATA *p_cb_data = (T_ANCS_CB_DATA *)p_data; + + switch (p_cb_data->cb_type) + { + case ANCS_CLIENT_CB_TYPE_DISC_STATE: + switch (p_cb_data->cb_content.disc_state) + { + case DISC_ANCS_DONE: + APP_PRINT_INFO0("ANCS BLE Client CB: discover procedure done."); + ancs_set_data_source_notify(conn_id, true); + break; + case DISC_ANCS_FAILED: + APP_PRINT_ERROR0("ANCS BLE Client CB: discover request failed."); + break; + default: + break; + } + break; + + case ANCS_CLIENT_CB_TYPE_NOTIF_IND_RESULT: + switch (p_cb_data->cb_content.notify_data.type) + { + case ANCS_FROM_DATA_SOURCE:; + app_parse_data_soucre_notifications(conn_id, p_cb_data->cb_content.notify_data.p_value, + p_cb_data->cb_content.notify_data.value_size); + break; + case ANCS_FROM_NOTIFICATION_SOURCE: + APP_PRINT_INFO2("ANCS_FROM_NOTIFICATION_SOURCE: conn_id %d, length %d", + conn_id, p_cb_data->cb_content.notify_data.value_size); + app_parse_notification_source_data(conn_id, p_cb_data->cb_content.notify_data.p_value, + p_cb_data->cb_content.notify_data.value_size); + break; + default: + break; + } + break; + + case ANCS_CLIENT_CB_TYPE_WRITE_RESULT: + { + if (p_cb_data->cb_content.write_result.cause != ATT_SUCCESS) + { + APP_PRINT_ERROR1("ANCS_CLIENT_CB_TYPE_WRITE_RESULT: Failed, cause 0x%x", + p_cb_data->cb_content.write_result.cause); + } + switch (p_cb_data->cb_content.write_result.type) + { + case ANCS_WRITE_NOTIFICATION_SOURCE_NOTIFY_ENABLE: + APP_PRINT_INFO0("ANCS_WRITE_NOTIFICATION_SOURCE_NOTIFY_ENABLE"); + break; + + case ANCS_WRITE_NOTIFICATION_SOURCE_NOTIFY_DISABLE: + APP_PRINT_INFO0("ANCS_WRITE_NOTIFICATION_SOURCE_NOTIFY_DISABLE"); + break; + + case ANCS_WRITE_DATA_SOURCE_NOTIFY_ENABLE: + APP_PRINT_INFO0("ANCS_WRITE_DATA_SOURCE_NOTIFY_ENABLE"); + ancs_set_notification_source_notify(conn_id, true); + break; + case ANCS_WRITE_DATA_SOURCE_NOTIFY_DISABLE: + APP_PRINT_INFO0("ANCS_WRITE_DATA_SOURCE_NOTIFY_DISABLE"); + break; + + case ANCS_WRITE_CONTROL_POINT: + APP_PRINT_INFO0("ANCS_WRITE_CONTROL_POINT"); +#if F_BT_ANCS_CLIENT_DEBUG + if (p_cb_data->cb_content.write_result.cause == 0x4A0) + { + APP_PRINT_ERROR0("The commandID was not recognized by the NP."); + } + else if (p_cb_data->cb_content.write_result.cause == 0x4A1) + { + APP_PRINT_ERROR0("The command was improperly formatted."); + } + else if (p_cb_data->cb_content.write_result.cause == 0x4A2) + { + APP_PRINT_ERROR0("One of the parameters (for example, the NotificationUID) does not refer to an existing object on the NP."); + } + else if (p_cb_data->cb_content.write_result.cause == 0x4A3) + { + APP_PRINT_ERROR0("The action was not performed."); + } +#endif + ancs_send_msg_to_app(conn_id); + break; + + default: + break; + } + } + break; + + case ANCS_CLIENT_CB_TYPE_DISCONNECT_INFO: + { + T_ANCS_MSG ancs_msg; + void *ancs_queue_handle = ancs_link_table[conn_id].ancs_queue_handle; + APP_PRINT_INFO1("ANCS_CLIENT_CB_TYPE_DISCONNECT_INFO: conn_id = 0x%x", conn_id); + memset(&ancs_link_table[conn_id], 0, sizeof(T_APP_ANCS_LINK)); + ancs_link_table[conn_id].ancs_queue_handle = ancs_queue_handle; + /*release msg queue*/ + while (os_msg_recv(ancs_link_table[conn_id].ancs_queue_handle, &ancs_msg, 0)); + } + break; + + default: + break; + } + return result; +} + +void ancs_handle_msg(T_IO_MSG *p_io_msg) +{ + uint8_t conn_id = p_io_msg->u.param; + T_ANCS_MSG ancs_msg; + if (os_msg_recv(ancs_link_table[conn_id].ancs_queue_handle, &ancs_msg, 0) == false) + { + APP_PRINT_INFO1("ancs_handle_msg: conn_id 0x%x os_msg_recv failed", conn_id); + return; + } + if (ancs_msg.type == ANCS_MSG_TYPE_GET_NOTIFI_ATTR) + { + APP_PRINT_INFO1("ANCS_MSG_TYPE_GET_NOTIFI_ATTR: notification_uid 0x%x", + ancs_msg.data.notifi_attr.notification_uid); + if (ancs_get_notification_attr(ancs_msg.data.notifi_attr.conn_id, + ancs_msg.data.notifi_attr.notification_uid, + ancs_msg.data.notifi_attr.attribute_ids, ancs_msg.data.notifi_attr.attribute_ids_len + ) == false) + { + APP_PRINT_ERROR0("ANCS_MSG_TYPE_GET_NOTIFI_ATTR: Failed"); + } + + } + else if (ancs_msg.type == ANCS_MSG_TYPE_PERFORM_NOTIFI_ACTION) + { + APP_PRINT_INFO1("ANCS_MSG_TYPE_PERFORM_NOTIFI_ACTION: notification_uid 0x%x", + ancs_msg.data.perform_action.notification_uid); + if (ancs_perform_notification_action(ancs_msg.data.perform_action.conn_id, + ancs_msg.data.perform_action.notification_uid, + ancs_msg.data.perform_action.action_id) == false) + { + APP_PRINT_ERROR0("ANCS_MSG_TYPE_PERFORM_NOTIFI_ACTION: Failed"); + } + + } +#if F_BT_ANCS_GET_APP_ATTR + else if (ancs_msg.type == ANCS_MSG_TYPE_GET_APP_ATTR) + { + APP_PRINT_INFO1("ANCS_MSG_TYPE_GET_APP_ATTR: app_identifier %s", + TRACE_STRING(ancs_msg.data.app_attr.app_identifier)); + if (ancs_get_app_attr(ancs_msg.data.app_attr.conn_id, + ancs_msg.data.app_attr.app_identifier, + ancs_msg.data.app_attr.attribute_ids, + ancs_msg.data.app_attr.attribute_ids_len) == false) + { + APP_PRINT_ERROR0("ANCS_MSG_TYPE_GET_APP_ATTR: Failed"); + } + + } +#endif +} + +/** + * @brief App register ancs client to upperstack. + * This ancs_client_cb callback function will handle message. + * @param[in] link_num Initialize link number + * @return void + */ +void ancs_init(uint8_t link_num) +{ + uint8_t i; + ancs_link_number = link_num; + ancs_link_table = os_mem_zalloc(RAM_TYPE_DATA_ON, ancs_link_number * sizeof(T_APP_ANCS_LINK)); + if (ancs_link_table == NULL) + { + APP_PRINT_ERROR0("ancs_init: allocate buffer failed"); + } + for (i = 0; i < ancs_link_number; i++) + { + if (os_msg_queue_create(&(ancs_link_table[i].ancs_queue_handle), ANCS_MSG_QUEUE_NUM, + sizeof(T_ANCS_MSG)) == false) + { + APP_PRINT_ERROR2("ancs_init: link_num %d, i 0x%x create queue failed", link_num, i); + } + } + ancs_client = ancs_add_client(ancs_client_cb, link_num); +} +/** @} */ /* End of group PERIPH_ANCS_Exported_Functions */ +/** @} */ /* End of group PERIPH_ANCS */ +#endif diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/ancs.h b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/ancs.h new file mode 100644 index 0000000..68ec35b --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/ancs.h @@ -0,0 +1,259 @@ +/** +********************************************************************************************************* +* Copyright(c) 2015, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ancs.h +* @brief ancs +* @details ancs +* @author ranhui +* @date 2015-03-27 +* @version v0.1 +* ********************************************************************************************************* +*/ + +#ifndef _ANCS_H__ +#define _ANCS_H__ + +#ifdef __cplusplus +extern "C" { +#endif +/*============================================================================* + * Header Files + *============================================================================*/ +#include <gap_le.h> + +/** @addtogroup PERIPH_ANCS + * @{ + */ +/*============================================================================* + * Macros + *============================================================================*/ +/** @defgroup PERIPH_ANCS_Exported_Macros ANCS Exported Macros + * @{ + */ +#define ANCS_MAX_ATTR_LEN 256 //!< Max ancs attribute length + +#if F_BT_ANCS_GET_APP_ATTR +#define ANCS_APP_IDENTIFIER_MAX_LEN 30 //!< Max app IDENTIFIER length +#endif + +#define ANCS_MSG_QUEUE_NUM 5 //!< ANCS message queue size + + +/** @brief ANCS event flag */ +#define NS_EVENT_FLAG_SILENT (1 << 0) +#define NS_EVENT_FLAG_IMPORTANT (1 << 1) +#define NS_EVENT_FLAG_PRE_EXISTING (1 << 2) +#define NS_EVENT_FLAG_POSITIVE_ACTION (1 << 3) //!<A positive action exists and is associated with this iOS notification +#define NS_EVENT_FLAG_NEGATIVE_ACTION (1 << 4) //!<A negative action exists and is associated with this iOS notification. + +/** End of PERIPH_ANCS_Exported_Macros + * @} + */ + +/*============================================================================* + * Types + *============================================================================*/ +/** @defgroup PERIPH_ANCS_Exported_Types ANCS Exported Types + * @{ + */ +/** @brief ANCS event id for the peer device notification */ +typedef enum +{ + NS_EVENT_ID_NOTIFICATION_ADD = 0, /**< The arrival of a new iOS notification on the NP */ + NS_EVENT_ID_NOTIFICATION_MODIFIED = 1, /**< The modification of an iOS notification on the NP */ + NS_EVENT_ID_NOTIFICATION_REMOVED = 2, /**< The removal of an iOS notification on the NP */ + NS_EVENT_ID_NOTIFICATION_RESERVED = 0xff +} T_NS_EVENT_ID; + +/** @brief ANCS category id */ +typedef enum +{ + NS_CATEGORY_ID_OTHER = 0, + NS_CATEGORY_ID_INCOMING_CALL = 1, + NS_CATEGORY_ID_MISSED_CALL = 2, + NS_CATEGORY_ID_VOICE_MAIL = 3, + NS_CATEGORY_ID_SOCIAL = 4, + NS_CATEGORY_ID_SCHEDULE = 5, + NS_CATEGORY_ID_EMAIL = 6, + NS_CATEGORY_ID_NEWS = 7, + NS_CATEGORY_ID_HEALTH_AND_FITNESS = 8, + NS_CATEGORY_ID_BUSINESS_ADN_FINANCE = 9, + NS_CATEGORY_ID_LOCATION = 10, + NS_CATEGORY_ID_ENTERTAINMENT = 11, + NS_CATEGORY_ID_RESERVED = 255 +} T_NS_CATEGORY_ID; + +/** @brief ANCS notification attribute id */ +typedef enum +{ + DS_NOTIFICATION_ATTR_ID_APP_IDENTIFIER = 0, /**< Format: UTF-8 strings */ + DS_NOTIFICATION_ATTR_ID_TITLE = 1, /**<Format: UTF-8 strings. Needs to be followed by a 2-bytes max length parameter */ + DS_NOTIFICATION_ATTR_ID_SUB_TITLE = 2, /**<Format: UTF-8 strings. Needs to be followed by a 2-bytes max length parameter */ + DS_NOTIFICATION_ATTR_ID_MESSAGE = 3, /**<Format: UTF-8 strings. Needs to be followed by a 2-bytes max length parameter */ + DS_NOTIFICATION_ATTR_ID_MESSAGE_SIZE = 4, /**<The format of the DS_NOTIFICATION_ATTR_ID_MESSAGE_SIZE constant is a string + that represents the integral value of the message size. */ + DS_NOTIFICATION_ATTR_ID_DATE = 5, /**<The format of the DS_NOTIFICATION_ATTR_ID_DATE constant is a string + that uses the Unicode Technical Standard (UTS) #35 date format pattern yyyyMMdd'T'HHmmSS. */ + DS_NOTIFICATION_ATTR_ID_POSITIVE_ACTION_LABEL = 6, /**<Format: UTF-8 strings. The label used to describe + the positive action that can be performed on the iOS notification. */ + DS_NOTIFICATION_ATTR_ID_NEGATIVE_ACTION_LABEL = 7, /**<Format: UTF-8 strings. The label used to describe + the negative action that can be performed on the iOS notification. */ + DS_NOTIFICATION_ATTR_ID_RESERVED = 255 +} T_DS_NOTIFICATION_ATTR_ID; + +/** @brief App parse ANCS notification attribute state */ +typedef enum +{ + DS_PARSE_NOT_START = 0x00, + DS_PARSE_GET_NOTIFICATION_COMMAND_ID = 0x01, + DS_PARSE_UID1, + DS_PARSE_UID2, + DS_PARSE_UID3, + DS_PARSE_UID4, + DS_PARSE_ATTRIBUTE_ID, + DS_PARSE_ATTRIBUTE_LEN1, + DS_PARSE_ATTRIBUTE_LEN2, + DS_PARSE_ATTRIBUTE_READY +} T_DS_NOTIFICATION_ATTR_PARSE_STATE; + +/** @brief Smart Phone App attribute id. */ +typedef enum +{ + DS_APP_ATTR_ID_DISPLAY_NAME = 0, + DS_APP_ATTR_ID_RESERVED = 255 +} T_DS_APP_ATTR_ID; + +/** @brief App parse ANCS attribute state */ +typedef enum +{ + DS_PARSE_GET_APP_COMMAND_ID = 0x10, + DS_PARSE_APP_IDENTIFIER_START, + DS_PARSE_APP_IDENTIFIER_END, + DS_PARSE_APP_ATTRIBUTE_ID, + DS_PARSE_APP_ATTRIBUTE_LEN1, + DS_PARSE_APP_ATTRIBUTE_LEN2, + DS_PARSE_APP_ATTRIBUTE_READY +} T_DS_APP_ATTR_PARSE_STATE; + +/** @brief ANCS action id state */ +typedef enum +{ + CP_ACTION_ID_POSITIVE = 0, + CP_ACTION_ID_NEGATIVE = 1, + CP_ACTION_ID_RESERVED = 255 +} T_CP_ACTION_ID_VALUES; + +/** @brief Define notification source data for record ANCS notification parameters */ +typedef struct +{ + uint8_t event_id; /**< This field informs the accessory whether the given iOS notification + was added, modified, or removed. The enumerated values for this field are defined in @ref T_NS_EVENT_ID*/ + uint8_t event_flags; /**< A bitmask whose set bits inform an NC of specificities with the iOS notification. */ + uint8_t category_id; /**< A numerical value providing a category in which the iOS notification + can be classified. The enumerated values for this field are defined in @ref T_NS_CATEGORY_ID*/ + uint8_t category_count; /**< The current number of active iOS notifications in the given category. */ + uint32_t notification_uid; /**< A 32-bit numerical value that is the unique identifier (UID) for the iOS notification.*/ +} T_NS_DATA, *P_NS_DATA; + +/** @brief Define notification attribute details data */ +/** App can acquire details information by attribute id */ +typedef struct +{ + uint8_t command_id; + uint8_t notification_uid[4]; + uint8_t attribute_id; + uint16_t attribute_len; + uint8_t data[ANCS_MAX_ATTR_LEN]; +} T_DS_NOTIFICATION_ATTR; + +/** @brief Local app record notification attribute information */ +typedef struct +{ + uint8_t command_id; + uint8_t attribute_id; + uint16_t attribute_len; + uint8_t data[ANCS_MAX_ATTR_LEN]; +} T_DS_APP_ATTR; + +/** @brief ANCS Message Type */ +typedef enum +{ + ANCS_MSG_TYPE_GET_NOTIFI_ATTR, + ANCS_MSG_TYPE_PERFORM_NOTIFI_ACTION, + ANCS_MSG_TYPE_GET_APP_ATTR, +} T_ANCS_MSG_TYPE; + +/** @brief Message data of ANCS_MSG_TYPE_GET_NOTIFI_ATTR */ +typedef struct +{ + uint8_t conn_id; + uint32_t notification_uid; + uint8_t attribute_ids[14]; + uint8_t attribute_ids_len; +} T_ANCS_GET_NOTIFI_ATTR; + +/** @brief Message data of ANCS_MSG_TYPE_PERFORM_NOTIFI_ACTION */ +typedef struct +{ + uint8_t conn_id; + uint32_t notification_uid; + uint8_t action_id; +} T_ANCS_PERFORM_NOTIFI_ACTION; + +#if F_BT_ANCS_GET_APP_ATTR +/** @brief Message data of ANCS_MSG_TYPE_GET_APP_ATTR */ +typedef struct +{ + uint8_t conn_id; + char app_identifier[ANCS_APP_IDENTIFIER_MAX_LEN]; + uint8_t attribute_ids[1]; + uint8_t attribute_ids_len; +} T_ANCS_GET_APP_ATTR; +#endif + +/** @brief ANCS Message Data */ +typedef struct +{ + T_ANCS_MSG_TYPE type; + union + { + T_ANCS_GET_NOTIFI_ATTR notifi_attr; + T_ANCS_PERFORM_NOTIFI_ACTION perform_action; +#if F_BT_ANCS_GET_APP_ATTR + T_ANCS_GET_APP_ATTR app_attr; +#endif + } data; +} T_ANCS_MSG; +/** End of PERIPH_ANCS_Exported_Types + * @} + */ + +/*============================================================================* + * Functions + *============================================================================*/ +/** @defgroup PERIPH_ANCS_Exported_Functions ANCS Exported Functions + * @{ + */ +/** + * @brief App register ancs client to upperstack. + * This ancs_client_cb callback function will handle message. + * @param[in] link_num Initialize link number + * @return void + */ +void ancs_init(uint8_t link_num); + +/** + * @brief All the ancs messages are pre-handled in this function + * @param[in] io_msg IO message data + * @return void + */ +void ancs_handle_msg(T_IO_MSG *p_io_msg); +/** @} */ /* End of group PERIPH_ANCS_Exported_Functions */ +/** @} */ /* End of group PERIPH_ANCS */ +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app.c b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app.c new file mode 100644 index 0000000..141d8ca --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app.c @@ -0,0 +1,608 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file peripheral_app.c + * @brief This file handles BLE peripheral application routines. + * @author jane + * @date 2017-06-06 + * @version v1.0 + ************************************************************************************** + * @attention + * <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> + ************************************************************************************** + */ + +/*============================================================================* + * Header Files + *============================================================================*/ +#include <string.h> + +#include <gap.h> +#include <gap_adv.h> +#include <gap_bond_le.h> +#include <gap_conn_le.h> +#include <gap_msg.h> +#if F_BT_ANCS_CLIENT_SUPPORT +#include <ancs_client.h> +#include "ancs.h" +#endif +#include <bas.h> +#include <simple_ble_service.h> + +#include "trace.h" + +#include "app.h" +#include "io_keyscan.h" + +/** @defgroup PERIPH_APP Peripheral Application + * @brief This file handles BLE peripheral application routines. + * @{ + */ + +/*============================================================================* + * Variables + *============================================================================*/ +/** @addtogroup PERIPH_SEVER_CALLBACK Profile Server Callback Event Handler + * @brief Handle profile server callback event + * @{ + */ +T_SERVER_ID simp_srv_id; /**< Simple ble service id*/ +T_SERVER_ID bas_srv_id; /**< Battery service id */ +/** @} */ /* End of group PERIPH_SEVER_CALLBACK */ + +/** @defgroup PERIPH_GAP_MSG GAP Message Handler + * @brief Handle GAP Message + * @{ + */ +T_GAP_DEV_STATE gap_dev_state = {0, 0, 0, 0}; /**< GAP device state */ +T_GAP_CONN_STATE gap_conn_state = GAP_CONN_STATE_DISCONNECTED; /**< GAP connection state */ + +/*============================================================================* + * Functions + *============================================================================*/ +void app_handle_gap_msg(T_IO_MSG *p_gap_msg); + +/** + * @brief All the application messages are pre-handled in this function + * @note All the IO MSGs are sent to this function, then the event handling + * function shall be called according to the MSG type. + * @param[in] io_msg IO message data + * @return void + */ +void app_handle_io_msg(T_IO_MSG io_msg) +{ + uint16_t msg_type = io_msg.type; + + switch (msg_type) + { + case IO_MSG_TYPE_BT_STATUS: + { + app_handle_gap_msg(&io_msg); + } + break; +#if F_BT_ANCS_CLIENT_SUPPORT + case IO_MSG_TYPE_ANCS: + { + ancs_handle_msg(&io_msg); + } + break; +#endif + case IO_MSG_TYPE_KEYSCAN: + { +// APP_PRINT_INFO0("[app] app_handle_io_msg: Keyscan msg."); + io_handle_keyscan_msg(&io_msg); + //Add user code here! + } + break; + default: + break; + } +} + +/** + * @brief Handle msg GAP_MSG_LE_DEV_STATE_CHANGE + * @note All the gap device state events are pre-handled in this function. + * Then the event handling function shall be called according to the new_state + * @param[in] new_state New gap device state + * @param[in] cause GAP device state change cause + * @return void + */ +void app_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause) +{ + APP_PRINT_INFO3("app_handle_dev_state_evt: init state %d, adv state %d, cause 0x%x", + new_state.gap_init_state, new_state.gap_adv_state, cause); + if (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"); + /*stack ready*/ +// le_adv_start(); + } + } + + if (gap_dev_state.gap_adv_state != new_state.gap_adv_state) + { + if (new_state.gap_adv_state == GAP_ADV_STATE_IDLE) + { + if (new_state.gap_adv_sub_state == GAP_ADV_TO_IDLE_CAUSE_CONN) + { + APP_PRINT_INFO0("GAP adv stoped: because connection created"); + } + else + { + APP_PRINT_INFO0("GAP adv stoped"); + } + } + else if (new_state.gap_adv_state == GAP_ADV_STATE_ADVERTISING) + { + APP_PRINT_INFO0("GAP adv start"); + } + } + + gap_dev_state = new_state; +} + +/** + * @brief Handle msg GAP_MSG_LE_CONN_STATE_CHANGE + * @note All the gap conn state events are pre-handled in this function. + * Then the event handling function shall be called according to the new_state + * @param[in] conn_id Connection ID + * @param[in] new_state New gap connection state + * @param[in] disc_cause Use this cause when new_state is GAP_CONN_STATE_DISCONNECTED + * @return void + */ +void app_handle_conn_state_evt(uint8_t conn_id, T_GAP_CONN_STATE new_state, uint16_t disc_cause) +{ + APP_PRINT_INFO4("app_handle_conn_state_evt: conn_id %d old_state %d new_state %d, disc_cause 0x%x", + conn_id, gap_conn_state, new_state, disc_cause); + switch (new_state) + { + case GAP_CONN_STATE_DISCONNECTED: + { + if ((disc_cause != (HCI_ERR | HCI_ERR_REMOTE_USER_TERMINATE)) + && (disc_cause != (HCI_ERR | HCI_ERR_LOCAL_HOST_TERMINATE))) + { + APP_PRINT_ERROR1("app_handle_conn_state_evt: connection lost cause 0x%x", disc_cause); + } + + le_adv_start(); + } + break; + + case GAP_CONN_STATE_CONNECTED: + { + uint16_t conn_interval; + uint16_t conn_latency; + uint16_t conn_supervision_timeout; + uint8_t remote_bd[6]; + T_GAP_REMOTE_ADDR_TYPE 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; + } + gap_conn_state = new_state; +} + +/** + * @brief Handle msg GAP_MSG_LE_AUTHEN_STATE_CHANGE + * @note All the gap authentication state events are pre-handled in this function. + * Then the event handling function shall be called according to the new_state + * @param[in] conn_id Connection ID + * @param[in] new_state New authentication state + * @param[in] cause Use this cause when new_state is GAP_AUTHEN_STATE_COMPLETE + * @return void + */ +void app_handle_authen_state_evt(uint8_t conn_id, uint8_t new_state, uint16_t cause) +{ + APP_PRINT_INFO2("app_handle_authen_state_evt:conn_id %d, cause 0x%x", conn_id, cause); + + switch (new_state) + { + case GAP_AUTHEN_STATE_STARTED: + { + APP_PRINT_INFO0("app_handle_authen_state_evt: GAP_AUTHEN_STATE_STARTED"); + } + break; + + case GAP_AUTHEN_STATE_COMPLETE: + { + if (cause == GAP_SUCCESS) + { +#if F_BT_ANCS_CLIENT_SUPPORT + ancs_start_discovery(conn_id); +#endif + APP_PRINT_INFO0("app_handle_authen_state_evt: GAP_AUTHEN_STATE_COMPLETE pair success"); + + } + else + { + APP_PRINT_INFO0("app_handle_authen_state_evt: GAP_AUTHEN_STATE_COMPLETE pair failed"); + } + } + break; + + default: + { + APP_PRINT_ERROR1("app_handle_authen_state_evt: unknown newstate %d", new_state); + } + break; + } +} + +/** + * @brief Handle msg GAP_MSG_LE_CONN_MTU_INFO + * @note This msg is used to inform APP that exchange mtu procedure is completed. + * @param[in] conn_id Connection ID + * @param[in] mtu_size New mtu size + * @return void + */ +void app_handle_conn_mtu_info_evt(uint8_t conn_id, uint16_t mtu_size) +{ + APP_PRINT_INFO2("app_handle_conn_mtu_info_evt: conn_id %d, mtu_size %d", conn_id, mtu_size); +} + +/** + * @brief Handle msg GAP_MSG_LE_CONN_PARAM_UPDATE + * @note All the connection parameter update change events are pre-handled in this function. + * @param[in] conn_id Connection ID + * @param[in] status New update state + * @param[in] cause Use this cause when status is GAP_CONN_PARAM_UPDATE_STATUS_FAIL + * @return void + */ +void app_handle_conn_param_update_evt(uint8_t conn_id, uint8_t status, uint16_t cause) +{ + switch (status) + { + case GAP_CONN_PARAM_UPDATE_STATUS_SUCCESS: + { + uint16_t conn_interval; + uint16_t conn_slave_latency; + uint16_t conn_supervision_timeout; + + le_get_conn_param(GAP_PARAM_CONN_INTERVAL, &conn_interval, conn_id); + le_get_conn_param(GAP_PARAM_CONN_LATENCY, &conn_slave_latency, conn_id); + le_get_conn_param(GAP_PARAM_CONN_TIMEOUT, &conn_supervision_timeout, conn_id); + APP_PRINT_INFO3("app_handle_conn_param_update_evt update success:conn_interval 0x%x, conn_slave_latency 0x%x, conn_supervision_timeout 0x%x", + conn_interval, conn_slave_latency, conn_supervision_timeout); + } + break; + + case GAP_CONN_PARAM_UPDATE_STATUS_FAIL: + { + APP_PRINT_ERROR1("app_handle_conn_param_update_evt update failed: cause 0x%x", cause); + } + break; + + case GAP_CONN_PARAM_UPDATE_STATUS_PENDING: + { + APP_PRINT_INFO0("app_handle_conn_param_update_evt update pending."); + } + break; + + default: + break; + } +} + +/** + * @brief All the BT GAP MSG are pre-handled in this function. + * @note Then the event handling function shall be called according to the + * subtype of T_IO_MSG + * @param[in] p_gap_msg Pointer to GAP msg + * @return void + */ +void app_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("app_handle_gap_msg: subtype %d", p_gap_msg->subtype); + switch (p_gap_msg->subtype) + { + case GAP_MSG_LE_DEV_STATE_CHANGE: + { + app_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: + { + app_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_CONN_MTU_INFO: + { + app_handle_conn_mtu_info_evt(gap_msg.msg_data.gap_conn_mtu_info.conn_id, + gap_msg.msg_data.gap_conn_mtu_info.mtu_size); + } + break; + + case GAP_MSG_LE_CONN_PARAM_UPDATE: + { + app_handle_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_AUTHEN_STATE_CHANGE: + { + app_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); + le_bond_passkey_display_confirm(conn_id, GAP_CFM_CAUSE_ACCEPT); + } + 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; + + default: + APP_PRINT_ERROR1("app_handle_gap_msg: unknown subtype %d", p_gap_msg->subtype); + break; + } +} +/** @} */ /* End of group PERIPH_GAP_MSG */ + +/** @defgroup PERIPH_GAP_CALLBACK GAP Callback Event Handler + * @brief Handle GAP callback event + * @{ + */ + +/** + * @brief Callback for gap le to notify app + * @param[in] cb_type callback msy type @ref GAP_LE_MSG_Types. + * @param[in] p_cb_data point to callback data @ref T_LE_CB_DATA. + * @retval result @ref 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_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; + + default: + APP_PRINT_ERROR1("app_gap_callback: unhandled cb_type 0x%x", cb_type); + break; + } + return result; +} +/** @} */ /* End of group PERIPH_GAP_CALLBACK */ + +/** @defgroup PERIPH_SEVER_CALLBACK Profile Server Callback Event Handler + * @brief Handle profile server callback event + * @{ + */ + +/** + * @brief All the BT Profile service callback events are handled in this function + * @note Then the event handling function shall be called according to the + * service_id + * @param service_id Profile service ID + * @param p_data Pointer to callback data + * @return T_APP_RESULT, which indicates the function call is successful or not + * @retval APP_RESULT_SUCCESS Function run successfully + * @retval others Function run failed, and return number indicates the reason + */ +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) + { + T_SERVER_APP_CB_DATA *p_param = (T_SERVER_APP_CB_DATA *)p_data; + switch (p_param->eventId) + { + case PROFILE_EVT_SRV_REG_COMPLETE:// srv register result event. + APP_PRINT_INFO1("PROFILE_EVT_SRV_REG_COMPLETE: result %d", + p_param->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_param->event_data.send_data_result.conn_id, + p_param->event_data.send_data_result.cause, + p_param->event_data.send_data_result.service_id, + p_param->event_data.send_data_result.attrib_idx, + p_param->event_data.send_data_result.credits); + if (p_param->event_data.send_data_result.cause == GAP_SUCCESS) + { + APP_PRINT_INFO0("PROFILE_EVT_SEND_DATA_COMPLETE success"); + } + else + { + APP_PRINT_ERROR0("PROFILE_EVT_SEND_DATA_COMPLETE failed"); + } + break; + + default: + break; + } + } + else if (service_id == simp_srv_id) + { + TSIMP_CALLBACK_DATA *p_simp_cb_data = (TSIMP_CALLBACK_DATA *)p_data; + switch (p_simp_cb_data->msg_type) + { + case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION: + { + switch (p_simp_cb_data->msg_data.notification_indification_index) + { + case SIMP_NOTIFY_INDICATE_V3_ENABLE: + { + APP_PRINT_INFO0("SIMP_NOTIFY_INDICATE_V3_ENABLE"); + } + break; + + case SIMP_NOTIFY_INDICATE_V3_DISABLE: + { + APP_PRINT_INFO0("SIMP_NOTIFY_INDICATE_V3_DISABLE"); + } + break; + case SIMP_NOTIFY_INDICATE_V4_ENABLE: + { + APP_PRINT_INFO0("SIMP_NOTIFY_INDICATE_V4_ENABLE"); + } + break; + case SIMP_NOTIFY_INDICATE_V4_DISABLE: + { + APP_PRINT_INFO0("SIMP_NOTIFY_INDICATE_V4_DISABLE"); + } + break; + default: + break; + } + } + break; + + case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE: + { + if (p_simp_cb_data->msg_data.read_value_index == SIMP_READ_V1) + { + uint8_t value[2] = {0x01, 0x02}; + APP_PRINT_INFO0("SIMP_READ_V1"); + simp_ble_service_set_parameter(SIMPLE_BLE_SERVICE_PARAM_V1_READ_CHAR_VAL, 2, &value); + } + } + break; + case SERVICE_CALLBACK_TYPE_WRITE_CHAR_VALUE: + { + switch (p_simp_cb_data->msg_data.write.opcode) + { + case SIMP_WRITE_V2: + { + APP_PRINT_INFO2("SIMP_WRITE_V2: write type %d, len %d", p_simp_cb_data->msg_data.write.write_type, + p_simp_cb_data->msg_data.write.len); + } + break; + default: + break; + } + } + break; + + default: + break; + } + } + else if (service_id == bas_srv_id) + { + T_BAS_CALLBACK_DATA *p_bas_cb_data = (T_BAS_CALLBACK_DATA *)p_data; + switch (p_bas_cb_data->msg_type) + { + case SERVICE_CALLBACK_TYPE_INDIFICATION_NOTIFICATION: + { + switch (p_bas_cb_data->msg_data.notification_indification_index) + { + case BAS_NOTIFY_BATTERY_LEVEL_ENABLE: + { + APP_PRINT_INFO0("BAS_NOTIFY_BATTERY_LEVEL_ENABLE"); + } + break; + + case BAS_NOTIFY_BATTERY_LEVEL_DISABLE: + { + APP_PRINT_INFO0("BAS_NOTIFY_BATTERY_LEVEL_DISABLE"); + } + break; + default: + break; + } + } + break; + + case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE: + { + if (p_bas_cb_data->msg_data.read_value_index == BAS_READ_BATTERY_LEVEL) + { + uint8_t battery_level = 90; + APP_PRINT_INFO1("BAS_READ_BATTERY_LEVEL: battery_level %d", battery_level); + bas_set_parameter(BAS_PARAM_BATTERY_LEVEL, 1, &battery_level); + } + } + break; + + default: + break; + } + } + + return app_result; +} + +/** @} */ /* End of group PERIPH_SEVER_CALLBACK */ + +/** @} */ /* End of group PERIPH_APP */ diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app.h b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app.h new file mode 100644 index 0000000..8aed00b --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app.h @@ -0,0 +1,72 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** +* @file app.h +* @brief This file handles BLE peripheral application routines. +* @author jane +* @date 2017-06-06 +* @version v1.0 +************************************************************************************** +* @attention +* <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> +************************************************************************************** +*/ + +#ifndef _APP_H +#define _APP_H + +#ifdef __cplusplus +extern "C" { +#endif +/*============================================================================* + * Header Files + *============================================================================*/ +#include <profile_server.h> + +#include "app_msg.h" + + +/*============================================================================* + * Variables + *============================================================================*/ +extern T_SERVER_ID simp_srv_id; /**< Simple ble service id*/ +extern T_SERVER_ID bas_srv_id; /**< Battery service id */ + +/*============================================================================* + * Functions + *============================================================================*/ + +/** + * @brief All the application messages are pre-handled in this function + * @note All the IO MSGs are sent to this function, then the event handling + * function shall be called according to the MSG type. + * @param[in] io_msg:IO message data + * @return void + */ +void app_handle_io_msg(T_IO_MSG io_msg); + +/** + * @brief All the BT Profile service callback events are handled in this function + * @note Then the event handling function shall be called according to the + * @param[in] service_id: Profile service ID + * @param[in] p_data: Pointer to callback data + * @return Indicates the function call is successful or not + * @retval result @ref T_APP_RESULT + */ +T_APP_RESULT app_profile_callback(T_SERVER_ID service_id, void *p_data); + +/** + * @brief Callback for gap le to notify app + * @param[in] cb_type callback msy type @ref GAP_LE_MSG_Types. + * @param[in] p_cb_data point to callback data @ref T_LE_CB_DATA. + * @retval result @ref T_APP_RESULT + */ +T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_flags.h b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_flags.h new file mode 100644 index 0000000..3371839 --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_flags.h @@ -0,0 +1,40 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file app_flags.h + * @brief This file is used to config app functions. + * @author jane + * @date 2017-06-06 + * @version v1.0 + ************************************************************************************** + * @attention + * <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> + ************************************************************************************** + */ +#ifndef _APP_FLAGS_H_ +#define _APP_FLAGS_H_ + +#include "upperstack_config.h" + +/** @defgroup PERIPH_Config Peripheral App Configuration + * @brief This file is used to config app functions. + * @{ + */ +/*============================================================================* + * Constants + *============================================================================*/ + +/** @brief Config APP LE link number */ +#define APP_MAX_LINKS 1 +/** @brief Config DLPS: 0-Disable DLPS, 1-Enable DLPS */ +#define F_BT_DLPS_EN 0 +/** @brief Config ANCS Client: 0-Not built in, 1-Open ANCS client function */ +#define F_BT_ANCS_CLIENT_SUPPORT 0 +#define F_BT_ANCS_APP_FILTER (F_BT_ANCS_CLIENT_SUPPORT & 1) +#define F_BT_ANCS_GET_APP_ATTR (F_BT_ANCS_CLIENT_SUPPORT & 0) +/** @brief Config ANCS Client debug log: 0-close, 1-open */ +#define F_BT_ANCS_CLIENT_DEBUG (F_BT_ANCS_CLIENT_SUPPORT & 0) + +/** @} */ /* End of group PERIPH_Config */ +#endif diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_task.c b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_task.c new file mode 100644 index 0000000..f5914b1 --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_task.c @@ -0,0 +1,123 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** + * @file app_task.c + * @brief Routines to create App task and handle events & messages + * @author jane + * @date 2017-06-02 + * @version v1.0 + ************************************************************************************** + * @attention + * <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> + ************************************************************************************** + */ + +/*============================================================================* + * Header Files + *============================================================================*/ +#include <gap_le.h> + +#include "app.h" +#include "app_task.h" + + +/** @defgroup PERIPH_APP_TASK Peripheral App Task + * @brief This file handles the implementation of application task related functions. + * + * Create App task and handle events & messages + * @{ + */ +/*============================================================================* + * Macros + *============================================================================*/ +#define APP_TASK_PRIORITY 1 //!< Task priorities +#define APP_TASK_STACK_SIZE 256 * 4 //!< Task stack size +#define MAX_NUMBER_OF_GAP_MESSAGE 0x20 //!< GAP message queue size +#define MAX_NUMBER_OF_IO_MESSAGE 0x20 //!< IO message queue size +#define MAX_NUMBER_OF_EVENT_MESSAGE (MAX_NUMBER_OF_GAP_MESSAGE + MAX_NUMBER_OF_IO_MESSAGE) //!< Event message queue size + +/*============================================================================* + * Variables + *============================================================================*/ +void *app_task_handle; //!< APP Task handle +void *evt_queue_handle; //!< Event queue handle +void *io_queue_handle; //!< IO queue handle + +/*============================================================================* + * Functions + *============================================================================*/ +extern void driver_init(void); + +void app_main_task(void *p_param); + +/** + * @brief Send msg to app task. + * @param[in] p_handle: The handle to the message queue being peeked. + * @return The status of the message queue peek. + * @retval true:Message queue was peeked successfully. + * @retval false:Message queue was failed to peek. + */ +bool app_send_msg_to_apptask(T_IO_MSG *p_msg) +{ + uint8_t event = EVENT_IO_TO_APP; + + if (os_msg_send(io_queue_handle, p_msg, 0) == false) + { + APP_PRINT_ERROR0("[app_task] app_send_msg_to_apptask: send_io_msg_to_app fail"); + return false; + } + if (os_msg_send(evt_queue_handle, &event, 0) == false) + { + APP_PRINT_ERROR0("[app_task] app_send_msg_to_apptask: send_evt_msg_to_app fail"); + return false; + } + return true; +} + +/** + * @brief Initialize App task + * @return void + */ +void app_task_init() +{ + os_task_create(&app_task_handle, "app", app_main_task, 0, APP_TASK_STACK_SIZE, APP_TASK_PRIORITY); +} + +/** + * @brief App task to handle events & messages + * @param[in] p_param: Parameters sending to the task + * @return void + */ +void app_main_task(void *p_param) +{ + uint8_t event; + os_msg_queue_create(&io_queue_handle, MAX_NUMBER_OF_IO_MESSAGE, sizeof(T_IO_MSG)); + os_msg_queue_create(&evt_queue_handle, MAX_NUMBER_OF_EVENT_MESSAGE, sizeof(uint8_t)); + + gap_start_bt_stack(evt_queue_handle, io_queue_handle, MAX_NUMBER_OF_GAP_MESSAGE); + + driver_init(); + while (true) + { + if (os_msg_recv(evt_queue_handle, &event, 0xFFFFFFFF) == true) + { + if (event == EVENT_IO_TO_APP) + { + T_IO_MSG io_msg; + if (os_msg_recv(io_queue_handle, &io_msg, 0) == true) + { + app_handle_io_msg(io_msg); + } + } + else + { + gap_handle_msg(event); + } + } + } +} + +/** @} */ /* End of group PERIPH_APP_TASK */ + + diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_task.h b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_task.h new file mode 100644 index 0000000..5d5918a --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/app_task.h @@ -0,0 +1,47 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** +* @file app_task.h +* @brief Routines to create App task and handle events & messages +* @author jane +* @date 2017-06-02 +* @version v1.0 +************************************************************************************** +* @attention +* <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> +************************************************************************************** +*/ +#ifndef _APP_TASK_H_ +#define _APP_TASK_H_ + +#include <string.h> + +#include "os_msg.h" +#include "os_queue.h" +#include "os_sched.h" +#include "os_task.h" +#include "os_timer.h" + +#include "app_msg.h" + +#include "trace.h" + + +/** + * @brief Send msg to app task. + * @param[in] p_handle: The handle to the message queue being peeked. + * @return The status of the message queue peek. + * @retval true:Message queue was peeked successfully. + * @retval false:Message queue was failed to peek. + */ +bool app_send_msg_to_apptask(T_IO_MSG *p_msg); + +/** + * @brief Initialize app task + * @return void + */ +void app_task_init(void); + +#endif + diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/main.c b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/main.c new file mode 100644 index 0000000..95e1d08 --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/ble_peripheral/main.c @@ -0,0 +1,248 @@ +/** +***************************************************************************************** +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +***************************************************************************************** +* @file main.c +* @brief Source file for BLE peripheral project, mainly used for initialize modules +* @author jane +* @date 2017-06-12 +* @version v1.0 +************************************************************************************** +* @attention +* <h2><center>© COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2> +************************************************************************************** +*/ + +/*============================================================================* + * Header Files + *============================================================================*/ +#include <string.h> +#include <stdlib.h> +#include <gap.h> +#include <gap_adv.h> +#include <gap_bond_le.h> +#include <gap_msg.h> +#include <bas.h> +#include <simple_ble_service.h> + +#if F_BT_ANCS_CLIENT_SUPPORT +#include <profile_client.h> +#include "ancs.h" +#endif + +#include "trace.h" + +#include "app.h" +#include "app_task.h" +#include "app_timer.h" + +#include "io_keyscan.h" + + +/** @defgroup PERIPH_DEMO_MAIN Peripheral Main + * @brief Main file to initialize hardware and BT stack and start task scheduling + * @{ + */ + +/*============================================================================* + * Constants + *============================================================================*/ +/** @brief Default minimum advertising interval when device is discoverable (units of 625us, 160=100ms) */ +#define DEFAULT_ADVERTISING_INTERVAL_MIN 320 +/** @brief Default maximum advertising interval */ +#define DEFAULT_ADVERTISING_INTERVAL_MAX 320 + + +/*============================================================================* + * Variables + *============================================================================*/ + +/** @brief GAP - scan response data (max size = 31 bytes) */ +static const uint8_t scan_rsp_data[] = +{ + 0x03, /* length */ + GAP_ADTYPE_APPEARANCE, /* type="Appearance" */ + LO_WORD(GAP_GATT_APPEARANCE_UNKNOWN), + HI_WORD(GAP_GATT_APPEARANCE_UNKNOWN), +}; + +/** @brief GAP - Advertisement data (max size = 31 bytes, best kept short to conserve power) */ +static const uint8_t adv_data[] = +{ + /* Flags */ + 0x02, /* length */ + GAP_ADTYPE_FLAGS, /* type="Flags" */ + GAP_ADTYPE_FLAGS_LIMITED | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED, + /* Service */ + 0x03, /* length */ + GAP_ADTYPE_16BIT_COMPLETE, + LO_WORD(GATT_UUID_SIMPLE_PROFILE), + HI_WORD(GATT_UUID_SIMPLE_PROFILE), + /* Local name */ + 0x0F, /* length */ + GAP_ADTYPE_LOCAL_NAME_COMPLETE, + 'B', 'L', 'E', '_', 'P', 'E', 'R', 'I', 'P', 'H', 'E', 'R', 'A', 'L', +}; + +/*============================================================================* + * Functions + *============================================================================*/ +/** + * @brief Initialize peripheral and gap bond manager related parameters + * @return void + */ +void app_le_gap_init(void) +{ + /* Device name and device appearance */ + uint8_t device_name[GAP_DEVICE_NAME_LEN] = "BLE_PERIPHERAL"; + uint16_t appearance = GAP_GATT_APPEARANCE_UNKNOWN; + uint8_t slave_init_mtu_req = false; + + + /* Advertising parameters */ + uint8_t adv_evt_type = GAP_ADTYPE_ADV_IND; + uint8_t adv_direct_type = GAP_REMOTE_ADDR_LE_PUBLIC; + uint8_t adv_direct_addr[GAP_BD_ADDR_LEN] = {0}; + uint8_t adv_chann_map = GAP_ADVCHAN_ALL; + uint8_t adv_filter_policy = GAP_ADV_FILTER_ANY; + uint16_t adv_int_min = DEFAULT_ADVERTISING_INTERVAL_MIN; + uint16_t adv_int_max = DEFAULT_ADVERTISING_INTERVAL_MAX; + + /* GAP Bond Manager parameters */ + uint8_t auth_pair_mode = GAP_PAIRING_MODE_PAIRABLE; + uint16_t auth_flags = GAP_AUTHEN_BIT_BONDING_FLAG; + uint8_t auth_io_cap = GAP_IO_CAP_NO_INPUT_NO_OUTPUT; + uint8_t auth_oob = false; + uint8_t auth_use_fix_passkey = false; + uint32_t auth_fix_passkey = 0; +#if F_BT_ANCS_CLIENT_SUPPORT + uint8_t auth_sec_req_enable = true; +#else + uint8_t auth_sec_req_enable = false; +#endif + uint16_t auth_sec_req_flags = GAP_AUTHEN_BIT_BONDING_FLAG; + + /* Set device name and device appearance */ + le_set_gap_param(GAP_PARAM_DEVICE_NAME, GAP_DEVICE_NAME_LEN, device_name); + le_set_gap_param(GAP_PARAM_APPEARANCE, sizeof(appearance), &appearance); + le_set_gap_param(GAP_PARAM_SLAVE_INIT_GATT_MTU_REQ, sizeof(slave_init_mtu_req), + &slave_init_mtu_req); + + /* Set advertising parameters */ + le_adv_set_param(GAP_PARAM_ADV_EVENT_TYPE, sizeof(adv_evt_type), &adv_evt_type); + le_adv_set_param(GAP_PARAM_ADV_DIRECT_ADDR_TYPE, sizeof(adv_direct_type), &adv_direct_type); + le_adv_set_param(GAP_PARAM_ADV_DIRECT_ADDR, sizeof(adv_direct_addr), adv_direct_addr); + le_adv_set_param(GAP_PARAM_ADV_CHANNEL_MAP, sizeof(adv_chann_map), &adv_chann_map); + le_adv_set_param(GAP_PARAM_ADV_FILTER_POLICY, sizeof(adv_filter_policy), &adv_filter_policy); + le_adv_set_param(GAP_PARAM_ADV_INTERVAL_MIN, sizeof(adv_int_min), &adv_int_min); + le_adv_set_param(GAP_PARAM_ADV_INTERVAL_MAX, sizeof(adv_int_max), &adv_int_max); + le_adv_set_param(GAP_PARAM_ADV_DATA, sizeof(adv_data), (void *)adv_data); + le_adv_set_param(GAP_PARAM_SCAN_RSP_DATA, sizeof(scan_rsp_data), (void *)scan_rsp_data); + + /* Setup the GAP Bond Manager */ + gap_set_param(GAP_PARAM_BOND_PAIRING_MODE, sizeof(auth_pair_mode), &auth_pair_mode); + gap_set_param(GAP_PARAM_BOND_AUTHEN_REQUIREMENTS_FLAGS, sizeof(auth_flags), &auth_flags); + gap_set_param(GAP_PARAM_BOND_IO_CAPABILITIES, sizeof(auth_io_cap), &auth_io_cap); + gap_set_param(GAP_PARAM_BOND_OOB_ENABLED, sizeof(auth_oob), &auth_oob); + le_bond_set_param(GAP_PARAM_BOND_FIXED_PASSKEY, sizeof(auth_fix_passkey), &auth_fix_passkey); + le_bond_set_param(GAP_PARAM_BOND_FIXED_PASSKEY_ENABLE, sizeof(auth_use_fix_passkey), + &auth_use_fix_passkey); + le_bond_set_param(GAP_PARAM_BOND_SEC_REQ_ENABLE, sizeof(auth_sec_req_enable), &auth_sec_req_enable); + le_bond_set_param(GAP_PARAM_BOND_SEC_REQ_REQUIREMENT, sizeof(auth_sec_req_flags), + &auth_sec_req_flags); + + /* register gap message callback */ + le_register_app_cb(app_gap_callback); +} + +/** + * @brief Add GATT services and register callbacks + * @return void + */ +void app_le_profile_init(void) +{ + server_init(2); + simp_srv_id = simp_ble_service_add_service(app_profile_callback); + bas_srv_id = bas_add_service(app_profile_callback); + server_register_app_cb(app_profile_callback); +#if F_BT_ANCS_CLIENT_SUPPORT + client_init(1); + ancs_init(APP_MAX_LINKS); +#endif +} + +/** + * @brief Initialize global data. + * @param No parameter. + * @return void + */ +void global_data_init(void) +{ + global_data_keyscan_init(); +} + +/** + * @brief Contains the initialization of pinmux settings and pad settings + * @note All the pinmux settings and pad settings shall be initiated in this function, + * but if legacy driver is used, the initialization of pinmux setting and pad setting + * should be performed with the IO initializing. + * @return void + */ +void board_init(void) +{ + board_keyboard_init(); +} + +/** + * @brief Contains the initialization of peripherals + * @note Both new architecture driver and legacy driver initialization method can be used + * @return void + */ +void driver_init(void) +{ + driver_keyboard_init(KeyScan_Debounce_Enable); +// nvic_keyscan_init(); +} + +/** + * @brief Contains the power mode settings + * @return void + */ +void pwr_mgr_init(void) +{ +} + +/** + * @brief Contains the initialization of all tasks + * @note There is only one task in BLE Peripheral APP, thus only one APP task is init here + * @return void + */ +void task_init(void) +{ + app_task_init(); +} + +/** + * @brief Entry of app code + * @return int (To avoid compile warning) + */ +int main(void) +{ + extern uint32_t random_seed_value; + srand(random_seed_value); + global_data_init(); + board_init(); + le_gap_init(APP_MAX_LINKS); + gap_lib_init(); + app_le_gap_init(); + app_le_profile_init(); + pwr_mgr_init(); + sw_timer_init(); + task_init(); + os_sched_start(); + + return 0; +} +/** @} */ /* End of group PERIPH_DEMO_MAIN */ + + diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/io_keyscan.c b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/io_keyscan.c new file mode 100644 index 0000000..258cfef --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/io_keyscan.c @@ -0,0 +1,234 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file io_keyscan.c +* @brief This file provides demo code of keyscan manual mode. +* @details +* @author yuan +* @date 2018-12-07 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "io_keyscan.h" + +#include "app_task.h" + + +/* Globals ------------------------------------------------------------------*/ +/* Timer handle */ +void *KeyScan_Timer_Handle = NULL; + +KeyScan_Data_TypeDef Current_Key_Data; +bool Key_Pressed_Flag = false; + + +/** + * @brief Initialize keyscan global data. + * @param No parameter. + * @return void + */ +void global_data_keyscan_init(void) +{ + /* Data struct init */ + memset(&Current_Key_Data, 0, sizeof(KeyScan_Data_TypeDef)); +// memset(&Pre_Key_Data, 0, sizeof(KeyScan_Data_TypeDef)); +} + +/** + * @brief Initialization of pinmux settings and pad settings. + * @param No parameter. + * @return Void + */ +void board_keyboard_init(void) +{ + /* Keypad pad config */ + Pad_Config(KEYBOARD_ROW_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, + PAD_OUT_LOW); + Pad_Config(KEYBOARD_ROW_1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, + PAD_OUT_LOW); + Pad_Config(KEYBOARD_COLUMN_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, + PAD_OUT_LOW); + Pad_Config(KEYBOARD_COLUMN_1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, + PAD_OUT_LOW); + + /* keypad pinmux config */ + Pinmux_Config(KEYBOARD_ROW_0, KEY_ROW_0); + Pinmux_Config(KEYBOARD_ROW_1, KEY_ROW_1); + Pinmux_Config(KEYBOARD_COLUMN_0, KEY_COL_0); + Pinmux_Config(KEYBOARD_COLUMN_1, KEY_COL_1); +} + +/** + * @brief Initialize keyboard peripheral. + * @param No parameter. + * @return Void + */ +void driver_keyboard_init(uint32_t vDebounce_En) +{ + /* Turn on keyscan clock */ + RCC_PeriphClockCmd(APBPeriph_KEYSCAN, APBPeriph_KEYSCAN_CLOCK, ENABLE); + + KEYSCAN_InitTypeDef KEYSCAN_InitStruct; + KeyScan_StructInit(&KEYSCAN_InitStruct); + + KEYSCAN_InitStruct.rowSize = KEYBOARD_ROW_SIZE; + KEYSCAN_InitStruct.colSize = KEYBOARD_COLUMN_SIZE; + KEYSCAN_InitStruct.scanmode = KeyScan_Manual_Scan_Mode; + KEYSCAN_InitStruct.debounceEn = vDebounce_En; + + KeyScan_Init(KEYSCAN, &KEYSCAN_InitStruct); + + KeyScan_INTConfig(KEYSCAN, KEYSCAN_INT_SCAN_END, ENABLE); + KeyScan_ClearINTPendingBit(KEYSCAN, KEYSCAN_INT_SCAN_END); + KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, DISABLE); /* Unmask keyscan interrupt */ + KeyScan_Cmd(KEYSCAN, ENABLE); + + /* Keyscan IRQ */ + NVIC_InitTypeDef NVIC_InitStruct; + NVIC_InitStruct.NVIC_IRQChannel = KeyScan_IRQn; + NVIC_InitStruct.NVIC_IRQChannelCmd = (FunctionalState)ENABLE; + NVIC_InitStruct.NVIC_IRQChannelPriority = 3; + NVIC_Init(&NVIC_InitStruct); +} + +/** + * @brief Calculate adc sample voltage. + * @param No parameter. + * @return void + */ +static void io_keyscan_handle_keys(T_IO_MSG *io_keyscan_msg) +{ + uint16_t subtype = io_keyscan_msg->subtype; + + if (subtype == IO_MSG_KEYSCAN_RX_PKT) + { + KeyScan_Data_TypeDef *p_key_data = (KeyScan_Data_TypeDef *)io_keyscan_msg->u.buf; + /* Single key press */ + if (p_key_data->length == 1) + { + APP_PRINT_INFO2("[io_keyscan] io_keyscan_handle_keys: Single key press. key: (%d, %d)", + p_key_data->key[0].row, p_key_data->key[0].column); + } + + /* two keys press */ + if (p_key_data->length == 2) + { + APP_PRINT_INFO4("[io_keyscan] io_keyscan_handle_keys: Two key press. key0: (%d, %d), key1: (%d, %d)", + p_key_data->key[0].row, p_key_data->key[0].column, p_key_data->key[1].row, + p_key_data->key[1].column); + } + } + else if (subtype == IO_MSG_KEYSCAN_ALLKEYRELEASE) + { + APP_PRINT_INFO0("[io_keyscan] io_keyscan_handle_keys: All keys release."); + + } + else + { + APP_PRINT_INFO0("[io_keyscan] io_keyscan_handle_keys: Wrong key event!"); + } +} + +/** + * @brief Handle keyscan data function. + * @param No parameter. + * @return void + */ +void io_handle_keyscan_msg(T_IO_MSG *io_keyscan_msg) +{ + io_keyscan_handle_keys(io_keyscan_msg); +} + +void timer_keyscan_callback(void *p_xTimer) +{ + if (true == Key_Pressed_Flag) + { +// APP_PRINT_INFO0("[io_keyscan] timer_keyscan_callback: start release timer"); + Key_Pressed_Flag = false; + driver_keyboard_init(KeyScan_Debounce_Disable); + + /* Start timer to check key status */ + os_timer_restart(&p_xTimer, KEYSCAN_SW_RELEASE_TIMEOUT); + } + else + { + /* Keyscan release event detected */ +// APP_PRINT_INFO0("[io_keyscan] timer_keyscan_callback: keyscan release event detected "); + T_IO_MSG int_keyscan_msg; + int_keyscan_msg.type = IO_MSG_TYPE_KEYSCAN; + int_keyscan_msg.subtype = IO_MSG_KEYSCAN_ALLKEYRELEASE; + + if (false == app_send_msg_to_apptask(&int_keyscan_msg)) + { + APP_PRINT_ERROR0("[io_keyscan] timer_keyscan_callback: Send IO_MSG_KEYSCAN_ALLKEYRELEASE failed!"); + } + + global_data_keyscan_init(); + driver_keyboard_init(KeyScan_Debounce_Enable); + } +} + +void timer_keyscan_init(void) +{ + APP_PRINT_INFO0("[io_keyscan] timer_keyscan_init: keyscan timer init"); + if (false == os_timer_create(&KeyScan_Timer_Handle, "keyscan_timer", 1, \ + KEYSCAN_SW_INTERVAL, false, timer_keyscan_callback)) + { + APP_PRINT_ERROR0("[io_keyscan] timer_keyscan_init: timer creat failed!"); + } +} + +/** + * @brief Keyscan interrupt handler function. + * @param No parameter. + * @return void +*/ +void Keyscan_Handler(void) +{ + uint32_t fifo_length; + T_IO_MSG int_keyscan_msg; + + if (KeyScan_GetFlagState(KEYSCAN, KEYSCAN_INT_FLAG_SCAN_END) == SET) + { + /* Read current keyscan interrupt status and mask interrupt */ + KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, ENABLE); + memset(&Current_Key_Data, 0, sizeof(KeyScan_Data_TypeDef)); + + /* KeyScan fifo not empty */ + if (KeyScan_GetFlagState(KEYSCAN, KEYSCAN_FLAG_EMPTY) != SET) + { + fifo_length = (uint32_t)KeyScan_GetFifoDataNum(KEYSCAN); + KeyScan_Read(KEYSCAN, (uint16_t *)&Current_Key_Data.key[0], fifo_length); + Current_Key_Data.length = fifo_length; + Key_Pressed_Flag = true; + + /* Start sw timer to check press status */ + if (!os_timer_restart(&KeyScan_Timer_Handle, KEYSCAN_SW_INTERVAL)) + { + APP_PRINT_ERROR0("[io_keyscan] Keyscan_Handler: Restart keyscan_timer failed!"); + /* Set flag to default status and reinit keyscan module with debounce enabled */ + global_data_keyscan_init(); + driver_keyboard_init(KeyScan_Debounce_Enable); + return; + } + + /* Send event to app task */ + int_keyscan_msg.type = IO_MSG_TYPE_KEYSCAN; + int_keyscan_msg.subtype = IO_MSG_KEYSCAN_RX_PKT; + int_keyscan_msg.u.buf = (void *)&Current_Key_Data; + if (false == app_send_msg_to_apptask(&int_keyscan_msg)) + { + APP_PRINT_ERROR0("[io_keyscan] Keyscan_Handler: Send IO_MSG_KEYSCAN_RX_PKT failed!"); + //Add user code here! + return; + } + } + KeyScan_ClearINTPendingBit(KEYSCAN, KEYSCAN_INT_SCAN_END); + KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, DISABLE); + } +} + +/******************* (C) COPYRIGHT 2018 Realtek Semiconductor Corporation *****END OF FILE****/ diff --git a/src/sample/io_sample/KEYSCAN/Keyscan_Manual/io_keyscan.h b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/io_keyscan.h new file mode 100644 index 0000000..60d01d3 --- /dev/null +++ b/src/sample/io_sample/KEYSCAN/Keyscan_Manual/io_keyscan.h @@ -0,0 +1,63 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file io_keyscan.h +* @brief +* @details +* @author yuan +* @date 2018-12-07 +* @version v1.0 +********************************************************************************************************* +*/ + +#ifndef __IO_ADC_H +#define __IO_ADC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "rtl876x_keyscan.h" +#include "rtl876x_nvic.h" +#include "rtl876x_pinmux.h" +#include "rtl876x_rcc.h" + +#include "board.h" + +#include "app_msg.h" + + +/* Defines -------------------------------------------------------------------*/ +#define KEYSCAN_SW_INTERVAL (200)/* 200ms */ +#define KEYSCAN_SW_RELEASE_TIMEOUT (10)/* 10ms */ + +/* Typedefs ------------------------------------------------------------------*/ +typedef struct +{ + uint32_t length; + struct + { + uint16_t column: 5; /**< keyscan column buffer data */ + uint16_t row: 4; /**< keyscan raw buffer data */ + } key[26]; +} KeyScan_Data_TypeDef; + + +extern void *KeyScan_Timer_Handle; +extern KeyScan_Data_TypeDef Current_Key_Data; + + +void global_data_keyscan_init(void); +void board_keyboard_init(void); +void driver_keyboard_init(uint32_t vDebounce_En); +void timer_keyscan_init(void); +void io_handle_keyscan_msg(T_IO_MSG *io_keyscan_msg); + +#ifdef __cplusplus +} +#endif + +#endif + |