btstack源码分析-主函数

主函数分析(port/windows-winusb/main.c):

int main(int argc, const char * argv[])
{ 

    main_argc = argc;
    main_argv = argv;

    btstack_memory_init();
            ...
            #if MAX_NR_HCI_CONNECTIONS > 0
                 //把hci_connection_storage挂到hci_connection_pool单向链表下,hci_connection_storage是hci_connection_t类型数组,MAX_NR_HCI_CONNECTIONS是数组个数
                 btstack_memory_pool_create(&hci_connection_pool, hci_connection_storage, MAX_NR_HCI_CONNECTIONS, sizeof(hci_connection_t));
            #endif
            ...
            #if MAX_NR_GATT_CLIENTS > 0
                btstack_memory_pool_create(&gatt_client_pool, gatt_client_storage, MAX_NR_GATT_CLIENTS, sizeof(gatt_client_t));
            #endif
            ...

    btstack_run_loop_init(btstack_run_loop_windows_get_instance());
            the_run_loop = btstack_run_loop_windows;
            the_run_loop->init();
            /*
                    btstack_run_loop_windows定义为如下:

                    static const btstack_run_loop_t btstack_run_loop_windows = {
                    &btstack_run_loop_windows_init,
                    &btstack_run_loop_windows_add_data_source,
                    &btstack_run_loop_windows_remove_data_source,
                    &btstack_run_loop_windows_enable_data_source_callbacks,
                    &btstack_run_loop_windows_disable_data_source_callbacks,
                    &btstack_run_loop_windows_set_timer,
                    &btstack_run_loop_windows_add_timer,
                    &btstack_run_loop_windows_remove_timer,
                    &btstack_run_loop_windows_execute,
                    &btstack_run_loop_windows_dump_timer,
                    &btstack_run_loop_windows_get_time_ms,
                };

            */

    // setup USB Transport
    transport = hci_transport_usb_instance();
        transport = hci_transport_usb
        /*
            hci_transport_usb定义为如下:
            
            // get usb singleton
            static const hci_transport_t hci_transport_usb = {
                /* const char * name; */                                        "H2_WINUSB",
                /* void   (*init) (const void *transport_config); */            &usb_init,
                /* int    (*open)(void); */                                     &usb_open,
                /* int    (*close)(void); */                                    &usb_close,
                /* void   (*register_packet_handler)(void (*handler)(...); */   &usb_register_packet_handler,
                /* int    (*can_send_packet_now)(uint8_t packet_type); */       &usb_can_send_packet_now,
                /* int    (*send_packet)(...); */                               &usb_send_packet,
                /* int    (*set_baudrate)(uint32_t baudrate); */                NULL,
                /* void   (*reset_link)(void); */                               NULL,
                #ifdef ENABLE_SCO_OVER_HCI
                /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ usb_set_sco_config, 
                #else
                /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL, 
                #endif    
            };
        */
    btstack_chipset_intel_download_firmware(hci_transport_usb, &intel_firmware_done);
        done = intel_firmware_done;
        transport = hci_transport_usb;
        transport->register_packet_handler(&transport_packet_handler);
        transport->open();

        //这里,主机往控制器发送复位CMD
        state = 0;
        state_machine(NULL);

    btstack_run_loop_execute();
        the_run_loop->execute();
}

 

主函数main主要干了哪几件大事?

1、把结构体btstack_run_loop_windows赋值the_run_loop全局变量(btstack_run_loop_windows基于windows平台实现的操作接口),并调用了btstack_run_loop_windows的init函数;

the_run_loop = btstack_run_loop_windows;


//btstack_run_loop_windows定义如下:
 static const btstack_run_loop_t btstack_run_loop_windows = {
                    &btstack_run_loop_windows_init,
                    &btstack_run_loop_windows_add_data_source,
                    &btstack_run_loop_windows_remove_data_source,
                    &btstack_run_loop_windows_enable_data_source_callbacks,
                    &btstack_run_loop_windows_disable_data_source_callbacks,
                    &btstack_run_loop_windows_set_timer,
                    &btstack_run_loop_windows_add_timer,
                    &btstack_run_loop_windows_remove_timer,
                    &btstack_run_loop_windows_execute,
                    &btstack_run_loop_windows_dump_timer,
                    &btstack_run_loop_windows_get_time_ms,
};

2、设置transport 全局变量(hci_transport_usb是用于操作usb的结构体);

transport = hci_transport_usb;


//hci_transport_usb定义如下:
static const hci_transport_t hci_transport_usb = {
    /* const char * name; */                                        "H2_WINUSB",
    /* void   (*init) (const void *transport_config); */            &usb_init,
    /* int    (*open)(void); */                                     &usb_open,
    /* int    (*close)(void); */                                    &usb_close,
    /* void   (*register_packet_handler)(void (*handler)(...); */   &usb_register_packet_handler,
    /* int    (*can_send_packet_now)(uint8_t packet_type); */       &usb_can_send_packet_now,
    /* int    (*send_packet)(...); */                               &usb_send_packet,
    /* int    (*set_baudrate)(uint32_t baudrate); */                NULL,
    /* void   (*reset_link)(void); */                               NULL,
#ifdef ENABLE_SCO_OVER_HCI
    /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ usb_set_sco_config, 
#else
    /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL, 
#endif    
};

3、调用btstack_chipset_intel_download_firmware函数,执行了如下操作;

//设置done全局变量,done为函数指针变量,赋值intel_firmware_done,该函数启动真正的上层应用
done = intel_firmware_done;

//把usb操作抽象出的结构体hci_transport_usb赋值给全局变量transport
transport = hci_transport_usb;
//调用hci_transport_usb的register_packet_handler注册回调函数,到数据包到达时调用transport_packet_handler
transport->register_packet_handler(&transport_packet_handler);
//调用usb的open函数,打开usb设备,并注册了数据处理对象struct btstack_data_source到data_sources
transport->open();

//下面两句语句会导致Host向Controller发送复位命令,数据传输从此开始
state = 0;   
state_machine(NULL);

上面transport->register_packet_handler(&transport_packet_handler)注册回调函数,作为参数传入的transport_packet_handler函数定义如下:

static void transport_packet_handler (uint8_t packet_type, uint8_t *packet, uint16_t size){
    UNUSED(packet_type);
    // we also get events with packet_type ACL from the controller
    hci_dump_packet(HCI_EVENT_PACKET, 1, packet, size);
    switch (hci_event_packet_get_type(packet)){
        case HCI_EVENT_COMMAND_COMPLETE:
        case HCI_EVENT_VENDOR_SPECIFIC:
            state_machine(packet);
            break;
        default:
            break;
    }
}

4、btstack_run_loop_execute中调用循环处理函数,其实就是调用btstack_run_loop_windows_execute;

在函数btstack_run_loop_execute中运行的the_run_loop->execute(),其定义如下:

static void btstack_run_loop_windows_execute(void) {

    btstack_timer_source_t *ts;
    btstack_linked_list_iterator_t it;

    while (1) {

        // collect handles to wait for
        HANDLE handles[100];
        memset(handles, 0, sizeof(handles));
        int num_handles = 0;     
        btstack_linked_list_iterator_init(&it, &data_sources);
        while (btstack_linked_list_iterator_has_next(&it)){
            btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
            if (ds->source.handle == 0) continue;
            if (ds->flags & (DATA_SOURCE_CALLBACK_READ | DATA_SOURCE_CALLBACK_WRITE)){
                handles[num_handles++] = ds->source.handle;
                log_debug("btstack_run_loop_execute adding handle %p", ds->source.handle);
            }
        }

        // get next timeout
        int32_t timeout_ms = INFINITE;
        if (timers) {
            ts = (btstack_timer_source_t *) timers;
            uint32_t now_ms = btstack_run_loop_windows_get_time_ms();
            timeout_ms = ts->timeout - now_ms;
            if (timeout_ms < 0){
                timeout_ms = 0;
            }
            log_debug("btstack_run_loop_execute next timeout in %u ms", timeout_ms);
        }
        
        int res;
        if (num_handles){
            // wait for ready Events or timeout
            res = WaitForMultipleObjects(num_handles, &handles[0], 0, timeout_ms);
        } else {
            // just wait for timeout
            Sleep(timeout_ms);
            res = WAIT_TIMEOUT;
        }
        
        // process data source
        if (WAIT_OBJECT_0 <= res && res < (WAIT_OBJECT_0 + num_handles)){
            void * triggered_handle = handles[res - WAIT_OBJECT_0];
            btstack_linked_list_iterator_init(&it, &data_sources);
            while (btstack_linked_list_iterator_has_next(&it)){
                btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
                log_debug("btstack_run_loop_windows_execute: check ds %p with handle %p\n", ds, ds->source.handle);
                if (triggered_handle == ds->source.handle){
                    if (ds->flags & DATA_SOURCE_CALLBACK_READ){
                        log_debug("btstack_run_loop_windows_execute: process read ds %p with handle %p\n", ds, ds->source.handle);
                        ds->process(ds, DATA_SOURCE_CALLBACK_READ);
                    } else if (ds->flags & DATA_SOURCE_CALLBACK_WRITE){
                        log_debug("btstack_run_loop_windows_execute: process write ds %p with handle %p\n", ds, ds->source.handle);
                        ds->process(ds, DATA_SOURCE_CALLBACK_WRITE);
                    }
                    break;
                }
            }
        }

        // process timers
        uint32_t now_ms = btstack_run_loop_windows_get_time_ms();
        while (timers) {
            ts = (btstack_timer_source_t *) timers;
            if (ts->timeout > now_ms) break;
            log_debug("btstack_run_loop_windows_execute: process timer %p\n", ts);
            
            // remove timer before processing it to allow handler to re-register with run loop
            btstack_run_loop_windows_remove_timer(ts);
            ts->process(ts);
        }
    }
}

btstack_run_loop_execute的工作可总结为如下:

  • 循环遍历data_sources,把挂到链表的所有struct btstack_data_source结构体实例的handle成员保存到数组handles中;

  • 调用WaitForMultipleObjects(参数为handles数组和超时时间),等待事件或超时,该函数类似于linux的select函数;

  • 当有事件发生或者超时,遍历data_sources链表中的struct btstack_data_source结构体实例,找到产生event的实例,调用其process回调函数;

  • 如果设置了超时处理并且超时发生,则当调用struct btstack_timer_source结构体实例的process回调函数;

  • 循环上述过程...

可知btstack_run_loop_windows_execute和 data_sources密切相关,在while循环里面取得data_sources链表的成员调用。那data_sources的成员由哪里加入链表呢?通过下面的接口:

static void btstack_run_loop_windows_add_data_source(btstack_data_source_t *ds);

 btstack_run_loop_windows_add_data_source函数调用流程如下:

usb_open (hci_transport_h2_winusb.c)
{
    ...
    usb_try_open_device();
        ...
        // setup btstack data soures
        usb_data_source_event_in.source.handle = usb_overlapped_event_in.hEvent;
        btstack_run_loop_set_data_source_handler(&usb_data_source_event_in, &usb_process_event_in);
        btstack_run_loop_add_data_source(&usb_data_source_event_in);

        usb_data_source_command_out.source.handle = usb_overlapped_command_out.hEvent;
        btstack_run_loop_set_data_source_handler(&usb_data_source_command_out, &usb_process_command_out);
        btstack_run_loop_add_data_source(&usb_data_source_command_out);

        usb_data_source_acl_in.source.handle = usb_overlapped_acl_in.hEvent;
        btstack_run_loop_set_data_source_handler(&usb_data_source_acl_in, &usb_process_acl_in);
        btstack_run_loop_add_data_source(&usb_data_source_acl_in);

        usb_data_source_acl_out.source.handle = usb_overlapped_acl_out.hEvent;
        btstack_run_loop_set_data_source_handler(&usb_data_source_acl_out, &usb_process_acl_out);
        btstack_run_loop_add_data_source(&usb_data_source_acl_out);
        ...

}

如上可知在 transport->open()时调用了btstack_run_loop_add_data_source,把struct btstack_data_source结构体实例挂到data_sources链表下;

上面提到的struct btstack_data_source结构体定义如下:

typedef struct btstack_data_source {
	// linked item
    btstack_linked_item_t item;

    // item to watch in run loop
    union {
	    // file descriptor for posix systems
	    int  fd;
    	// handle on windows
    	void * handle;	
    } source;   //windows的WaitForMultipleObjects接口通过handle/fd等待事件产生

    // callback to call for enabled callback types
    //btstack_run_loop_windows_execute中事件产生后回调process
    void  (*process)(struct btstack_data_source *ds, btstack_data_source_callback_type_t callback_type);

    // flags storing enabled callback types
    uint16_t flags;

} btstack_data_source_t;

数据的通讯方Host、Controller之间,对于BLE,有如下几种数据的传输:

  • command    (Host -> Controller)

  • event    (Controller -> Host)

  • acl_out (Host -> Controller)

  • acl_in    (Controller -> Host)

目前作为Host端为什么还有usb_data_source_command_out、usb_data_source_acl_out?不是接收到Controller的数据才产生事件吗?原因是为了通知上层command和acl data已经发送完成,可以继续发送,所以发送完成后也加入事件触发。

触发流程是这样的(以command为例,acl_out 也一样):

usb_send_packet(hci_transport_h2_winusb.c)
    usb_send_cmd_packet(packet, size);
        //传输完成时触发usb_overlapped_command_out的事件
        WinUsb_ControlTransfer(usb_interface_0_handle, setup_packet, packet, size, NULL, &usb_overlapped_command_out); 

总结一下

1. transport->open();打开usb设备,并往data_sources链入struct btstack_data_source结构体对象(针对command、event 、acl data,acl data包括acl in 和 acl out)

2. state = 0; state_machine(NULL);Host向Controller发送复位命令,Host与Controller交互开始,随后Controller返回event

3. btstack_run_loop_execute();遍历data_sources中的struct btstack_data_source结构体对象,等待事件产生,调用struct btstack_data_source结构体对象的process函数。此步循环进行

发布了18 篇原创文章 · 获赞 6 · 访问量 6356

猜你喜欢

转载自blog.csdn.net/lewanhah01/article/details/103834708