当前位置:   article > 正文

ancs协议分析

ancs

     网上有很多关于ancs的文章,但是翻译过来的可能会看的没头没脑,建议还是看苹果的官方文档:

https://developer.apple.com/library/archive/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Specification/Specification.html#//apple_ref/doc/uid/TP40013460-CH1-SW61

ancs过程:

1.ble设备进行ancs服务广播,iphone 连接ble设备并绑定;

2.iphone有事件(电话、短信)到来,通过notify通知ble设备;

3.ble设备收到notify之后发出控制notify给iPhone,请求具体数据;

4.iPhone收到ble请求后notify给ble具体数据;

 

下面以52832的代码对ancs进行程序解析:

1.ble设备收到iPhone  notify

  1. static void on_ancs_c_evt(ble_ancs_c_evt_t * p_evt)
  2. {
  3. ret_code_t ret = NRF_SUCCESS;
  4. switch (p_evt->evt_type)
  5. {
  6. case BLE_ANCS_C_EVT_DISCOVERY_COMPLETE:
  7. NRF_LOG_DEBUG("Apple Notification Center Service discovered on the server.\r\n");
  8. ret = nrf_ble_ancs_c_handles_assign(&m_ancs_c, p_evt->conn_handle, &p_evt->service);
  9. APP_ERROR_CHECK(ret);
  10. apple_notification_setup();
  11. break;
  12. case BLE_ANCS_C_EVT_NOTIF://notify解析完毕
  13. m_notification_latest = p_evt->notif;
  14. notif_print(&m_notification_latest);
  15. break;
  16. case BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE://从iPhone端获取到的属性值解析完毕
  17. m_notif_attr_latest = p_evt->attr;
  18. notif_attr_print(&m_notif_attr_latest);
  19. if(p_evt->attr.attr_id == BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER)
  20. {
  21. m_notif_attr_app_id_latest = p_evt->attr;
  22. }
  23. break;
  24. case BLE_ANCS_C_EVT_DISCOVERY_FAILED:
  25. NRF_LOG_DEBUG("Apple Notification Center Service not discovered on the server.\r\n");
  26. break;
  27. case BLE_ANCS_C_EVT_APP_ATTRIBUTE:
  28. app_attr_print(&p_evt->attr);
  29. break;
  30. case BLE_ANCS_C_EVT_NP_ERROR:
  31. err_code_print(p_evt->err_code_np);
  32. break;
  33. default:
  34. // No implementation needed.
  35. break;
  36. }
  37. }

static void on_ancs_c_evt(ble_ancs_c_evt_t * p_evt)函数是ancs服务初始化的时候注册的一个回调,当iPhone有notify来的时候就会执行这个回调;

当iPhone有电话进来的时候,通过ancs服务通知ble设备,数据解析完毕后进入on_ancs_c_evt函数的  BLE_ANCS_C_EVT_NOTIF  事件中,执行了打印函数static void notif_print(ble_ancs_c_evt_notif_t * p_notif);

 

    Event:代表是事件类型,比如收到qq消息,他是add一个消息到信息中心,你在手机上查看了这个qq消息那就是remove这个信息到信息中心,所以收到和已经查看消息ble设备都能知悉;

    Category id:apple公司将消息源做了很多分类,微信qq这些是放在social这一类的;

    Category  cnt,就是累计在iPhone通知栏没有被处理的历史消息总和数;

    Flags,比如iPhone将未读的消息定义为消极,那么你ble设备后续回复消极notify的话就会通知这条信息已经在ble设备端被读取;

  1. static void notif_print(ble_ancs_c_evt_notif_t * p_notif)
  2. {
  3. NRF_LOG_INFO("\r\nNotification\r\n");
  4. NRF_LOG_INFO("Event: %s\r\n", (uint32_t)lit_eventid[p_notif->evt_id]);
  5. NRF_LOG_INFO("Category ID: %s\r\n", (uint32_t)lit_catid[p_notif->category_id]);
  6. NRF_LOG_INFO("Category Cnt:%u\r\n", (unsigned int) p_notif->category_count);
  7. NRF_LOG_INFO("UID: %u\r\n", (unsigned int) p_notif->notif_uid);
  8. //uuid
  9. NRF_LOG_INFO("Flags:\r\n");
  10. if(p_notif->evt_flags.silent == 1)
  11. {
  12. NRF_LOG_INFO(" Silent\r\n");
  13. }
  14. if(p_notif->evt_flags.important == 1)
  15. {
  16. NRF_LOG_INFO(" Important\r\n");
  17. }
  18. if(p_notif->evt_flags.pre_existing == 1)
  19. {
  20. NRF_LOG_INFO(" Pre-existing\r\n");
  21. }
  22. if(p_notif->evt_flags.positive_action == 1)
  23. {
  24. NRF_LOG_INFO(" Positive Action\r\n");
  25. }
  26. if(p_notif->evt_flags.negative_action == 1)
  27. {
  28. NRF_LOG_INFO(" Negative Action\r\n");
  29. }
  30. }

对照着这个协议图示,是不是一目了然; 

2.ble设备向iPhone发送获取详细信息的notify;

在官方的ancs例程中这个发送是通过开发板上的按键KEY0来实现的:

  1. static void bsp_event_handler(bsp_event_t event)
  2. {
  3. ret_code_t ret;
  4. switch (event)
  5. {
  6. case BSP_EVENT_SLEEP:
  7. sleep_mode_enter();
  8. break;
  9. case BSP_EVENT_DISCONNECT:
  10. ret = sd_ble_gap_disconnect(m_cur_conn_handle,
  11. BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
  12. if (ret != NRF_ERROR_INVALID_STATE)
  13. {
  14. APP_ERROR_CHECK(ret);
  15. }
  16. break;
  17. case BSP_EVENT_WHITELIST_OFF:
  18. if (m_ancs_c.conn_handle == BLE_CONN_HANDLE_INVALID)
  19. {
  20. ret = ble_advertising_restart_without_whitelist();
  21. if (ret != NRF_ERROR_INVALID_STATE)
  22. {
  23. APP_ERROR_CHECK(ret);
  24. }
  25. }
  26. break;
  27. case BSP_EVENT_KEY_0:
  28. ret = nrf_ble_ancs_c_request_attrs(&m_ancs_c, &m_notification_latest);//发送获取详细信息notify请求
  29. APP_ERROR_CHECK(ret);
  30. break;
  31. case BSP_EVENT_KEY_1:
  32. if(m_notif_attr_app_id_latest.attr_id == BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER
  33. && m_notif_attr_app_id_latest.attr_len != 0)
  34. {
  35. NRF_LOG_INFO("Request for %s: \r\n", (uint32_t)m_notif_attr_app_id_latest.p_attr_data);
  36. ret = nrf_ble_ancs_c_app_attr_request(&m_ancs_c,
  37. m_notif_attr_app_id_latest.p_attr_data,
  38. m_notif_attr_app_id_latest.attr_len);
  39. APP_ERROR_CHECK(ret);
  40. }
  41. break;
  42. case BSP_EVENT_KEY_2://回复积极指令
  43. if(m_notification_latest.evt_flags.positive_action == true)
  44. {
  45. NRF_LOG_INFO("Performing Positive Action.\r\n");
  46. ret = nrf_ancs_perform_notif_action(&m_ancs_c,
  47. m_notification_latest.notif_uid,
  48. ACTION_ID_POSITIVE);
  49. APP_ERROR_CHECK(ret);
  50. }
  51. break;
  52. case BSP_EVENT_KEY_3://回复消极指令
  53. if(m_notification_latest.evt_flags.negative_action == true)
  54. {
  55. NRF_LOG_INFO("Performing Negative Action.\r\n");
  56. ret = nrf_ancs_perform_notif_action(&m_ancs_c,
  57. m_notification_latest.notif_uid,
  58. ACTION_ID_NEGATIVE);
  59. APP_ERROR_CHECK(ret);
  60. }
  61. break;
  62. default:
  63. break;
  64. }
  65. }

我们详细的来看这个 ret = nrf_ble_ancs_c_request_attrs(&m_ancs_c, &m_notification_latest)函数:

  1. ret_code_t nrf_ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
  2. const ble_ancs_c_evt_notif_t * p_notif)
  3. {
  4. uint32_t err_code;
  5. err_code = ble_ancs_verify_notification_format(p_notif);
  6. VERIFY_SUCCESS(err_code);
  7. err_code = ble_ancs_get_notif_attrs(p_ancs, p_notif->notif_uid);
  8. p_ancs->parse_info.parse_state = COMMAND_ID;
  9. VERIFY_SUCCESS(err_code);
  10. return NRF_SUCCESS;
  11. }

继续下探:

  1. uint32_t ble_ancs_get_notif_attrs(ble_ancs_c_t * p_ancs,
  2. const uint32_t p_uid)
  3. {
  4. tx_message_t p_msg;
  5. memset(&p_msg, 0, sizeof(tx_message_t));
  6. uint32_t index = 0;
  7. p_ancs->number_of_requested_attr = 0;
  8. p_msg.req.write_req.gattc_params.handle = p_ancs->service.control_point_char.handle_value;
  9. p_msg.req.write_req.gattc_params.p_value = p_msg.req.write_req.gattc_value;
  10. p_msg.req.write_req.gattc_params.offset = 0;
  11. p_msg.req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
  12. //Encode Command ID.
  13. p_msg.req.write_req.gattc_value[index++] = BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
  14. //Encode Notification UID.
  15. index += uint32_encode(p_uid, &(p_msg.req.write_req.gattc_value[index]));
  16. //Encode Attribute ID.
  17. for (uint32_t attr = 0; attr < BLE_ANCS_NB_OF_NOTIF_ATTR; attr++)//添加需要获悉详情的attribute id
  18. {
  19. if (p_ancs->ancs_notif_attr_list[attr].get == true)
  20. {
  21. p_msg.req.write_req.gattc_value[index++] = attr;
  22. if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) ||
  23. (attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
  24. (attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE))
  25. {
  26. //Encode Length field, only applicable for Title, Subtitle and Message
  27. index += uint16_encode(p_ancs->ancs_notif_attr_list[attr].attr_len,
  28. &(p_msg.req.write_req.gattc_value[index]));
  29. }
  30. p_ancs->number_of_requested_attr++;
  31. }
  32. }
  33. p_msg.req.write_req.gattc_params.len = index;
  34. p_msg.conn_handle = p_ancs->conn_handle;
  35. p_msg.type = WRITE_REQ;
  36. p_ancs->parse_info.expected_number_of_attrs = p_ancs->number_of_requested_attr;
  37. tx_buffer_insert(&p_msg);
  38. tx_buffer_process();
  39. return NRF_SUCCESS;
  40. }

BLE_ANCS_NB_OF_NOTIF_ATTR的值为8,再看看各个attribute id的值:

  1. typedef enum
  2. {
  3. BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER = 0, /**< Identifies that the attribute data is of an "App Identifier" type. */
  4. BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". */
  5. BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". */
  6. BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". */
  7. BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */
  8. BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */
  9. BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */
  10. BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */
  11. } ble_ancs_c_notif_attr_id_val_t;

 所以,nordic的例程每次收到notify后是把所有的id详情每次都申请了

这样去看这个协议是不是就一目了然了;

3.iPhone通过notify发送详情给ble设备;

ble设备对notify解析后就在这里进行打印:

  1. static void notif_attr_print(ble_ancs_c_attr_t * p_attr)
  2. {
  3. if (p_attr->attr_len != 0)
  4. {
  5. NRF_LOG_INFO("%s: %s\r\n", (uint32_t)lit_attrid[p_attr->attr_id], nrf_log_push((char *)p_attr->p_attr_data));
  6. //打印id号 打印id号下的内容
  7. }
  8. else if (p_attr->attr_len == 0)
  9. {
  10. NRF_LOG_INFO("%s: (N/A)\r\n", (uint32_t)lit_attrid[p_attr->attr_id]);
  11. }
  12. }

这里看一下其调试的打印数据:

因为数据量太大所有两次notify上报过来,就出现了两次(N/A);

 

再对比一下协议,很容易就能理解了;

获取到所有详细的信息后,ble设备能够对当前信息作出反应,比如进来一个电话,iPhone通知消息notify到ble设备,并将这个消息定义为消极,那ble设备回复一个消极notify其实就通知iPhone接这个电话;同理iPhone收到一个qq消息在通知栏并将其定义为消息,ble设备回复消极notify的话表示消息已经在ble设备读取,那么iPhone就会在通知栏消除这条通知,并且回复通知remove了一条消息;所以通知有变动都会通知到ble设备,不管是增加还是减少;

需要说明的是这8个attribute id 信息通过notify下达后,是一个一个attribute id解析然后再进入on_ancs_c_evt回调的,所以写应用层的话需要全部回调完后再对信息打包处理;

attribute id是从0到8的索引标号,ancs赋予他们意义,后边的attribute值就是他们的意义,是id的内容;ancs规定有8个attribute id也就是iPhone一个notify事件产生后能生产8个于此有关的标签信息,你需要获取8个中的哪一个在获取详情那里填充对应的attribute id值;

ancs有一个重要的特点就是使用前一定需要配对绑定,官方的ancs例程里面还使用了白名单机制,ble设备第一次被绑定之后就会往flash写入绑定信息,设置白名单,其他手机就没有办法连接绑定;针对此写应用可能用到的函数有

1.删除绑定:delete_bonds();

2.设置白名单:            ret = ble_advertising_whitelist_reply(&m_advertising,
                                                  whitelist_addrs,
                                                  addr_cnt,
                                                  whitelist_irks,
                                                  irk_cnt);

3.去除白名单:ret = ble_advertising_restart_without_whitelist(&m_advertising);

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/146807
推荐阅读
相关标签
  

闽ICP备14008679号