diff options
Diffstat (limited to 'src/sample/io_sample/IR/Learn')
21 files changed, 3679 insertions, 0 deletions
diff --git a/src/sample/io_sample/IR/Learn/ble_peripheral/ancs.c b/src/sample/io_sample/IR/Learn/ble_peripheral/ancs.c new file mode 100644 index 0000000..ac3254e --- /dev/null +++ b/src/sample/io_sample/IR/Learn/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/IR/Learn/ble_peripheral/ancs.h b/src/sample/io_sample/IR/Learn/ble_peripheral/ancs.h new file mode 100644 index 0000000..68ec35b --- /dev/null +++ b/src/sample/io_sample/IR/Learn/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/IR/Learn/ble_peripheral/app.c b/src/sample/io_sample/IR/Learn/ble_peripheral/app.c new file mode 100644 index 0000000..af0eaa1 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ble_peripheral/app.c @@ -0,0 +1,619 @@ +/** +***************************************************************************************** +* 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 "ir_learn_app.h" +#include "ir_learn.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 +#if (IR_FUN_EN) + case IO_MSG_TYPE_IR: + { +#if (IR_FUN_LEARN_EN) + if (ir_learn_handle_msg(&io_msg)) + { + /* IR learn finish */ +#if (LED_IR_FUN_EN) + extern void led_ir_learn_swap(void); + led_ir_learn_swap(); +#endif + } + //Add user code here! +#endif + } + break; +#endif + 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/IR/Learn/ble_peripheral/app.h b/src/sample/io_sample/IR/Learn/ble_peripheral/app.h new file mode 100644 index 0000000..8aed00b --- /dev/null +++ b/src/sample/io_sample/IR/Learn/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/IR/Learn/ble_peripheral/app_flags.h b/src/sample/io_sample/IR/Learn/ble_peripheral/app_flags.h new file mode 100644 index 0000000..3371839 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/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/IR/Learn/ble_peripheral/app_task.c b/src/sample/io_sample/IR/Learn/ble_peripheral/app_task.c new file mode 100644 index 0000000..0d2bbb9 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ble_peripheral/app_task.c @@ -0,0 +1,124 @@ +/** +***************************************************************************************** +* 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 * 10 //!< 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/IR/Learn/ble_peripheral/app_task.h b/src/sample/io_sample/IR/Learn/ble_peripheral/app_task.h new file mode 100644 index 0000000..5d5918a --- /dev/null +++ b/src/sample/io_sample/IR/Learn/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/IR/Learn/ble_peripheral/main.c b/src/sample/io_sample/IR/Learn/ble_peripheral/main.c new file mode 100644 index 0000000..65575cb --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ble_peripheral/main.c @@ -0,0 +1,261 @@ +/** +***************************************************************************************** +* 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 <stdlib.h> +#include <string.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_flags.h" +//#include "app_timer.h" + +#include "ir_learn_app.h" +#include "ir_learn.h" +#include "ir_led.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) +{ +} + +/** + * @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) +{ +#if (IR_FUN_EN && LED_IR_FUN_EN) + board_ir_led_init(); +#endif +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + board_ir_learn_init(); +#endif +} + +/** + * @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) +{ +#if (IR_FUN_EN && LED_IR_FUN_EN) + driver_ir_led_init(); +#endif +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + ir_learn_timer_init(); + ir_learn_module_init(); +#endif +} + +/** + * @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/IR/Learn/ir_learn.c b/src/sample/io_sample/IR/Learn/ir_learn.c new file mode 100644 index 0000000..efb68e5 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ir_learn.c @@ -0,0 +1,340 @@ +/** +********************************************************************************************************* +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file ir_learn.c +* @brief This file provides ir learn driver. +* @details +* @author elliot chen +* @date 2017-11-16 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes --------------------------------------------------------------------*/ +#include "ir_learn.h" + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + +/** + * @brief Initialization of pinmux settings and pad settings. + * @param No parameter. + * @return void + */ +void board_ir_learn_init(void) +{ + board_ir_rx_init(); +} + +/** + * @brief Close the IR learn function. + * @param none. + * @retval None + */ +void ir_learn_deinit(void) +{ + ir_trans_rx_deinit(); +} + +/** + * @brief Initializes some peripherals which used to learn waveform. + * @param none. + * @retval None + */ +void ir_learn_init(void) +{ + ir_trans_rx_init(); +} + +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT +/** + * @brief Learn a specific IR waveform duty cycle. + * @param pIR_Packet: point to IR packet struct. + * @retval The decoded status. + */ +static IR_Learn_Status ir_learn_dutycycle(IR_Learn_TypeDef *pIR_Packet) +{ + uint16_t i = 0; + uint32_t buf[IR_LEARN_DUTY_CYCLE_SAMPLE_SIZE_MAX] = {0}; + uint32_t carrier_high_time = 0; + uint32_t carrier_low_time = 0; + + /* Replicate data used to calculate duty cycle from the IR receiving data queue. */ + if (ir_trans_rx_get_data_len() >= IR_LEARN_DUTY_CYCLE_SAMPLE_SIZE_MAX) + { + ir_trans_rx_copy_data(buf, IR_LEARN_DUTY_CYCLE_SAMPLE_SIZE_MAX); + } + else + { + return IR_LEARN_DUTY_CYCLE_ERR_NO_SAMPLE; + } + + for (i = 0; i < (IR_LEARN_DUTY_CYCLE_SAMPLE_SIZE_MAX - 1); i++) + { + if (((buf[i] & IR_DATA_MSK) < TIME_HIGHEST_VALUE) && + ((buf[i + 1] & IR_DATA_MSK) < TIME_HIGHEST_VALUE)) + { + /* Check if there is a carrier waveform. */ + if (buf[i] & IR_CARRIER_DATA_TYPE) + { + carrier_high_time = buf[i] & IR_DATA_MSK; + carrier_low_time = buf[i + 1] & IR_DATA_MSK; + } + else + { + carrier_high_time = buf[i + 1] & IR_DATA_MSK; + carrier_low_time = buf[i] & IR_DATA_MSK; + } + break; + } + } + + if (carrier_high_time && carrier_low_time) + { + pIR_Packet->carrier_time = carrier_high_time + carrier_low_time; + pIR_Packet->duty_cycle = (float)carrier_high_time / ((float)carrier_high_time + + (float)carrier_low_time); + return IR_LEARN_OK; + } + + return IR_LEARN_DUTY_CYCLE_ERR_NO_VALID_DATA; +} + +/** + * @brief IR data compensation. + * @param pIR_Packet: point to ir packet struct. + * @retval void + */ +void ir_learn_data_compensation(IR_Learn_TypeDef *pIR_Packet) +{ + uint16_t i = 0; + + if ((pIR_Packet->freq == 0) || (pIR_Packet->duty_cycle == 0)) + { + return ; + } + + for (i = 0; i <= pIR_Packet->buf_index; i++) + { + pIR_Packet->ir_buf[i] += pIR_Packet->carrier_time; + } +} + +#endif + + +/** + * @brief Learn a specific ir waveform freqency. + * @param pIR_Packet: point to ir packet struct. + * @retval The decoded status. + */ +IR_Learn_Status ir_learn_freq(IR_Learn_TypeDef *pIR_Packet) +{ + uint16_t i = 0; + uint16_t j = 0; + float freq_sum = 0; +#if IR_LEARN_FREQ_FILTER_EN + float max_freq = 0; + float min_freq = 1000.0; + float temp = 0; +#endif + + for (i = 0, j = 0; (i <= pIR_Packet->buf_index) && (j <= pIR_Packet->carrier_info_idx); i++) + { + if (pIR_Packet->ir_buf[i] & IR_CARRIER_DATA_TYPE) + { + temp = (pIR_Packet->carrier_info_buf[j++] * (IR_LEARN_FREQ * 0.5)) / \ + (pIR_Packet->ir_buf[i] & IR_DATA_MSK); + + freq_sum += temp; + +#if IR_LEARN_FREQ_FILTER_EN + if (max_freq < temp) + { + max_freq = temp; + } + if (min_freq > temp) + { + min_freq = temp; + } +#endif + } + } + +#if IR_LEARN_FREQ_FILTER_EN + if (j > 2) + { + freq_sum -= (max_freq + min_freq); + j -= 2; + } +#endif + + if (j) + { + pIR_Packet->freq = freq_sum / j; + } + + return IR_LEARN_OK; +} + + +/** + * @brief Convert ir learned waveform data to actual ir data which can be sent. + * @param pIR_Packet: point to ir packet struct. + * @retval void + */ +void ir_learn_data_convert(IR_Learn_TypeDef *pIR_Packet) +{ + uint16_t i = 0; + +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + if ((pIR_Packet->freq == 0) || (pIR_Packet->duty_cycle == 0)) + { + return ; + } +#else + if (pIR_Packet->freq == 0) + { + return ; + } +#endif + + for (i = 0; i <= pIR_Packet->buf_index; i++) + { + if (pIR_Packet->ir_buf[i] & IR_CARRIER_DATA_TYPE) + { + pIR_Packet->ir_buf[i] = (pIR_Packet->ir_buf[i] & IR_DATA_MSK) * pIR_Packet->freq / IR_LEARN_FREQ; + pIR_Packet->ir_buf[i] |= IR_CARRIER_DATA_TYPE; + } + else + { + pIR_Packet->ir_buf[i] = (pIR_Packet->ir_buf[i] & IR_DATA_MSK) * pIR_Packet->freq / IR_LEARN_FREQ; + } + +#if IR_LEARN_SOFTWARE_ADJUST_EN + if ((pIR_Packet->ir_buf[i] & IR_DATA_MSK) > 0) + { + pIR_Packet->ir_buf[i] -= 1; + } +#endif + } +} + +/** + * @brief IR learn data decode + * @param pIR_Packet: point to IR packet struct. + * @retval The decoded status. + */ +IR_Learn_Status ir_learn_decode(IR_Learn_TypeDef *pIR_Packet) +{ + uint32_t time_interval = 0; + IR_Learn_Status status = IR_LEARN_OK; + +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + if (!pIR_Packet->duty_cycle) + { + status = ir_learn_dutycycle(pIR_Packet); + } +#endif + + while (ir_trans_rx_get_data_len()) + { + /* Extract data */ + ir_trans_rx_read_data(&time_interval, 1); + time_interval &= IR_DATA_MSK; + + /* Record total time of carrier wave */ + if (time_interval < TIME_HIGHEST_VALUE) + { + /* Record carrier waveform time */ + pIR_Packet->ir_buf[pIR_Packet->buf_index] += time_interval; + + /* Record carrier number */ + pIR_Packet->carrier_info_buf[pIR_Packet->carrier_info_idx]++; + + /* Record data type */ + pIR_Packet->is_carrier = true; +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + pIR_Packet->last_handle_data = time_interval; +#endif + } + else + { + if (pIR_Packet->is_carrier == true) + { +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + if (pIR_Packet->duty_cycle) + { + if (pIR_Packet->last_handle_data < TIME_HIGHEST_VALUE) + { + pIR_Packet->ir_buf[pIR_Packet->buf_index] += pIR_Packet->carrier_time - + pIR_Packet->last_handle_data; + } + } + else + { + IR_RX_DBG_BUFFER(MODULE_APP, LEVEL_INFO, "Warning: IR carrier data compensation handle error!", + 0); + status = IR_LEARN_CARRIRE_DATA_HANDLE_ERR; + } +#endif + /* Restore data type */ + pIR_Packet->ir_buf[pIR_Packet->buf_index] |= IR_CARRIER_DATA_TYPE; + /* pointer to next buffer to store data */ + pIR_Packet->buf_index++; +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + if (pIR_Packet->duty_cycle) + { + /* Store value of low waveform */ + pIR_Packet->ir_buf[pIR_Packet->buf_index++] = time_interval + pIR_Packet->last_handle_data - \ + pIR_Packet->carrier_time; + } + else + { + /* Store value of low waveform */ + pIR_Packet->ir_buf[pIR_Packet->buf_index++] = time_interval; + IR_RX_DBG_BUFFER(MODULE_APP, LEVEL_INFO, + "Warning: IR no carrier data compensation handle error!", 0); + status = IR_LEARN_NO_CARRIRE_DATA_HANDLE_ERR; + } +#else + /* Store value of low waveform */ + pIR_Packet->ir_buf[pIR_Packet->buf_index++] = time_interval; +#endif + /* Record new carrier waveform information */ + pIR_Packet->carrier_info_idx++; + /* Record data type */ + pIR_Packet->is_carrier = false; + } + else + { + /* Store value of low waveform */ + //pIR_Packet->ir_buf[pIR_Packet->buf_index] += time_interval; + IR_RX_DBG_BUFFER(MODULE_APP, LEVEL_INFO, "Warning: exceed maximum stop signal value!", 0); + status = IR_LEARN_WAVEFORM_ERR; + break; + } + } + + /* Check the maximum number of learning data */ + if (pIR_Packet->buf_index >= IR_LEARN_WAVEFORM_SIZE_MAX) + { + status = IR_LEARN_EXCEED_SIZE; + break; + } + + /* Check IR end signal */ + if (time_interval >= IR_LEARN_STOP_TIME) + { + status = IR_LEARN_EXIT; + break; + } + } + + return status; +} + +#endif /* (IR_FUN_EN && IR_FUN_LEARN_EN) */ + +/******************* (C) COPYRIGHT 2017 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/ir_learn.h b/src/sample/io_sample/IR/Learn/ir_learn.h new file mode 100644 index 0000000..a88df33 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ir_learn.h @@ -0,0 +1,99 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_learn.h +* @brief +* @details +* @author yuan +* @date 2019-01-24 +* @version v1.0 +* ********************************************************************************************************* +*/ + +#ifndef __IR_LEARN_H +#define __IR_LEARN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "board.h" + + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + +/* Includes ------------------------------------------------------------------*/ +#include "ir_trans_rx.h" +#include "ir_learn_config.h" + +/* Defines -------------------------------------------------------------*/ +/* Filter threshold value. If time interval< 200us(10KHz), treat it as a part of a carrier time. */ +/* IR learn carrier freqency between 10KHz and 2.5MHz */ +#define TIME_HIGHEST_VALUE (200*(IR_LEARN_FREQ/1000000)) + +/* IR data mask */ +#define IR_DATA_MSK ((uint32_t)0x7FFFFFFFUL) +/* Carrier waveform data type select */ +#define IR_CARRIER_DATA_TYPE ((uint32_t)0x80000000UL) + +/** @defgroup IR_LEARN_Exported_Types IR Learn Exported Types + * @{ + */ +typedef enum +{ + IR_LEARN_OK, /**< IR learn ok: learning */ + IR_LEARN_EXIT, /**< IR learn exit: complete IR learn */ + IR_LEARN_WAVEFORM_ERR, /**< IR learn waveform error */ + IR_LEARN_CARRIRE_DATA_HANDLE_ERR, /**< IR learn carrier data compensation error */ + IR_LEARN_NO_CARRIRE_DATA_HANDLE_ERR, /**< IR learn carrier data compensation error */ + IR_LEARN_EXCEED_SIZE, /**< IR learn exceed maximum size */ + IR_LEARN_DUTY_CYCLE_ERR_NO_SAMPLE, /**< IR learn duty cycle error: samples were not collceted */ + IR_LEARN_DUTY_CYCLE_ERR_NO_VALID_DATA, /**< IR learn duty cycle error: have no valid data */ + //IR_LEARN_DUTY_CYCLE_ERR_NO_Carrier_TIME,/**< IR learn duty cycle error: have no valid carrier high time */ +} IR_Learn_Status; + +/** + * @brief IR learn data structure + */ +typedef struct +{ + uint32_t ir_buf[IR_LEARN_WAVEFORM_SIZE_MAX]; +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + uint32_t last_handle_data; +#endif + uint16_t buf_index; + uint16_t carrier_info_buf[IR_LEARN_WAVEFORM_SIZE_MAX / 2 + 2]; + uint16_t carrier_info_idx; + uint8_t is_carrier; + +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + uint32_t carrier_time; + float duty_cycle; +#endif + float freq; +} IR_Learn_TypeDef; + +/** End of IR_LEARN_Exported_Types + * @} + */ + +void board_ir_learn_init(void); +void ir_learn_deinit(void); +void ir_learn_init(void); +IR_Learn_Status ir_learn_freq(IR_Learn_TypeDef *pIR_Packet); +void ir_learn_data_convert(IR_Learn_TypeDef *pIR_Packet); +IR_Learn_Status ir_learn_decode(IR_Learn_TypeDef *pIR_Packet); + +#endif /* (IR_FUN_EN && IR_FUN_LEARN_EN) */ + +#ifdef __cplusplus +} +#endif + +#endif /* __IR_LEARN_H */ + + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/ir_learn_app.c b/src/sample/io_sample/IR/Learn/ir_learn_app.c new file mode 100644 index 0000000..44d1784 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ir_learn_app.c @@ -0,0 +1,199 @@ +/** +********************************************************************************************************* +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file ir_learn_app.c +* @brief This file provides application layer application code for how to use IR learin driver. +* @details +* @author elliot chen +* @date 2018-7-24 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "ir_learn_app.h" + + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) +#include "os_timer.h" + +/* Globals -------------------------------------------------------------------*/ +typedef void *TimerHandle_t; + +TimerHandle_t IR_Learn_Timer = 0; + +IR_Learn_TypeDef IR_Learn_Packet; + +extern bool app_send_msg_to_apptask(T_IO_MSG *p_msg); +#define ir_send_msg_to_apptask app_send_msg_to_apptask + +/** + * @brief ir learn msg handle from ir learn driver isr. + * @param vIsEnd:0 FALSE, 1 TRUE + * @return void + */ +static void ir_learn_send_msg_from_isr(uint8_t vIsEnd) +{ + //Add applcation code here which send msg from IR ISR to application layer to notify handling data + T_IO_MSG bee_io_msg; + bee_io_msg.type = IO_MSG_TYPE_IR; + + if (vIsEnd) + { + /* send ir learn data message to app */ + bee_io_msg.subtype = IO_MSG_TYPE_IR_LEARN_STOP; + } + else + { + /* send ir learn data message to app */ + bee_io_msg.subtype = IO_MSG_TYPE_IR_LEARN_DATA; + } + ir_send_msg_to_apptask(&bee_io_msg); +} + +/** + * @brief Stop ir learn function. + * @param None + * @return void + */ +static void ir_learn_exit(void) +{ + APP_PRINT_INFO0("[ir_learn_app]ir_learn_exit"); + + /* Close IR learn */ + ir_learn_deinit(); +} + +/** + * @brief IR learn timer callback. + * @param TimerHandle_t pxTimer. + * @return void. + * @note None. + */ +static void ir_learn_timer_callback(TimerHandle_t pxTimer) +{ + APP_PRINT_INFO0("[ir_learn_app]ir_learn_timer_callback: ir learn time out"); + ir_learn_exit(); + + //Add application code here!!! +} + +/** + * @brief ir learn timer init. + *@param void. + * @return void. + * @note none. +**/ +void ir_learn_timer_init(void) +{ + APP_PRINT_INFO0("[ir_learn_app]ir_learn_timer_init"); + /* IR_Learn_Timer is used for ir learn */ + if (false == os_timer_create(&IR_Learn_Timer, "ir_learn_timer", 1, \ + IR_LEARN_TIMEOUT, false, ir_learn_timer_callback)) + { + APP_PRINT_ERROR0("[ir_learn_app]ir_learn_timer_init: creat IR_Learn_Timer fail!"); + } +} + +/** +* @brief Application code for IR learn module init. +* @param No parameter. +* @return void +*/ +void ir_learn_module_init(void) +{ + APP_PRINT_INFO0("[ir_learn_app]ir_learn_module_init"); + if (true == os_timer_start(&IR_Learn_Timer)) + { + APP_PRINT_INFO0("[ir_learn_app]ir_learn_module_init: IR_Learn_Timer start success!"); + } + else + { + APP_PRINT_ERROR0("[ir_learn_app]ir_learn_module_init: IR_Learn_Timer start failed!"); + } + + board_ir_learn_init(); + /* Initialize IR learn data structure */ + memset(&IR_Learn_Packet, 0, sizeof(IR_Learn_TypeDef)); + ir_trans_rx_handler_cb(ir_learn_send_msg_from_isr); + ir_learn_init(); +} + +/** + * @brief Check if ir learn allow enter dlps. + * @param None + * @return bool: true working; + * false idle; + */ +bool ir_learn_check_dlps(void) +{ + return true; +} + +/** + * @brief Application code for IR learn data process. + * @param IR sub type msg. + * @return bool. + * true: specific msg can be handle; + * false: ir msg can not be handled. + */ +bool ir_learn_handle_msg(T_IO_MSG *io_ir_msg) +{ + bool ret = false; + uint16_t sub_type = io_ir_msg->subtype; + + if (sub_type == IO_MSG_TYPE_IR_LEARN_DATA) + { + IR_Learn_Status status = IR_LEARN_OK; + status = ir_learn_decode(&IR_Learn_Packet); + + if (status == IR_LEARN_EXCEED_SIZE) + { + APP_PRINT_WARN0("[ir_learn_app]ir_learn_handle_msg: IR learn exceed size!"); + /* Close IR learn */ + ir_learn_deinit(); + ret = false; + } + else if (status == IR_LEARN_EXIT) + { + APP_PRINT_WARN0("[ir_learn_app]ir_learn_handle_msg: IR learn stop time error!"); + /* Close IR learn */ + ir_learn_deinit(); + ret = false; + } + } + else if (sub_type == IO_MSG_TYPE_IR_LEARN_STOP) + { + /* Pick up the last ir data*/ + ir_learn_decode(&IR_Learn_Packet); + /* Decode IR carrier freqency */ + ir_learn_freq(&IR_Learn_Packet); + /* Data reduction */ + ir_learn_data_convert(&IR_Learn_Packet); + /* Print decode result */ +#ifdef IR_LEARN_DUTY_CYCLE_SUPPORT + APP_PRINT_INFO1("[ir_learn_app]ir_learn_handle_msg:IO_MSG_TYPE_IR_LEARN_STOP, duty_cycle: %d/1000.", + (uint32_t)(IR_Learn_Packet.duty_cycle * 1000)); +#endif + APP_PRINT_INFO1("[ir_learn_app]ir_learn_handle_msg:IO_MSG_TYPE_IR_LEARN_STOP, frequence: %d.", + (uint32_t)(IR_Learn_Packet.freq * 1000)); + APP_PRINT_INFO1("[ir_learn_app]ir_learn_handle_msg:IO_MSG_TYPE_IR_LEARN_STOP, learn data length: %d.", + IR_Learn_Packet.buf_index); + for (uint32_t i = 0; i < IR_Learn_Packet.buf_index; i++) + { + APP_PRINT_INFO2("[ir_learn_app]ir_learn_handle_msg:IO_MSG_TYPE_IR_LEARN_STOP,learn data%d: 0x%x.", + i, IR_Learn_Packet.ir_buf[i]); + } + ir_learn_exit(); + ret = true; + + // Add application code here!!! + ir_learn_module_init(); + } + return ret; +} + +#endif /* IR_FUN_EN && IR_FUN_LEARN_EN */ + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ diff --git a/src/sample/io_sample/IR/Learn/ir_learn_app.h b/src/sample/io_sample/IR/Learn/ir_learn_app.h new file mode 100644 index 0000000..c5212e4 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ir_learn_app.h @@ -0,0 +1,38 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_learn_app.h +* @brief +* @details +* @author elliot chen +* @date 2018-7-24 +* @version v1.0 +* ********************************************************************************************************* +*/ + +#ifndef __IR_LEARN_APP_H_ +#define __IR_LEARN_APP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "app_msg.h" + +#include "ir_learn.h" +#include "ir_learn_config.h" + +void ir_learn_timer_init(void); +void ir_learn_module_init(void); +bool ir_learn_handle_msg(T_IO_MSG *io_ir_msg); + +#ifdef __cplusplus +} +#endif + +#endif /*__IR_LEARN_APP_H_*/ + +/******************* (C) COPYRIGHT 2018Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/ir_learn_config.h b/src/sample/io_sample/IR/Learn/ir_learn_config.h new file mode 100644 index 0000000..4adc05c --- /dev/null +++ b/src/sample/io_sample/IR/Learn/ir_learn_config.h @@ -0,0 +1,54 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file ir_learn_config.h +* @brief ir learn configuration header file +* @details +* @author elliot chen +* @date 2017-11-16 +* @version v1.0 +********************************************************************************************************* +*/ + +#ifndef __IR_LEARN_CONFIG_H +#define __IR_LEARN_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Defines ------------------------------------------------------------------*/ + +/** + * @brief No carrier waveform maximum time is 6ms + */ +#define IR_LEARN_NO_WAVEFORM_TIME_MAX ((uint32_t)IR_LEARN_FREQ*6) +#define IR_LEARN_STOP_TIME (IR_LEARN_NO_WAVEFORM_TIME_MAX*0.95) + +/** + * @brief Enable IR duty cycle learning or not + */ +#define IR_LEARN_DUTY_CYCLE_SUPPORT +#define IR_LEARN_DUTY_CYCLE_SAMPLE_SIZE_MAX 6 + +/** + * @brief Enable filter IR freqency or not + */ +#define IR_LEARN_FREQ_FILTER_EN 1 +/** + * @brief Software adjustment for sending IR learn data + */ +#define IR_LEARN_SOFTWARE_ADJUST_EN 1 + + + + +#ifdef __cplusplus +} +#endif + +#endif /* !defined (__IR_LEARN_CONFIG_H) */ + +/******************* (C) COPYRIGHT 2017 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/led/ir_led.c b/src/sample/io_sample/IR/Learn/led/ir_led.c new file mode 100644 index 0000000..d04166f --- /dev/null +++ b/src/sample/io_sample/IR/Learn/led/ir_led.c @@ -0,0 +1,78 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file ir_led.c +* @brief This file provides led display for ir application code. +* @details +* @author yuan +* @date 2019-01-24 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "ir_led.h" + +#if (IR_FUN_EN && LED_IR_FUN_EN) + +/** + * @brief Initialization of pinmux settings and pad settings. + * @param No parameter. + * @return void + */ +void board_ir_led_init(void) +{ + Pad_Config(LED_IR_SEND_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, + PAD_OUT_HIGH); + Pinmux_Config(LED_IR_SEND_PIN, DWGPIO); +#if (IR_FUN_LEARN_EN) + Pad_Config(LED_IR_LEARN_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, + PAD_OUT_HIGH); + Pinmux_Config(LED_IR_LEARN_PIN, DWGPIO); +#endif +} + +/** + * @brief Initialize gpio peripheral. + * @param No parameter. + * @return void + */ +void driver_ir_led_init(void) +{ + /* Enable GPIO clock */ + RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE); + + /* Initialize GPIO */ + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_StructInit(&GPIO_InitStruct); +#if (IR_FUN_LEARN_EN) + GPIO_InitStruct.GPIO_Pin = LED_IR_SEND_OUT_PIN | LED_IR_LEARN_OUT_PIN; +#else + GPIO_InitStruct.GPIO_Pin = LED_IR_SEND_OUT_PIN; +#endif + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_Init(&GPIO_InitStruct); + + GPIO_ResetBits(LED_IR_SEND_OUT_PIN); +#if (IR_FUN_LEARN_EN) + GPIO_ResetBits(LED_IR_LEARN_OUT_PIN); +#endif +} + +void led_ir_send_swap(void) +{ + GPIO_WriteBit(LED_IR_SEND_OUT_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_IR_SEND_OUT_PIN))); +} + +#if (IR_FUN_LEARN_EN) +void led_ir_learn_swap(void) +{ + GPIO_WriteBit(LED_IR_LEARN_OUT_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_IR_LEARN_OUT_PIN))); +} +#endif /* IR_FUN_LEARN_EN */ + +#endif /* (IR_FUN_EN && LED_IR_FUN_EN) */ + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/led/ir_led.h b/src/sample/io_sample/IR/Learn/led/ir_led.h new file mode 100644 index 0000000..8755201 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/led/ir_led.h @@ -0,0 +1,51 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_led.h +* @brief +* @details +* @author yuan +* @date 2019-01-24 +* @version v1.0 +* ********************************************************************************************************* +*/ + +#ifndef __IR_LED_H +#define __IR_LED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "board.h" + +#if (IR_FUN_EN && LED_IR_FUN_EN) +#include "rtl876x_gpio.h" +#include "rtl876x_pinmux.h" +#include "rtl876x_rcc.h" + +/* Defines ------------------------------------------------------------------*/ +#define LED_IR_SEND_OUT_PIN GPIO_GetPin(LED_IR_SEND_PIN) +#if (IR_FUN_LEARN_EN) +#define LED_IR_LEARN_OUT_PIN GPIO_GetPin(LED_IR_LEARN_PIN) +#endif + +/* Function declaration --------------------------------------------------------*/ +void board_ir_led_init(void); +void driver_ir_led_init(void); +void led_ir_send_swap(void); +void led_ir_learn_swap(void); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*__IR_LED_H*/ + + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/trans/ir_driver_rx.c b/src/sample/io_sample/IR/Learn/trans/ir_driver_rx.c new file mode 100644 index 0000000..0c13a65 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/trans/ir_driver_rx.c @@ -0,0 +1,166 @@ +/** +********************************************************************************************************* +* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_driver_rx.c +* @brief This file provides demo code of ir. +* @details +* @author yuan +* @date 2018-12-07 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "ir_driver_rx.h" + +#include "ir_rx_loop_queue.h" + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + +/* Globals ------------------------------------------------------------------*/ +/* Function pointer used to send event to application from IR learn interrupt handler. */ +pFn_IR_RX_Handler_CB_t pFn_IR_RX_Handler_CB = NULL; + +/** + * @brief Initialization of pinmux settings and pad settings. + * @param No parameter. + * @return void + */ +void board_ir_rx_init(void) +{ + Pad_Config(IR_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW); + + Pinmux_Config(IR_RX_PIN, IRDA_RX); +} + + +/** + * @brief Initialize ir peripheral. + * @param No parameter. + * @return void + */ +void driver_ir_rx_init(void) +{ + /* Enable IR clock */ + RCC_PeriphClockCmd(APBPeriph_IR, APBPeriph_IR_CLOCK, DISABLE); + RCC_PeriphClockCmd(APBPeriph_IR, APBPeriph_IR_CLOCK, ENABLE); + + /* Initialize IR */ + IR_InitTypeDef IR_InitStruct; + IR_StructInit(&IR_InitStruct); + /* IR carrier freqency is 38KHz */ + IR_InitStruct.IR_Freq = IR_LEARN_FREQ; + /* Duty ratio = 1/IR_DutyCycle */ + IR_InitStruct.IR_DutyCycle = 2; + /* IR receiveing mode */ + IR_InitStruct.IR_Mode = IR_MODE_RX; + IR_InitStruct.IR_RxStartMode = IR_RX_AUTO_MODE; + /* Configure RX FIFO threshold level to trigger IR_INT_RF_LEVEL interrupt */ + IR_InitStruct.IR_RxFIFOThrLevel = IR_RX_FIFO_THR_LEVEL; + /* Discard the latest received dta if RX FIFO is full */ + IR_InitStruct.IR_RxFIFOFullCtrl = IR_RX_FIFO_FULL_DISCARD_NEWEST; + /* Configure trigger type */ + IR_InitStruct.IR_RxTriggerMode = IR_RX_FALL_EDGE; + /* If high to low or low to high transition time <= 50ns,Filter out it. */ + IR_InitStruct.IR_RxFilterTime = IR_RX_FILTER_TIME_200ns; + /* IR_RX_Count_Low_Level is counting low level */ + IR_InitStruct.IR_RxCntThrType = IR_RX_Count_High_Level; + /* Configure RX counter threshold.You can use it to decide to stop receiving IR data */ + IR_InitStruct.IR_RxCntThr = IR_LEARN_NO_WAVEFORM_TIME_MAX; + IR_Init(&IR_InitStruct); + + IR_Cmd(IR_MODE_RX, ENABLE); + IR_ClearRxFIFO(); + + IR_INTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE); + IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); + + /* Configure NVIC */ + NVIC_InitTypeDef NVIC_InitStruct; + NVIC_InitStruct.NVIC_IRQChannel = IR_IRQn; + NVIC_InitStruct.NVIC_IRQChannelPriority = 2; + NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStruct); +} + +/** + * @brief Enables or disables the specified interrupt. + * @param NewState: new state of the specified interrupt. + * This parameter can be: ENABLE or DISABLE. + * @retval None. + */ +void int_ir_rx_config(FunctionalState state) +{ + if (state != DISABLE) + { + /* Enable interrupt */ + IR_INTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE); + } + else + { + /* Disable interrupt */ + IR_INTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); + } +} + +/** + * @brief Register callback function to send events from IR learn interrupt handle to application layer. + * @param pFunc: callback function. + * @return void + */ +void ir_rx_handler_cb(pFn_IR_RX_Handler_CB_t pFunc) +{ + pFn_IR_RX_Handler_CB = pFunc; +} + +/** + * @brief IR interrupt handler function. + * @param No parameter. + * @return void + */ +void IR_RX_Handler(void) +{ + uint16_t data_len = 0; + uint8_t ir_learn_end_flag = false; + ITStatus int_status_rfl = IR_GetINTStatus(IR_INT_RF_LEVEL); + ITStatus int_status_rxcnt = IR_GetINTStatus(IR_INT_RX_CNT_THR); + + /* Mask IR all interrupt */ + IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE); + + /* Received interrupt */ + if (int_status_rfl == SET) + { + data_len = IR_GetRxDataLen(); + ir_loop_queue_data_in(&IR_RX_Queue, data_len); + IR_ClearINTPendingBit(IR_INT_RF_LEVEL_CLR); + } + + /* Stop to receive IR data */ + if (int_status_rxcnt == SET) + { + /* Read remaining data */ + data_len = IR_GetRxDataLen(); + ir_loop_queue_data_in(&IR_RX_Queue, data_len); + IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR); + + /* Send ir learn end signal. */ + //Add application code here + ir_learn_end_flag = true; + } + + if (pFn_IR_RX_Handler_CB) + { + pFn_IR_RX_Handler_CB(ir_learn_end_flag); + } + + /* Unmask IR all interrupt */ + IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); + +} + +#endif + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/trans/ir_driver_rx.h b/src/sample/io_sample/IR/Learn/trans/ir_driver_rx.h new file mode 100644 index 0000000..edb9610 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/trans/ir_driver_rx.h @@ -0,0 +1,64 @@ +/** +********************************************************************************************************* +* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_driver_rx.h +* @brief +* @details +* @author yuan +* @date 2019-01-23 +* @version v1.0 +* ********************************************************************************************************* +*/ + +#ifndef __IR_DRIVER_RX_H +#define __IR_DRIVER_RX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include <string.h> + +#include "rtl876x_ir.h" +#include "rtl876x_nvic.h" +#include "rtl876x_pinmux.h" +#include "rtl876x_rcc.h" + +#include "board.h" + +#include "trace.h" + +#include "app_msg.h" + +#include "ir_learn_config.h" + + +/** @defgroup pFn_IR_RX_Handler_CB + * @brief Function pointer type used by IR learn interrupt handle to general callback and send events to application. + * @{ + */ +typedef void (*pFn_IR_RX_Handler_CB_t)(uint8_t vFlag); +/** + * @} End of pFn_IR_RX_Handler_CB + */ +extern pFn_IR_RX_Handler_CB_t pFn_IR_RX_Handler_CB; + + +void board_ir_rx_init(void); +void driver_ir_rx_init(void); +void int_ir_rx_config(FunctionalState state); +void ir_rx_handler_cb(pFn_IR_RX_Handler_CB_t pFunc); +void IR_Handler(void); +void IR_RX_Handler(void); + + +#ifdef __cplusplus +} +#endif + +#endif /*__IR_DRIVER_RX_H*/ + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/trans/ir_rx_loop_queue.c b/src/sample/io_sample/IR/Learn/trans/ir_rx_loop_queue.c new file mode 100644 index 0000000..6a06677 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/trans/ir_rx_loop_queue.c @@ -0,0 +1,234 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file ir_rx_loop_queue.c +* @brief +* @details +* @author yuan +* @date 2019-01-23 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "ir_rx_loop_queue.h" + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + +/* Globals ------------------------------------------------------------------ */ +/* Loop queue management data structure */ +IR_LoopQueue_TypeDef IR_RX_Queue; + + +/* Functions ------------------------------------------------------------------*/ + +/** + * @brief Initializes loop queue to their default reset values. + * @param pPacket: point to loop queue data structure. + * @retval None + */ +void ir_loop_queue_init(IR_LoopQueue_TypeDef *pLoopQueue) +{ + memset(pLoopQueue, 0, sizeof(IR_LoopQueue_TypeDef)); +} + +/** + * @brief check loop queue if will full or not. + * @param pLoopQueue: point to loop queue dta struct. + * @retval The new state of loop queue (full:TRUE, not full:FALSE). + */ +bool ir_loop_queue_is_full(IR_LoopQueue_TypeDef *pLoopQueue, uint16_t vLength) +{ + /* Check loop queue status */ + if (pLoopQueue->InQueueIndex >= pLoopQueue->OutQueueIndex) + { + if ((pLoopQueue->InQueueIndex + vLength) >= (LOOP_QUEUE_BUF_SIZE_MAX + pLoopQueue->OutQueueIndex)) + { + IR_RX_DBG_BUFFER(MODULE_APP, LEVEL_ERROR, + "[ir_trans_rx]loop_queue_is_full: Loop Queue is overflow!", 0); + pLoopQueue->IsOverFlow = true; + return true; + } + } + else + { + if ((pLoopQueue->InQueueIndex + vLength) >= pLoopQueue->OutQueueIndex) + { + IR_RX_DBG_BUFFER(MODULE_APP, LEVEL_ERROR, + "[ir_trans_rx]loop_queue_is_full: Loop Queue is overflow!", 0); + pLoopQueue->IsOverFlow = true; + return true; + } + } + return false; +} + +/** + * @brief Check loop queue if empty or not. + * @param pLoopQueue: point to IR packet struct. + * @retval The new state of loop queue (empty:true, not empty:false). + */ +bool ir_loop_queue_is_empty(IR_LoopQueue_TypeDef *pLoopQueue) +{ + return ((pLoopQueue->InQueueIndex) == pLoopQueue->OutQueueIndex); +} + +/** + * @brief Get valid data length. + * @param pLoopQueue: + * @retval valid data length + */ +uint16_t ir_loop_queue_get_data_len(IR_LoopQueue_TypeDef *pLoopQueue) +{ + return ((LOOP_QUEUE_BUF_SIZE_MAX + pLoopQueue->InQueueIndex - pLoopQueue->OutQueueIndex) & + LOOP_QUEUE_CAPABILITY); +} + +/** + * @brief Write buffer data to loop queue. + * @param None. + * @retval None. + */ +void ir_loop_queue_data_in(IR_LoopQueue_TypeDef *pLoopQueue, uint8_t vLen) +{ + uint8_t tail_data_len = 0; + + if (!ir_loop_queue_is_full(pLoopQueue, vLen)) + { + if (pLoopQueue->InQueueIndex + vLen <= LOOP_QUEUE_BUF_SIZE_MAX) + { + IR_ReceiveBuf(&(pLoopQueue->LoopQueueBuf[pLoopQueue->InQueueIndex]), vLen); + pLoopQueue->InQueueIndex += vLen; + } + else + { + tail_data_len = LOOP_QUEUE_BUF_SIZE_MAX - pLoopQueue->InQueueIndex; + IR_ReceiveBuf(&(pLoopQueue->LoopQueueBuf[pLoopQueue->InQueueIndex]), tail_data_len); + pLoopQueue->InQueueIndex = 0; + IR_ReceiveBuf(&(pLoopQueue->LoopQueueBuf[pLoopQueue->InQueueIndex]), vLen - tail_data_len); + pLoopQueue->InQueueIndex += (vLen - tail_data_len); + } + pLoopQueue->InQueueIndex &= LOOP_QUEUE_CAPABILITY; + } + else + { + /* Discard data. Actually IR maximum rx FIFO is 32, vLen <= 32. */ + uint8_t discard_data_len = 0; + uint32_t discard_buf[32]; + while (vLen) + { + discard_data_len = (vLen > 32) ? 32 : vLen; + IR_ReceiveBuf(discard_buf, discard_data_len); + vLen -= discard_data_len; + } + IR_RX_DBG_BUFFER(MODULE_APP, LEVEL_INFO, "[ir_trans_rx]loop_queue_data_in: Discard bytes = %d!", + 1, vLen); + } +} + +/** + * @brief Read data from loop queue. + * @param None. + * @retval None. + */ +void ir_loop_queue_data_out(IR_LoopQueue_TypeDef *pLoopQueue, uint32_t *pBuf, uint16_t vLen) +{ + uint16_t remain_data_len = 0; + uint16_t temp = 0; + + /* Check parameters */ + if ((vLen == 0) || (pBuf == NULL)) + { + return; + } + + if (pLoopQueue->InQueueIndex + vLen <= LOOP_QUEUE_BUF_SIZE_MAX) + { +#ifdef LOOP_QUEUE_USE_MEMCPY_FUNCTION + memcpy(pBuf, &(pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex]), vLen * sizeof(uint32_t)); + pLoopQueue->OutQueueIndex += vLen; +#else + while (vLen--) + { + *pBuf++ = pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex++]; + } +#endif + } + else + { +#ifdef LOOP_QUEUE_USE_MEMCPY_FUNCTION + remain_data_len = LOOP_QUEUE_BUF_SIZE_MAX - pLoopQueue->OutQueueIndex; + memcpy(pBuf, &(pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex]), + remain_data_len * sizeof(uint32_t)); + pLoopQueue->OutQueueIndex = 0; + memcpy(pBuf + remain_data_len, &(pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex]), + (vLen - remain_data_len)*sizeof(uint32_t)); +#else + remain_data_len = LOOP_QUEUE_BUF_SIZE_MAX - pLoopQueue->OutQueueIndex; + temp = remain_data_len; + while (temp--) + { + *pBuf++ = pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex++]; + } + pLoopQueue->OutQueueIndex = 0; + temp = vLen - remain_data_len; + while (temp--) + { + *pBuf++ = pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex++]; + } + +#endif + } + temp += 0; + pLoopQueue->OutQueueIndex &= LOOP_QUEUE_CAPABILITY; +} + +/** + * @brief Copy data from loop queue. + * @param None. + * @retval None. + */ +void ir_loop_queue_data_copy(IR_LoopQueue_TypeDef *pLoopQueue, uint32_t *pBuf, uint16_t vLen) +{ + uint16_t remain_data_len = 0; + uint16_t index = 0; + + /* Check parameters */ + if ((vLen == 0) || (pBuf == NULL)) + { + return; + } + + if (pLoopQueue->OutQueueIndex + vLen <= LOOP_QUEUE_BUF_SIZE_MAX) + { + index = 0; + while (vLen--) + { + *pBuf++ = pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex + index]; + index++; + } + } + else + { + remain_data_len = LOOP_QUEUE_BUF_SIZE_MAX - pLoopQueue->OutQueueIndex; + uint16_t i = remain_data_len; + index = 0; + while (i--) + { + *pBuf++ = pLoopQueue->LoopQueueBuf[pLoopQueue->OutQueueIndex + index]; + index++; + } + + i = vLen - remain_data_len; + index = 0; + while (i--) + { + *pBuf++ = pLoopQueue->LoopQueueBuf[index++]; + } + } +} + +#endif + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ diff --git a/src/sample/io_sample/IR/Learn/trans/ir_rx_loop_queue.h b/src/sample/io_sample/IR/Learn/trans/ir_rx_loop_queue.h new file mode 100644 index 0000000..f4050e5 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/trans/ir_rx_loop_queue.h @@ -0,0 +1,76 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_rx_loop_queue.h +* @brief ir rx data loop queue +* @details +* @author yuan +* @date 2019-01-23 +* @version v1.0 +* ********************************************************************************************************* +*/ + +#ifndef __IR_RX_LOOP_QUEUE_H +#define __IR_RX_LOOP_QUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +#include "board.h" + + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) +#include <string.h> + +#include "rtl876x_ir.h" + +#include "trace.h" + +/* Defines ------------------------------------------------------------------*/ +#ifdef IR_RX_PRINT_LOG +#define IR_RX_DBG_BUFFER(module, level, fmt, param_num,...) \ + DBG_BUFFER_##level(TYPE_BUMBLEBEE3, SUBTYPE_FORMAT, module, fmt, param_num, ##__VA_ARGS__) +#else +#define IR_RX_DBG_BUFFER(MODULE, LEVEL, pFormat, para_num,...) ((void)0) +#endif + +/** + * @brief IR loop queue parameters + */ +#define LOOP_QUEUE_USE_MEMCPY_FUNCTION 0 + +#define LOOP_QUEUE_BUF_SIZE_MAX (1024) +#define LOOP_QUEUE_CAPABILITY (LOOP_QUEUE_BUF_SIZE_MAX-1) + +typedef struct +{ + volatile uint16_t InQueueIndex; /* index of in queue */ + volatile uint16_t OutQueueIndex; /* index of out queue */ + uint32_t LoopQueueBuf[LOOP_QUEUE_BUF_SIZE_MAX]; + bool IsOverFlow; +} IR_LoopQueue_TypeDef; + +extern IR_LoopQueue_TypeDef IR_RX_Queue; + +void ir_loop_queue_init(IR_LoopQueue_TypeDef *pLoopQueue); +bool ir_loop_queue_is_full(IR_LoopQueue_TypeDef *pLoopQueue, uint16_t vLength); +bool ir_loop_queue_is_empty(IR_LoopQueue_TypeDef *pLoopQueue); +uint16_t ir_loop_queue_get_data_len(IR_LoopQueue_TypeDef *pLoopQueue); +void ir_loop_queue_data_in(IR_LoopQueue_TypeDef *pLoopQueue, uint8_t vLen); +void ir_loop_queue_data_out(IR_LoopQueue_TypeDef *pLoopQueue, uint32_t *pBuf, uint16_t vLen); +void ir_loop_queue_data_copy(IR_LoopQueue_TypeDef *pLoopQueue, uint32_t *pBuf, uint16_t vLen); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __IR_RX_LOOP_QUEUE_H */ + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + diff --git a/src/sample/io_sample/IR/Learn/trans/ir_trans_rx.c b/src/sample/io_sample/IR/Learn/trans/ir_trans_rx.c new file mode 100644 index 0000000..4f90a2b --- /dev/null +++ b/src/sample/io_sample/IR/Learn/trans/ir_trans_rx.c @@ -0,0 +1,153 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************** +* @file ir_trans_rx.c +* @brief +* @details +* @author yuan +* @date 2019-01-23 +* @version v1.0 +********************************************************************************************************* +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "ir_trans_rx.h" + +#if (IR_FUN_EN && IR_FUN_LEARN_EN) + +/** + * @brief Deinitializes data transmission layer. + * @param None. + * @retval None + */ +void ir_trans_rx_deinit(void) +{ + /* Initialize loop queue */ + ir_loop_queue_init(&IR_RX_Queue); + + /* Close IR peripheral */ + IR_Cmd(IR_MODE_RX, DISABLE); + + /* Modify IR interrupt handle */ + RamVectorTableUpdate(IR_VECTORn, IR_Handler); +} + +/** + * @brief Initializes data transmission layer. + * @param None. + * @retval None + */ +void ir_trans_rx_init(void) +{ + /* Initialize loop queue */ + ir_loop_queue_init(&IR_RX_Queue); + + /* Modify IR interrupt handle */ + RamVectorTableUpdate(IR_VECTORn, IR_RX_Handler); + + /* Initialize IR peripheral */ + driver_ir_rx_init(); +} + +/** + * @brief Initializes loop queue. + * @param None + * @retval None + */ +void ir_trans_rx_queue_init(void) +{ + ir_loop_queue_init(&IR_RX_Queue); +} + +/** + * @brief Check loop queue is empty or not. + * @param None. + * @retval status of loop queue.: + TRUE: loop queue is empty. + FALSE: loop queue is not empty. + */ +bool ir_trans_rx_queue_is_empty(void) +{ + return ir_loop_queue_is_empty(&IR_RX_Queue); +} + +/** + * @brief Get valid data length. + * @param None. + * @retval loop queue length + */ +uint16_t ir_trans_rx_get_data_len(void) +{ + return ir_loop_queue_get_data_len(&IR_RX_Queue); +} + +/** + * @brief Read data from loop queue. + * @param pBuf: point to address of buffer. + * @param vLen: data length. + * @retval None. + */ +void ir_trans_rx_read_data(uint32_t *pBuf, uint16_t vLen) +{ + ir_loop_queue_data_out(&IR_RX_Queue, pBuf, vLen); +} + +/** + * @brief copy data from loop queue. + * @param pBuf: point to address of buffer. + * @param vLen: data length. + * @retval None. + */ +void ir_trans_rx_copy_data(uint32_t *pBuf, uint16_t vLen) +{ + ir_loop_queue_data_copy(&IR_RX_Queue, pBuf, vLen); +} + +/** + * @brief Find special data in loop queue. + * @param vData: Find data. + * @param vLen: data length in loop queue. + * @retval actual data position in loop queue. + */ +uint16_t ir_trans_rx_find_data_pos(uint32_t vData, uint16_t vLen) +{ + uint16_t pos = IR_RX_Queue.OutQueueIndex; + + while (vLen--) + { + pos &= LOOP_QUEUE_CAPABILITY; + + if (vData == IR_RX_Queue.LoopQueueBuf[pos++]) + { + return (pos + LOOP_QUEUE_BUF_SIZE_MAX - IR_RX_Queue.OutQueueIndex) & LOOP_QUEUE_CAPABILITY; + } + } + + return 0; +} + +/** + * @brief Enables or disables the specified interrupt. + * @param NewState: new state of the specified interrupt. + * This parameter can be: ENABLE or DISABLE. + * @retval None. + */ +void ir_trans_rx_int_config(FunctionalState state) +{ + int_ir_rx_config(state); +} + +/** + * @brief Register callback function to send events from IR learn interrupt handle to application layer. + * @param pFunc: callback function. + * @return void +*/ +void ir_trans_rx_handler_cb(pFn_IR_RX_Handler_CB_t pFunc) +{ + ir_rx_handler_cb(pFunc); +} + +#endif + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ diff --git a/src/sample/io_sample/IR/Learn/trans/ir_trans_rx.h b/src/sample/io_sample/IR/Learn/trans/ir_trans_rx.h new file mode 100644 index 0000000..cdb54a0 --- /dev/null +++ b/src/sample/io_sample/IR/Learn/trans/ir_trans_rx.h @@ -0,0 +1,43 @@ +/** +********************************************************************************************************* +* Copyright(c) 2019, Realtek Semiconductor Corporation. All rights reserved. +********************************************************************************************************* +* @file ir_trans_rx.h +* @brief data transmission layer driver +* @details +* @author yuan +* @date 2019-01-23 +* @version v1.0 +* ********************************************************************************************************* +*/ +#ifndef __IR_TRANS_RX_H +#define __IR_TRANS_RX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "ir_driver_rx.h" +#include "ir_rx_loop_queue.h" + + +void ir_trans_rx_deinit(void); +void ir_trans_rx_init(void); +void ir_trans_rx_queue_init(void); +bool ir_trans_rx_queue_is_empty(void); +uint16_t ir_trans_rx_get_data_len(void); +void ir_trans_rx_read_data(uint32_t *pBuf, uint16_t vLen); +void ir_trans_rx_copy_data(uint32_t *pBuf, uint16_t vLen); +uint16_t ir_trans_rx_find_data_pos(uint32_t vData, uint16_t vLen); +void ir_trans_rx_int_config(FunctionalState state); +void ir_trans_rx_handler_cb(pFn_IR_RX_Handler_CB_t pFunc); + +#ifdef __cplusplus +} +#endif + +#endif /*__IR_TRANS_RX_H*/ + +/******************* (C) COPYRIGHT 2019 Realtek Semiconductor Corporation *****END OF FILE****/ + |