aboutsummaryrefslogtreecommitdiff
path: root/src/sample/io_sample/SPI/Flash
diff options
context:
space:
mode:
Diffstat (limited to 'src/sample/io_sample/SPI/Flash')
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/ancs.c662
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/ancs.h259
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/app.c608
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/app.h72
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/app_flags.h40
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/app_task.c123
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/app_task.h47
-rw-r--r--src/sample/io_sample/SPI/Flash/ble_peripheral/main.c245
-rw-r--r--src/sample/io_sample/SPI/Flash/io_spi.c124
-rw-r--r--src/sample/io_sample/SPI/Flash/io_spi.h41
-rw-r--r--src/sample/io_sample/SPI/Flash/spi_flash.c303
-rw-r--r--src/sample/io_sample/SPI/Flash/spi_flash.h68
12 files changed, 2592 insertions, 0 deletions
diff --git a/src/sample/io_sample/SPI/Flash/ble_peripheral/ancs.c b/src/sample/io_sample/SPI/Flash/ble_peripheral/ancs.c
new file mode 100644
index 0000000..ac3254e
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/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>&copy; 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/SPI/Flash/ble_peripheral/ancs.h b/src/sample/io_sample/SPI/Flash/ble_peripheral/ancs.h
new file mode 100644
index 0000000..68ec35b
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/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/SPI/Flash/ble_peripheral/app.c b/src/sample/io_sample/SPI/Flash/ble_peripheral/app.c
new file mode 100644
index 0000000..8649e55
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/ble_peripheral/app.c
@@ -0,0 +1,608 @@
+/**
+*****************************************************************************************
+* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved.
+*****************************************************************************************
+ * @file peripheral_app.c
+ * @brief This file handles BLE peripheral application routines.
+ * @author jane
+ * @date 2017-06-06
+ * @version v1.0
+ **************************************************************************************
+ * @attention
+ * <h2><center>&copy; COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2>
+ **************************************************************************************
+ */
+
+/*============================================================================*
+ * Header Files
+ *============================================================================*/
+#include <string.h>
+
+#include <gap.h>
+#include <gap_adv.h>
+#include <gap_bond_le.h>
+#include <gap_conn_le.h>
+#include <gap_msg.h>
+#if F_BT_ANCS_CLIENT_SUPPORT
+#include <ancs_client.h>
+#include "ancs.h"
+#endif
+#include <bas.h>
+#include <simple_ble_service.h>
+
+#include "trace.h"
+
+#include "app.h"
+#include "io_spi.h"
+
+/** @defgroup PERIPH_APP Peripheral Application
+ * @brief This file handles BLE peripheral application routines.
+ * @{
+ */
+
+/*============================================================================*
+ * Variables
+ *============================================================================*/
+/** @addtogroup PERIPH_SEVER_CALLBACK Profile Server Callback Event Handler
+ * @brief Handle profile server callback event
+ * @{
+ */
+T_SERVER_ID simp_srv_id; /**< Simple ble service id*/
+T_SERVER_ID bas_srv_id; /**< Battery service id */
+/** @} */ /* End of group PERIPH_SEVER_CALLBACK */
+
+/** @defgroup PERIPH_GAP_MSG GAP Message Handler
+ * @brief Handle GAP Message
+ * @{
+ */
+T_GAP_DEV_STATE gap_dev_state = {0, 0, 0, 0}; /**< GAP device state */
+T_GAP_CONN_STATE gap_conn_state = GAP_CONN_STATE_DISCONNECTED; /**< GAP connection state */
+
+/*============================================================================*
+ * Functions
+ *============================================================================*/
+void app_handle_gap_msg(T_IO_MSG *p_gap_msg);
+
+/**
+ * @brief All the application messages are pre-handled in this function
+ * @note All the IO MSGs are sent to this function, then the event handling
+ * function shall be called according to the MSG type.
+ * @param[in] io_msg IO message data
+ * @return void
+ */
+void app_handle_io_msg(T_IO_MSG io_msg)
+{
+ uint16_t msg_type = io_msg.type;
+
+ switch (msg_type)
+ {
+ case IO_MSG_TYPE_BT_STATUS:
+ {
+ app_handle_gap_msg(&io_msg);
+ }
+ break;
+#if F_BT_ANCS_CLIENT_SUPPORT
+ case IO_MSG_TYPE_ANCS:
+ {
+ ancs_handle_msg(&io_msg);
+ }
+ break;
+#endif
+ case IO_MSG_TYPE_SPI:
+ {
+ APP_PRINT_INFO0("[app] app_handle_io_msg: spi msg.");
+ //Add user code here!
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief Handle msg GAP_MSG_LE_DEV_STATE_CHANGE
+ * @note All the gap device state events are pre-handled in this function.
+ * Then the event handling function shall be called according to the new_state
+ * @param[in] new_state New gap device state
+ * @param[in] cause GAP device state change cause
+ * @return void
+ */
+void app_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause)
+{
+ APP_PRINT_INFO3("app_handle_dev_state_evt: init state %d, adv state %d, cause 0x%x",
+ new_state.gap_init_state, new_state.gap_adv_state, cause);
+ if (gap_dev_state.gap_init_state != new_state.gap_init_state)
+ {
+ if (new_state.gap_init_state == GAP_INIT_STATE_STACK_READY)
+ {
+ APP_PRINT_INFO0("GAP stack ready");
+ /*stack ready*/
+// le_adv_start();
+ spi_demo();
+ }
+ }
+
+ 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/SPI/Flash/ble_peripheral/app.h b/src/sample/io_sample/SPI/Flash/ble_peripheral/app.h
new file mode 100644
index 0000000..8aed00b
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/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>&copy; 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/SPI/Flash/ble_peripheral/app_flags.h b/src/sample/io_sample/SPI/Flash/ble_peripheral/app_flags.h
new file mode 100644
index 0000000..3371839
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/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>&copy; 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/SPI/Flash/ble_peripheral/app_task.c b/src/sample/io_sample/SPI/Flash/ble_peripheral/app_task.c
new file mode 100644
index 0000000..635c4c3
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/ble_peripheral/app_task.c
@@ -0,0 +1,123 @@
+/**
+*****************************************************************************************
+* Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved.
+*****************************************************************************************
+ * @file app_task.c
+ * @brief Routines to create App task and handle events & messages
+ * @author jane
+ * @date 2017-06-02
+ * @version v1.0
+ **************************************************************************************
+ * @attention
+ * <h2><center>&copy; 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/SPI/Flash/ble_peripheral/app_task.h b/src/sample/io_sample/SPI/Flash/ble_peripheral/app_task.h
new file mode 100644
index 0000000..5d5918a
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/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>&copy; 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/SPI/Flash/ble_peripheral/main.c b/src/sample/io_sample/SPI/Flash/ble_peripheral/main.c
new file mode 100644
index 0000000..a12dc8a
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/ble_peripheral/main.c
@@ -0,0 +1,245 @@
+/**
+*****************************************************************************************
+* 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>&copy; COPYRIGHT 2017 Realtek Semiconductor Corporation</center></h2>
+**************************************************************************************
+*/
+
+/*============================================================================*
+ * Header Files
+ *============================================================================*/
+#include <string.h>
+#include <stdlib.h>
+#include <gap.h>
+#include <gap_adv.h>
+#include <gap_bond_le.h>
+#include <gap_msg.h>
+#include <bas.h>
+#include <simple_ble_service.h>
+
+#if F_BT_ANCS_CLIENT_SUPPORT
+#include <profile_client.h>
+#include "ancs.h"
+#endif
+
+#include "trace.h"
+
+#include "app.h"
+#include "app_task.h"
+#include "app_flags.h"
+
+#include "io_spi.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)
+{
+ board_spi_init();
+}
+
+/**
+ * @brief Contains the initialization of peripherals
+ * @note Both new architecture driver and legacy driver initialization method can be used
+ * @return void
+ */
+void driver_init(void)
+{
+ driver_spi_init();
+}
+
+/**
+ * @brief Contains the power mode settings
+ * @return void
+ */
+void pwr_mgr_init(void)
+{
+}
+
+/**
+ * @brief Contains the initialization of all tasks
+ * @note There is only one task in BLE Peripheral APP, thus only one APP task is init here
+ * @return void
+ */
+void task_init(void)
+{
+ app_task_init();
+}
+
+/**
+ * @brief Entry of APP code
+ * @return int (To avoid compile warning)
+ */
+int main(void)
+{
+ extern uint32_t random_seed_value;
+ srand(random_seed_value);
+ global_data_init();
+ board_init();
+ le_gap_init(APP_MAX_LINKS);
+ gap_lib_init();
+ app_le_gap_init();
+ app_le_profile_init();
+ pwr_mgr_init();
+ task_init();
+ os_sched_start();
+
+ return 0;
+}
+/** @} */ /* End of group PERIPH_DEMO_MAIN */
+
+
diff --git a/src/sample/io_sample/SPI/Flash/io_spi.c b/src/sample/io_sample/SPI/Flash/io_spi.c
new file mode 100644
index 0000000..508d29c
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/io_spi.c
@@ -0,0 +1,124 @@
+/**
+*********************************************************************************************************
+* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved.
+*********************************************************************************************************
+* @file io_spi.c
+* @brief This file provides demo code of spi master.
+ GD25Q128E is slave.
+ Read the chip id of GD25Q128E.
+* @details
+* @author yuan
+* @date 2018-12-07
+* @version v1.0
+*********************************************************************************************************
+*/
+
+/* Includes ------------------------------------------------------------------*/
+#include "io_spi.h"
+
+#include "spi_flash.h"
+#include "app_task.h"
+
+
+/**
+ * @brief Initialization of pinmux settings and pad settings.
+ * @param No parameter.
+ * @return void
+*/
+void board_spi_init(void)
+{
+ Pad_Config(SPI0_SCK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
+ Pad_Config(SPI0_MOSI_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
+ Pad_Config(SPI0_MISO_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
+ Pad_Config(SPI0_CS_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
+
+ Pinmux_Deinit(P4_0);
+ Pinmux_Deinit(P4_1);
+ Pinmux_Deinit(P4_2);
+ Pinmux_Deinit(P4_3);
+
+ Pinmux_Config(SPI0_SCK_PIN, SPI0_CLK_MASTER);
+ Pinmux_Config(SPI0_MOSI_PIN, SPI0_MO_MASTER);
+ Pinmux_Config(SPI0_MISO_PIN, SPI0_MI_MASTER);
+ Pinmux_Config(SPI0_CS_PIN, SPI0_SS_N_0_MASTER);
+}
+
+/**
+ * @brief Initialize spi peripheral.
+ * @param No parameter.
+ * @return void
+ */
+//void SPI_InitConfiguration(void)
+//{
+// SPI_InitTypeDef SPI_InitStructure;
+
+// SPI_StructInit(&SPI_InitStructure);
+// SPI_InitStructure.SPI_Direction = SPI_Direction_EEPROM;
+// SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
+// SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
+// SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
+// SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
+// SPI_InitStructure.SPI_BaudRatePrescaler = 16;
+// SPI_InitStructure.SPI_RxThresholdLevel = 8;
+// SPI_InitStructure.SPI_FrameFormat = SPI_Frame_Motorola;
+// SPI_InitStructure.SPI_NDF = 0;
+// SPI_Init(SPI0, &SPI_InitStructure);
+
+// SPI_Cmd(SPI0, ENABLE);
+//}
+
+void driver_spi_init(void)
+{
+ RCC_PeriphClockCmd(APBPeriph_SPI0, APBPeriph_SPI0_CLOCK, ENABLE);
+
+ SPI_InitTypeDef SPI_InitStruct;
+ SPI_StructInit(&SPI_InitStruct);
+
+ SPI_InitStruct.SPI_Direction = SPI_Direction_FullDuplex;
+ SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
+ SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
+ SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
+ SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
+ SPI_InitStruct.SPI_BaudRatePrescaler = 20;
+ /* SPI_Direction_EEPROM mode read data length. */
+ SPI_InitStruct.SPI_RxThresholdLevel = 1;/* Flash id length = 3*/
+ SPI_InitStruct.SPI_NDF = 0;/* Flash id length = 3*/
+ SPI_InitStruct.SPI_FrameFormat = SPI_Frame_Motorola;
+ SPI_Init(SPI0, &SPI_InitStruct);
+
+ SPI_Cmd(SPI0, ENABLE);
+
+}
+
+/**
+ * @brief Demo code of operation about spi.
+ * @param No parameter.
+ * @return void
+*/
+void spi_demo(void)
+{
+ uint8_t flash_id[10] = {0};
+ uint8_t write_data[100];
+ uint8_t read_data[105] = {0};
+ for (uint16_t i = 0; i < 100; i++)
+ {
+ write_data[i] = i & 0xFF;
+ }
+
+ spi_flash_read_id(flash_id);
+ APP_PRINT_INFO1("[io_spi] spi_demo: flash_id = %b ", TRACE_BINARY(3, flash_id));
+
+ spi_flash_sector_erase(0x001000);
+ APP_PRINT_INFO0("[io_spi] spi_demo: spi_flash_sector_erase done");
+
+ spi_flash_read(SPI_FLASH_FAST_READ, 0x001000, read_data, 100);
+// APP_PRINT_INFO1("[io_spi] spi_demo: read_data = %b,", TRACE_BINARY(100, &read_data[5]));
+ APP_PRINT_INFO1("[io_spi] spi_demo: read_data = %b,", TRACE_BINARY(100, read_data));
+
+ spi_flash_page_write(0x001000, write_data, 100);
+
+ spi_flash_read(SPI_FLASH_FAST_READ, 0x001000, read_data, 100);
+ APP_PRINT_INFO1("[io_spi] spi_demo: read_data = %b,", TRACE_BINARY(100, read_data));
+}
+
+
diff --git a/src/sample/io_sample/SPI/Flash/io_spi.h b/src/sample/io_sample/SPI/Flash/io_spi.h
new file mode 100644
index 0000000..669d128
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/io_spi.h
@@ -0,0 +1,41 @@
+/**
+*********************************************************************************************************
+* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved.
+*********************************************************************************************************
+* @file io_spi.h
+* @brief
+* @details
+* @author yuan
+* @date 2018-12-07
+* @version v1.0
+*********************************************************************************************************
+*/
+
+#ifndef __IO_SPI_H
+#define __IO_SPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "rtl876x_nvic.h"
+#include "rtl876x_pinmux.h"
+#include "rtl876x_rcc.h"
+#include "rtl876x_spi.h"
+
+#include "board.h"
+
+#include "app_msg.h"
+
+void board_spi_init(void);
+void driver_spi_init(void);
+void spi_demo(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/sample/io_sample/SPI/Flash/spi_flash.c b/src/sample/io_sample/SPI/Flash/spi_flash.c
new file mode 100644
index 0000000..c159596
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/spi_flash.c
@@ -0,0 +1,303 @@
+/**
+*********************************************************************************************************
+* Copyright(c) 2015, Realtek Semiconductor Corporation. All rights reserved.
+**********************************************************************************************************
+* @file main.c
+* @brief This file provides demo code of spi write and ead data from GD25Q128E flash.
+* @details
+* @author yuan
+* @date 2019-07-10
+* @version v1.0
+*********************************************************************************************************
+*/
+#include "spi_flash.h"
+#include "io_spi.h"
+#include "trace.h"
+#include <string.h>
+
+
+void spi_flash_read_id(uint8_t *pFlashId)
+{
+ uint8_t send_buf[4] = {SPI_FLASH_JEDEC_ID, 0, 0, 0};
+ uint8_t recv_buf[10] = {0};
+ uint8_t recv_len = 3;
+
+#if (SPI_MODE_EEPROM == SPI_MODE)
+ SPI_SetReadLen(FLASH_SPI, 3);
+ SPI_SendBuffer(FLASH_SPI, send_buf, 1);
+#elif (SPI_MODE_FULLDUPLEX == SPI_MODE)
+ SPI_SendBuffer(FLASH_SPI, send_buf, 4);
+ recv_len += 1;
+#endif
+
+ uint8_t idx = 0;
+ while (recv_len--)
+ {
+ while (RESET == SPI_GetFlagState(FLASH_SPI, SPI_FLAG_RFNE));
+ recv_buf[idx++] = SPI_ReceiveData(FLASH_SPI);
+ }
+
+#if (SPI_MODE_EEPROM == SPI_MODE)
+ memcpy(pFlashId, recv_buf, 3);
+#elif (SPI_MODE_FULLDUPLEX == SPI_MODE)
+ memcpy(pFlashId, &recv_buf[1], 3);
+#endif
+}
+
+void spi_flash_busy_check(void)
+{
+ uint8_t send_buf[2] = {SPI_FLASH_READ_STATUS_REG_1, 0};
+ uint8_t recv_len = 0;
+ uint8_t recv_data[2] = {0};
+
+ while (1)
+ {
+ SPI_SendBuffer(FLASH_SPI, send_buf, 2);
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ recv_len = SPI_GetRxFIFOLen(FLASH_SPI);
+ uint8_t i = 0;
+ while (recv_len--)
+ {
+ recv_data[i++] = SPI_ReceiveData(FLASH_SPI);
+ }
+ i = 0;
+ if ((recv_data[1] & 0x01) == 0)
+ {
+ break;
+ }
+ }
+}
+
+void spi_flash_write_enable(void)
+{
+ uint8_t len = 0;
+
+ SPI_SendData(FLASH_SPI, SPI_FLASH_WRITE_ENABLE);
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ len = SPI_GetRxFIFOLen(FLASH_SPI);
+ while (len--)
+ {
+ SPI_ReceiveData(FLASH_SPI);
+ }
+}
+
+void spi_flash_status_reg_write(uint8_t vStatus)
+{
+ uint8_t len = 0;
+ uint8_t send_buf[2] = {SPI_FLASH_WRITE_STATUS_REG_1, 0};
+
+ send_buf[1] = vStatus & 0xff;
+
+ /* Enable write */
+ spi_flash_write_enable();
+
+ /* Write status register */
+ SPI_SendBuffer(FLASH_SPI, send_buf, 2);
+
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ len = SPI_GetRxFIFOLen(FLASH_SPI);
+ while (len--)
+ {
+ SPI_ReceiveData(FLASH_SPI);
+ }
+ spi_flash_busy_check();
+}
+
+void spi_flash_sector_erase(uint32_t vAddress)
+{
+ uint8_t send_buf[4] = {SPI_FLASH_SECTOR_ERASE, 0, 0, 0};
+ uint8_t recv_len = 0;
+
+ send_buf[1] = (vAddress >> 16) & 0xff;
+ send_buf[2] = (vAddress >> 8) & 0xff;
+ send_buf[3] = vAddress & 0xff;
+
+ /* enable write */
+ spi_flash_write_enable();
+
+ /* erase data */
+ SPI_SendBuffer(FLASH_SPI, send_buf, 4);
+
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ recv_len = SPI_GetRxFIFOLen(FLASH_SPI);
+ while (recv_len--)
+ {
+ SPI_ReceiveData(FLASH_SPI);
+ }
+ spi_flash_busy_check();
+}
+
+void spi_flash_block_erase(uint32_t vAddress)
+{
+ uint8_t send_buf[4] = {SPI_FLASH_BLOCK_ERASE_32K, 0, 0, 0};
+ uint8_t recv_len = 0;
+
+ send_buf[1] = (vAddress >> 16) & 0xff;
+ send_buf[2] = (vAddress >> 8) & 0xff;
+ send_buf[3] = vAddress & 0xff;
+
+ /* Enable write */
+ spi_flash_write_enable();
+ /* erase data */
+ SPI_SendBuffer(FLASH_SPI, send_buf, 4);
+
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ recv_len = SPI_GetRxFIFOLen(FLASH_SPI);
+ while (recv_len--)
+ {
+ SPI_ReceiveData(FLASH_SPI);
+ }
+ spi_flash_busy_check();
+}
+
+void spi_flash_chip_erase(void)
+{
+ uint8_t recv_len = 0;
+
+ /* Enable write */
+ spi_flash_write_enable();
+
+ SPI_SendData(FLASH_SPI, SPI_FLASH_CHIP_ERASE);
+
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ recv_len = SPI_GetRxFIFOLen(FLASH_SPI);
+ while (recv_len--)
+ {
+ SPI_ReceiveData(FLASH_SPI);
+ }
+ spi_flash_busy_check();
+}
+
+void spi_flash_page_write(uint32_t vWriteAddr, uint8_t *pBuffer, uint16_t vLength)
+{
+ uint16_t send_data_len = vLength;
+ uint8_t recv_data_len = 0;
+ uint8_t send_buf[4] = {SPI_FLASH_PAGE_PROGRAM, 0, 0, 0};
+ send_buf[1] = (vWriteAddr >> 16) & 0xff;
+ send_buf[2] = (vWriteAddr >> 8) & 0xff;
+ send_buf[3] = vWriteAddr & 0xff;
+
+ if (vLength > SPI_FLASH_PAGE_SIZE)
+ {
+ send_data_len = SPI_FLASH_PAGE_SIZE;
+ }
+
+ /* Enable write */
+ spi_flash_write_enable();
+ SPI_SendBuffer(FLASH_SPI, send_buf, 4);
+ SPI_SendBuffer(FLASH_SPI, pBuffer, send_data_len);
+
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_BUSY) == SET);
+ recv_data_len = SPI_GetRxFIFOLen(FLASH_SPI);
+ while (recv_data_len--)
+ {
+ SPI_ReceiveData(FLASH_SPI);
+ }
+ spi_flash_busy_check();
+}
+
+void spi_flash_buffer_write(uint32_t vWriteAddr, uint8_t *pBuffer, uint16_t vLength)
+{
+ uint32_t write_addr = vWriteAddr;
+ uint8_t *p_write_data = pBuffer;
+ uint16_t write_data_len = vLength;
+
+ uint8_t offset = vWriteAddr % SPI_FLASH_PAGE_SIZE;
+ uint8_t free_len = SPI_FLASH_PAGE_SIZE - offset;
+ uint8_t page_num = vLength / SPI_FLASH_PAGE_SIZE;
+ uint8_t remain_len = vLength % SPI_FLASH_PAGE_SIZE;
+
+ if (offset == 0)
+ {
+ if (page_num == 0) // write_data_len < SPI_FLASH_PAGE_SIZE
+ {
+ spi_flash_page_write(write_addr, p_write_data, remain_len);
+ }
+ else // write_data_len > SPI_FLASH_PAGE_SIZE
+ {
+ while (page_num--)
+ {
+ spi_flash_page_write(write_addr, p_write_data, SPI_FLASH_PAGE_SIZE);
+ write_addr += SPI_FLASH_PAGE_SIZE;
+ p_write_data += SPI_FLASH_PAGE_SIZE;
+ }
+ spi_flash_page_write(write_addr, p_write_data, remain_len);
+ }
+ }
+ else // write_addr is not SPI_FLASH_PAGE_SIZE aligned
+ {
+ if (page_num == 0)
+ {
+ if (remain_len > free_len) /* (write_data_len + write_addr) > SPI_FLASH_PAGE_SIZE */
+ {
+ uint8_t temp = remain_len - free_len;
+ spi_flash_page_write(write_addr, p_write_data, free_len);
+ write_addr += free_len;
+ p_write_data += free_len;
+ spi_flash_page_write(vWriteAddr, p_write_data, temp);
+ }
+ else
+ {
+ spi_flash_page_write(write_addr, p_write_data, write_data_len);
+ }
+
+ }
+ else /* NumByteToWrite > SPI_FLASH_PAGE_SIZE */
+ {
+ write_data_len -= free_len;
+ page_num = write_data_len / SPI_FLASH_PAGE_SIZE;
+ remain_len = write_data_len % SPI_FLASH_PAGE_SIZE;
+
+ spi_flash_page_write(write_addr, p_write_data, free_len);
+ write_addr += free_len;
+ p_write_data += free_len;
+
+ while (page_num--)
+ {
+ spi_flash_page_write(write_addr, p_write_data, SPI_FLASH_PAGE_SIZE);
+ write_addr += SPI_FLASH_PAGE_SIZE;
+ p_write_data += SPI_FLASH_PAGE_SIZE;
+ }
+
+ if (remain_len != 0)
+ {
+ spi_flash_page_write(write_addr, p_write_data, remain_len);
+ }
+ }
+ }
+}
+
+void spi_flash_read(uint8_t vReadCmd, uint32_t vReadAddr, uint8_t *pBuffer, uint16_t vLength)
+{
+ uint8_t send_buf[10] = {0};
+ uint8_t send_len = 0;
+ uint16_t recv_len = 0;
+
+ if (SPI_FLASH_READ_DATA == vReadCmd)
+ {
+ send_len = 4;
+ }
+ else if (SPI_FLASH_FAST_READ == vReadCmd)
+ {
+ send_len = 5;
+ }
+ send_buf[0] = vReadCmd;
+ send_buf[1] = (vReadAddr >> 16) & 0xFF;
+ send_buf[2] = (vReadAddr >> 8) & 0xFF;
+ send_buf[3] = (vReadAddr) & 0xFF;
+
+ SPI_SendBuffer(FLASH_SPI, send_buf, send_len);
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_RFNE) == RESET);
+ for (uint8_t i = 0; i < send_len; i++)
+ {
+ SPI_ReceiveData(FLASH_SPI);//dummy read data
+ }
+ recv_len = vLength;
+ while (recv_len--)
+ {
+ SPI_SendBuffer(FLASH_SPI, &send_buf[9], 1);
+ while (SPI_GetFlagState(FLASH_SPI, SPI_FLAG_RFNE) == RESET);
+ *pBuffer++ = SPI_ReceiveData(FLASH_SPI);
+ }
+
+}
diff --git a/src/sample/io_sample/SPI/Flash/spi_flash.h b/src/sample/io_sample/SPI/Flash/spi_flash.h
new file mode 100644
index 0000000..79867c8
--- /dev/null
+++ b/src/sample/io_sample/SPI/Flash/spi_flash.h
@@ -0,0 +1,68 @@
+/**
+*********************************************************************************************************
+* Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved.
+*********************************************************************************************************
+* @file spi_flash.h
+* @brief
+* @details
+* @author yuan
+* @date 2018-12-07
+* @version v1.0
+*********************************************************************************************************
+*/
+
+#ifndef __SPI_FLASH_H
+#define __SPI_FLASH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "rtl876x_spi.h"
+
+/* Defines ------------------------------------------------------------------*/
+#define SPI_FLASH_PAGE_SIZE 256
+
+#define SPI_FLASH_WRITE_ENABLE 0x06
+#define SPI_FLASH_WRITE_DISABLE 0x04
+#define SPI_FLASH_READ_STATUS_REG_1 0x05
+#define SPI_FLASH_WRITE_STATUS_REG_1 0x01
+#define SPI_FLASH_READ_STATUS_REG_2 0x35
+#define SPI_FLASH_WRITE_STATUS_REG_2 0x31
+#define SPI_FLASH_PAGE_PROGRAM 0x02
+#define SPI_FLASH_SECTOR_ERASE 0x20
+#define SPI_FLASH_BLOCK_ERASE_32K 0x52
+#define SPI_FLASH_BLOCK_ERASE_64K 0xD8
+#define SPI_FLASH_CHIP_ERASE 0xC7
+#define SPI_FLASH_POWER_DOWN 0xB9
+#define SPI_FLASH_READ_DATA 0x03
+#define SPI_FLASH_FAST_READ 0x0B
+#define SPI_FLASH_RELEASE_POWER_DOWN 0xAB
+#define SPI_FLASH_DEVICE_ID 0xAB
+#define SPI_FLASH_MANU_ID 0x90
+#define SPI_FLASH_JEDEC_ID 0x9F
+#define SPI_FLASH_ENABLE_RESET 0x66
+#define SPI_FLASH_RESET 0x99
+
+#define EWIP_FLAG 0x01 /* Erase/Write in progress (WIP) flag */
+
+
+void spi_flash_read_id(uint8_t *pFlashId);
+void spi_flash_busy_check(void);
+void spi_flash_write_enable(void);
+void spi_flash_status_reg_write(uint8_t vStatus);
+void spi_flash_sector_erase(uint32_t vAddress);
+void spi_flash_block_erase(uint32_t vAddress);
+void spi_flash_chip_erase(void);
+void spi_flash_page_write(uint32_t vWriteAddr, uint8_t *pBuffer, uint16_t vLength);
+void spi_flash_buffer_write(uint32_t vWriteAddr, uint8_t *pBuffer, uint16_t vLength);
+void spi_flash_read(uint8_t vReadCmd, uint32_t vReadAddr, uint8_t *pBuffer, uint16_t vLength);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+