注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
懒猫爱飞的个人空间 https://home.eeworld.com.cn/space-uid-238351.html [收藏] [复制] [分享] [RSS]
日志

Da14683学习日志(二) - Perpherial工程学习总结

热度 2已有 800 次阅读2018-8-17 15:12 |个人分类:工作小记




此内容由EEWORLD论坛网友懒猫爱飞原创,如需转载或用于商业用途需征得作者同意并注明出处



Da14683学习日志(二)
-- BLE peripheralapplication例程学习总结
概述   
   这是一个peripheral role的例程,研究一个新的BLE芯片的SDK最先要了看的就是central工程与perpherial工程,这对于了解整个SDK非常重要,一般情况下在perpherial工程中会有关于profile文件的配置,ble数据的发送,广播数据的设置等一般基本的设置与操作。对于芯片的外围设备,像定时器,ADC,USB,UART,I2C等,这些功能与普通的MCU基本差不多,基本上了解原理,都可以套着用,只是代码风格不一样,API不一样,或者有一些其它的注意事项,这个要结合芯片的规格书来看了。下面就简单的学习一下这个工程,通过学习这个工程,应该学会怎么配置一个新的profile文件 ,怎么发送与接收BLE数据。
工程结构
与Central工程类似,该工程中也包括有以下几个文件夹
  
Binaries
  
存放的是生成的elf文件
  
Include
  
包含头文件路径及头文件
  
config
  
工程配置及系统配置相关的文件
  
App
  
用户应用层相关源文件(这个是我后面建的,原DEMO中没有,原工程中main文件放在工程目录下的)
  
misc
  
关于内在地址的一些配置,不需要改动
  
sdk
  
adapters
存放的是系统应用层的驱动接口源文件,包括电池,i2c,uart等
ble
BLE协议栈相关的源文件,一般情况下不需要修改
ble_service
存放的是蓝牙服务相关的源代码
bsp_include
存放的是底层相关的一些头文件
config
存放的是配置相关的头文件,一般情况下不需要修改
cpm
存放的是系统相关的一些应用文件,一般情况下不需要修改
FreeRTOS
存放的是FreeRTOS相关的一条源文件,一般情况下不需要修改
Idscripts
链接相关的一些文件,不需要修改
memory
关于外部FLASH相关的源文件,换外部FALSH时可能要修改,目前没仔细研究
osal
系统相关的源文件,一般情况下不需要修改
peripherals
芯片外设相关的驱动,在适当的时候调用或者配合系统调用
  
startup
  
关于芯片底层的一些配置文件,暂时不需要改动
该工程中包含了以下几个服务:
? BatteryService(Multiple instance)
? CurrentTime Service
? DeviceInformation Service
? ScanParameter Service
? DialogDebug Service
? CustomUser Service
应用文件
  关于peripheral例程中的上层应用都在ble_peripheral_task.c源文件中。关于这个源文件,主要说一下以下两个函数:
  •       staticvoid myservice_init(ble_service_t *include_svc)
  •            voidble_peripheral_task(void *params)
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image001.gif  函数 myservice_init
该函数虽然简单,但可以做为用户添加自定义服务的一个模板,程序中用的是128bit的UUID,其源码如下所示:
  
static void myservice_init(ble_service_t  *include_svc)
  
{
  
        att_uuid_t uuid;
  
  
        /*
  
         * This service  does absolutely nothing, it just checks that it's possible to use 128-bit
  
         * UUIDs for  services, characteristics and descriptors.
  
         */
  
        // 这些API在 ble_uuid.c中有调用
  
        ble_uuid_from_string("91a7608d-4456-479d-b9b1-4706e8711cf8",  &uuid);
  
        ble_gatts_add_service(&uuid,  GATT_SERVICE_PRIMARY, ble_gatts_get_num_attr(1, 1, 1));
  
  
        if (include_svc)
  
        {
  
                 ble_gatts_add_include(include_svc->start_h, NULL);
  
        }
  
  
        ble_uuid_from_string("25047e64-657c-4856-afcf-e315048a965b",  &uuid);
  
         ble_gatts_add_characteristic(&uuid, GATT_PROP_NONE, ATT_PERM_NONE,  1, 0, NULL, NULL);
  
  
        ble_uuid_from_string("6b09fe25-eed7-41fc-8da7-1ec89fab7ecb",  &uuid);
  
        ble_gatts_add_descriptor(&uuid,  ATT_PERM_NONE, 1, 0, NULL);
  
  
        ble_gatts_register_service(NULL, 0);
  
}
  
添加server,添加Character,添加character描述都在里面,这些API在ble_uuid.c这个源文件中有定义,关于如果定义属性,如何通过UUID把值发出去,如果接收host端发过来的数据,如何设置notify,如何运用indication,在这个例程中没有给出,需要结合其它的例程来慢慢了解。该函数只是给出一个大体框架,而且没有给出处理数据的回调函数。关于其它的应用,会在学习其它例程中慢慢总结。
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image001.gif  函数 ble_peripheral_task
关于蓝牙的一些设备,服务的添加,及蓝牙状态的回调等都是在该函数中处理的,下面先看一下该函数的源代码:
  
void ble_peripheral_task(void *params)
  
{
  
        int8_t wdog_id;
  
#if CFG_CTS
  
        ble_service_t *cts;
  
        cts_local_time_info_t cts_lti =
  
        {
  
                /*  Example time zone, should be taken from permanent storage or RTC */
  
                .dst = CTS_DST_DAYLIGHT_TIME,
  
                .time_zone = cts_get_time_zone(+3,  0), // UTC +  3 Athens
  
        };
  
#endif
  
        ble_service_t *svc;
  
  
        // in  case services which do not use svc are all disabled, just surpress  -Wunused-variable
  
        (void) svc;
  
  
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image002.png        /*  register ble_peripheral task to be monitored by watchdog */
  
        wdog_id =  sys_watchdog_register(false);
  
  
        ble_peripheral_task_handle =  OS_GET_CURRENT_TASK();
  
  
        srand(time(NULL));
  
  
        ble_peripheral_start();
  
        ble_register_app();
  
  
        ble_gap_device_name_set("Dialog  Peripheral", ATT_PERM_READ);
  
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image003.png
  
#if  CFG_DEBUG_SERVICE
  
        /*  register debug service */
  
        dbgs = dlgdebug_init(NULL);
  
#endif /*  CFG_DEBUG_SERVICE */
  
  
#if CFG_BAS
  
#if  CFG_BAS_MULTIPLE
  
        /*  register BAS (1st instance) */
  
        svc = bas_init(NULL, &bas_bat1);
  
#if  CFG_DEBUG_SERVICE
  
        dlgdebug_register_handler(dbgs, "bas", "set",  dbg_bas_set, svc);
  
#endif /*  CFG_DEBUG_SERVICE */
  
        bas_set_level(svc, 90, false);
  
  
        /*  register BAS (2nd instance) */
  
        svc = bas_init(NULL, &bas_bat2);
  
        bas_set_level(svc, 60, false);
  
#else
  
  
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image004.png
  
        /* register BAS */
  
        svc  = bas_init(NULL, NULL);
  
#if CFG_DEBUG_SERVICE
  
         dlgdebug_register_handler(dbgs, "bas", "set", dbg_bas_set, svc);
  
#endif /*  CFG_DEBUG_SERVICE */
  
         bas_set_level(svc, 90, false);
  
#endif /*  CFG_BAS_MULTIPLE */
  
#endif /*  CFG_BAS */
  
  
#if CFG_CTS
  
        /*  register CTS */
  
        cts = cts_init(&cts_lti,  &cts_callbacks);
  
#if  CFG_DEBUG_SERVICE
  
        dlgdebug_register_handler(dbgs, "cts", "adjust",  dbg_cts_adjust, cts);
  
#endif /*  CFG_DEBUG_SERVICE */
  
#endif
  
  
#if  CFG_USER_SERVICE
  
        /*  register custom service */
  
#if CFG_CTS
  
        myservice_init(cts);
  
#else
  
         myservice_init(NULL);
  
#endif
  
#endif
  
  
#if CFG_DIS
  
        /* Add  DIS */
  
        dis_init(NULL, &dis_info);
  
#endif
  
  
#if CFG_SCPS
  
        /*  register ScPS */
  
        scps_init(&scps_callbacks);
  
#endif
  
  
#if CFG_CTS
  
        /*  create timer for CTS, this will be used to update current time every second  */
  
        cts_timer = OS_TIMER_CREATE("cts",  portCONVERT_MS_2_TICKS(1000), OS_TIMER_SUCCESS,
  
                                                 (void *)  OS_GET_CURRENT_TASK(), cts_timer_cb);
  
        OS_ASSERT(cts_timer);
  
        OS_TIMER_START(cts_timer,  OS_TIMER_FOREVER);
  
#endif
  
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image005.png
  
        ble_gap_adv_data_set(sizeof(adv_data),  adv_data, 0, NULL);
  
        ble_gap_adv_start(GAP_CONN_MODE_UNDIRECTED);
  
  
        for (;;)
  
        {
  
                OS_BASE_TYPE ret;
  
                uint32_t notif;
  
  
                /*  notify watchdog on each loop */
  
                sys_watchdog_notify(wdog_id);
  
  
                /*  suspend watchdog while blocking on OS_TASK_NOTIFY_WAIT() */
  
                 sys_watchdog_suspend(wdog_id);
  
  
                /*
  
                 * Wait on any of the  notification bits, then clear them all
  
                 */
  
                ret = OS_TASK_NOTIFY_WAIT(0,
  
OS_TASK_NOTIFY_ALL_BITS,
  
                          &notif,
  
OS_TASK_NOTIFY_FOREVER);
  
                /*  Blocks forever waiting for task notification. The return value must be OS_OK  */
  
                OS_ASSERT(ret == OS_OK);
  
  
                /*  resume watchdog */
  
                 sys_watchdog_notify_and_resume(wdog_id);
  
  
                /*  notified from BLE manager, can get event */
  
                if (notif  & BLE_APP_NOTIFY_MASK)
  
                {
  
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image006.png                        ble_evt_hdr_t *hdr;
  
  
                        hdr =  ble_get_event(false);
  
                        if (!hdr)
  
                        {
  
                                goto no_event;
  
                        }
  
  
                        if  (ble_service_handle_event(hdr))
  
                        {
  
                                goto handled;
  
                        }
  
  
                        switch (hdr->evt_code)
  
                        {
  
                            case BLE_EVT_GAP_CONNECTED:
  
                            {
  
                                 handle_evt_gap_connected((ble_evt_gap_connected_t *) hdr);
  
                            }break;
  
  
                            case BLE_EVT_GAP_ADV_COMPLETED:
  
                            {
  
                                 handle_evt_gap_adv_completed((ble_evt_gap_adv_completed_t *) hdr);
  
                            }break;
  
  
                            case BLE_EVT_GAP_DISCONNECTED:
  
                            {
  
                                 handle_evt_gap_disconnected((ble_evt_gap_disconnected_t *) hdr);
  
                            }break;
  
  
                            case BLE_EVT_GAP_PAIR_REQ:
  
                            {
  
                                ble_evt_gap_pair_req_t *evt = (ble_evt_gap_pair_req_t *) hdr;
  
                                 ble_gap_pair_reply(evt->conn_idx, true,  evt->bond);
  
                                break;
  
                            }
  
  
                            default:
  
                            {
  
                                 ble_handle_event_default(hdr);
  
                            }break;
  
                        }
  
  
handled:
  
                        OS_FREE(hdr);
  
  
no_event:
  
                        //  notify again if there are more events to process in queue
  
                        if  (ble_has_event())
  
                        {
  
                                 OS_TASK_NOTIFY(OS_GET_CURRENT_TASK(), BLE_APP_NOTIFY_MASK, eSetBits);
  
                        }
  
                }
  
file:///C:\Users\XCU\AppData\Local\Temp\msohtmlclip1\01\clip_image007.png#if CFG_CTS
  
                if (notif  & CTS_SET_TIME_NOTIF)
  
                {
  
                        cts_notify_time_all(cts,  &cts_time);
  
                }
  
#endif
  
        }
  
}
  
上述代码中主要做了以下几件事:
  • 橙色框中是启动BLE,注册APP及设置设备名称
  • 草绿色框中是添加各种服务的函数
  • 红色框中是设置广播数据,启动广播的操作
  •        灰色框中是获取BLE相关的事件,并进行处理
  • 蓝牙色框中是处理其它notify事件

(此处说明一下:我用的是word编辑好的,粘贴过来的,可是网站粘贴功能不给力,把我大部分格式去掉了,所以,
如果有需要可以下载二楼的PDF格式查看,谢谢!特此声明!)

至于其它的操作,比如广播时闪灯,连接上常亮等,则需要读者自行添加,可以添在
BLE的事件可,也可以用消息做一个任务,这个要结合freertos来做。关于freertos的使用,在后续学习中会慢慢涉及到。
   其它说明
DA14683的SDK的整体架构还是比较清晰的,调用起来也比较方便,只是有些地方还可以再细分一下,比如关于设备信息服务,关于设备的信息的定义,完全可以定义在设备信息服务的源文件中(源文件dis.c),而没必要定义在ble_peripheral_task.c这个件中,或许是为了用户更方便设置吧。
另外一点就是,全局变量会在源码中间定义,这个可能是考虑的是就近原则吧,在离调用处最近的地方调用,这样,可能当时看起来比较实用,但给其它阅读代码的人员会造成不必要的混乱,当然这也是仁者见仁,智者见智吧。
最后,曾记得当年有一段时间也是经常写学习日志,而每写完日志都会喊句口号,给自己鼓鼓劲,是的,是时候,有必要再吼一下当年的口号了:
每天进步一点点,开心多一点^_^


本文来自论坛,点击查看完整帖子内容。

发表评论 评论 (3 个评论)
回复 lanyuyan 2023-6-16 12:10
学习学习
回复 codeword 2024-9-29 15:38
  
回复 codeword 2024-11-3 21:03
  

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章