借助 Silicon Labs 的软件架构,蓝牙操作可以一系列事件展开,使用预定义的事件 ID 来表示事件的性质。在样例软件包中,main() 例程在上电或复位时运行,先调用一系列初始化例程,然后进入主循环,本例中主循环只包含两行代码(列表 1)。
副本int main(){#ifdef FEATURE_SPI_FLASH /* Put the SPI flash into Deep Power Down mode for those radio boards where it is available */ MX25_init(); MX25_DP(); /* We must disable SPI communication */ USART_Reset(USART1);#endif /* FEATURE_SPI_FLASH */ enter_DefaultMode_from_RESET();#if (EMBER_AF_BOARD_TYPE == BRD4304A) LNA_init();#endif gecko_init(&config);#ifdef FEATURE_PTI_SUPPORT APP_ConfigEnablePti();#endif // FEATURE_PTI_SUPPORT RETARGET_SerialInit(); /* initialize LEDs and buttons.Note: some radio boards share the same GPIO for button & LED.* Initialization is done in this order so that default configuration will be button for those * radio boards with shared pins.led_init() is called later as needed to (re)initialize the LEDs * */ led_init(); button_init(); LCD_init(); while (1) { struct gecko_cmd_packet *evt = gecko_wait_event(); handle_gecko_event(BGLIB_MSG_ID(evt->header), evt); }}
列表 1:Simplicity Studio 提供了一个综合开发环境,其中包括样例代码,例如此网状网络照明主例程,其演示了初始化和事件处理循环。(代码来源:Silicon Labs)
在主循环的第二行中,处理函数 handle_gecko_event() 根据其事件 ID 处理最新事件 (evt)(列表 2)。当设备上电时,堆栈发出系统引导事件 (gecko_evt_system_boot_id)。事件处理程序进而调用一系列初始化函数,包括 gecko_cmd_mesh_node_init(),其会初始化蓝牙网状网络堆栈。然后,处理程序调用其他函数来提供与该事件类型(由其相关事件 ID 表示)相关联的功能。
副本/** * Handling of stack events.Both Bluetooth LE and Bluetooth mesh events are handled here.*/static void handle_gecko_event(uint32_t evt_id, struct gecko_cmd_packet *evt){ struct gecko_bgapi_mesh_node_cmd_packet *node_evt; struct gecko_bgapi_mesh_generic_server_cmd_packet *server_evt; struct gecko_msg_mesh_node_provisioning_failed_evt_t *prov_fail_evt; if (NULL == evt) { return; } switch (evt_id) { case gecko_evt_system_boot_id: // check pushbutton state at startup.If either PB0 or PB1 is held down then do factory reset if (GPIO_PinInGet(BSP_GPIO_PB0_PORT, BSP_GPIO_PB0_PIN) == 0 || GPIO_PinInGet(BSP_GPIO_PB1_PORT, BSP_GPIO_PB1_PIN) == 0) { initiate_factory_reset(); } else { struct gecko_msg_system_get_bt_address_rsp_t *pAddr = gecko_cmd_system_get_bt_address(); set_device_name(&pAddr->address); // Initialize Mesh stack in Node operation mode, wait for initialized event gecko_cmd_mesh_node_init(); // re-initialize LEDs (needed for those radio board that share same GPIO for button/LED) led_init(); } break; ...case gecko_evt_mesh_node_initialized_id: printf(node initialized\r\n); struct gecko_msg_mesh_node_initialized_evt_t *pData = (struct gecko_msg_mesh_node_initialized_evt_t *)&(evt->data); if (pData->provisioned) { ...} else { printf(node is unprovisioned\r\n); LCD_write(unprovisioned, LCD_ROW_STATUS); printf(starting unprovisioned beaconing...\r\n); gecko_cmd_mesh_node_start_unprov_beaconing(0x3); // enable ADV and GATT provisioning bearer } break; case gecko_evt_mesh_node_provisioning_started_id: printf(Started provisioning\r\n); LCD_write(provisioning..., LCD_ROW_STATUS); // start timer for blinking LEDs to indicate which node is being provisioned gecko_cmd_hardware_set_soft_timer(32768 / 4, TIMER_ID_PROVISIONING, 0); break; case gecko_evt_mesh_node_provisioned_id: _my_index = 0; // index of primary element hardcoded to zero in this example lightbulb_state_init(); printf(node provisioned, got index=%x\r\n, _my_index); // stop LED blinking when provisioning complete gecko_cmd_hardware_set_soft_timer(0, TIMER_ID_PROVISIONING, 0); LED_set_state(LED_STATE_OFF); LCD_write(provisioned, LCD_ROW_STATUS); break; case gecko_evt_mesh_node_provisioning_failed_id: prov_fail_evt = (struct gecko_msg_mesh_node_provisioning_failed_evt_t *)&(evt->data); printf(provisioning failed, code %x\r\n, prov_fail_evt->result); LCD_write(prov failed, LCD_ROW_STATUS); /* start a one-shot timer that will trigger soft reset after small delay */ gecko_cmd_hardware_set_soft_timer(2 * 32768, TIMER_ID_RESTART, 1); break; ...}}
副本/** * This function publishes one on/off request to change the state of light(s) in the group.* Global variable switch_pos holds the latest desired light state, possible values are * switch_pos = 1 -> PB1 was pressed, turn lights on * switch_pos = 0 -> PB0 was pressed, turn lights off * * This application sends multiple requests for each button press to improve reliability.* Parameter retrans indicates whether this is the first request or a re-transmission.* The transaction ID is not incremented in case of a re-transmission.*/void send_onoff_request(int retrans){ uint16 resp; uint16 delay; struct mesh_generic_request req; req.kind = mesh_generic_request_on_off; req.on_off = switch_pos ?MESH_GENERIC_ON_OFF_STATE_ON : MESH_GENERIC_ON_OFF_STATE_OFF; // increment transaction ID for each request, unless it's a retransmission if (retrans == 0) { trid++; } /* delay for the request is calculated so that the last request will have a zero delay and each * of the previous request have delay that increases in 50 ms steps.For example, when using three * on/off requests per button press the delays are set as 100, 50, 0 ms */ delay = (request_count - 1) * 50; resp = gecko_cmd_mesh_generic_client_publish( MESH_GENERIC_ON_OFF_CLIENT_MODEL_ID, _my_index, trid, 0, // transition delay, 0, // flags mesh_generic_request_on_off, // type 1, // param len &req.on_off /// parameters data )->result; if (resp) { printf(gecko_cmd_mesh_generic_client_publish failed,code %x\r\n, resp); } else { printf(request sent, trid = %u, delay = %d\r\n, trid, delay); }}