从Main.c开始,Main函数。
初始化时钟,创建system_init任务,然后启动操作系统调度,并不再返回。
在system_init任务主要做系统初始化,然后创建pxp_reporter_task任务,然后Delete自己。
pxp_reporter_task中,依次做了以下几件事:
- 初始化;
- 创建要广播的设备名称;
- 注册标准的服务, IAS(Immediate Alert service),LLS(Link Loss service);注册时,会注册一个回调函数,分别用于这两个消息触发时的回调。
- 设置Txpower,固定为0db。没有用TPS(Tx Power Service)注册服务;
- 注册BAS(battery service),电池电量服务。注意以初始化时用了全局变量保留服务指针,应该是以后还要用到。
- 接下来为几个服务分别创建了定时器,包含时间和回调函数;
- 接下来设置了广播时间和参数,并启动广播。。
- 然后启动任务死循环;在循环中,处理watchdog, OS_TASK_NOTIFY_WAIT等待Notify,挂起任务,有Notify则往下走,处理GAP事件。
接下来看各个服务是怎么组织的。
ble_service_t是一个重要的结构,如下:
typedef struct ble_service {
uint16_t start_h; /**< Service start handle */
uint16_t end_h; /**< Service end handle */
connected_evt_t connected_evt; /**< Connected event callback*/
disconnected_evt_t disconnected_evt; /**< Disconnected event callback */
read_req_t read_req; /**<Read request callback */
write_req_t write_req; /**< Writerequest callback */
prepare_write_req_tprepare_write_req; /**< Prepare write request callback */
event_sent_t event_sent; /**< Event sentcallback */
} ble_service_t;
而每一个单独的Sevice,以LLS为例,都会在自己定义的结构体的最开始,包含ble_service_t:
typedef struct {
ble_service_t svc;
// handles
uint16_t al_val_h;
// callbacks
lls_alert_cb_t cb;
queue_t levels;
} ll_service_t;
结构体中,除svc外,handles和Callbacks是基本都会用到的,其他还可以添加服务相关的数据结构。Service结构体中对应的handle是Service的UUID,而单独结构体中的Handle对应的就是characteristics。在初始化时会注册到service的UUID。
每个服务会有自己的初始化函数。如下:
ble_service_t *ias_init(ias_alert_level_cb_t alert_level_cb)
{
ia_service_t *ias;
uint16_t num_attr;
att_uuid_t uuid;
ias =OS_MALLOC(sizeof(*ias));
memset(ias, 0,sizeof(*ias));
//将服务对应的读写操作函数注册到结构体,这些函数在APP处理Event时被分别调用。
ias->svc.write_req= handle_write_req;
ias->svc.disconnected_evt = handle_disconnected_evt;
//这个是自定义的处理函数,由APP初始化任务时传递过来的回调指针。个人理解这种操作可以很多,取决于服务的性质。这些函数是在消息解析后调用,保证了APP希望做的相关处理与Service分割,更好的保证代码可重用。
ias->cb =alert_level_cb;
//创建并注册service和characteristic的UUID。
num_attr =ble_gatts_get_num_attr(0, 1, 0);
ble_uuid_create16(UUID_SERVICE_IAS, &uuid);
ble_gatts_add_service(&uuid, GATT_SERVICE_PRIMARY, num_attr);
ble_uuid_create16(UUID_ALERT_LEVEL, &uuid);
ble_gatts_add_characteristic(&uuid, GATT_PROP_WRITE_NO_RESP,ATT_PERM_WRITE,
sizeof(uint8_t), 0, NULL, &ias->al_val_h);
//注册service。这保证了协议栈在接收到相关service UUID读写时会被调用相关处理函数。
ble_gatts_register_service(&ias->svc.start_h,&ias->al_val_h, 0);
ias->svc.end_h =ias->svc.start_h + num_attr;
return&ias->svc;
}