diff options
Diffstat (limited to 'common/btle_ll.c')
-rw-r--r-- | common/btle_ll.c | 861 |
1 files changed, 0 insertions, 861 deletions
diff --git a/common/btle_ll.c b/common/btle_ll.c deleted file mode 100644 index 20ede4d4a0..0000000000 --- a/common/btle_ll.c +++ /dev/null @@ -1,861 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "bluetooth_le_ll.h" -#include "bluetooth_le.h" -#include "btle_hci_int.h" -#include "util.h" -#include "console.h" -#include "radio.h" -#include "radio_test.h" -#include "task.h" -#include "timer.h" - -#ifdef CONFIG_BLUETOOTH_LL_DEBUG - -#define CPUTS(outstr) cputs(CC_BLUETOOTH_LL, outstr) -#define CPRINTS(format, args...) cprints(CC_BLUETOOTH_LL, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_BLUETOOTH_LL, format, ## args) - -#else /* CONFIG_BLUETOOTH_LL_DEBUG */ - -#define CPUTS(outstr) -#define CPRINTS(format, args...) -#define CPRINTF(format, args...) - -#endif /* CONFIG_BLUETOOTH_LL_DEBUG */ - -/* Link Layer */ - -enum ll_state_t ll_state = UNINITIALIZED; - -static struct hciLeSetAdvParams ll_adv_params; -static struct hciLeSetScanParams ll_scan_params; -static int ll_adv_interval_us; -static int ll_adv_timeout_us; - -static struct ble_pdu ll_adv_pdu; -static struct ble_pdu ll_scan_rsp_pdu; -static struct ble_pdu tx_packet_1; -static struct ble_pdu *packet_tb_sent; -static struct ble_connection_params conn_params; -static int connection_initialized; -static struct remapping_table remap_table; - -static uint64_t receive_time, last_receive_time; -static uint8_t num_consecutive_failures; - -static uint32_t tx_end, tx_rsp_end, time_of_connect_req; -struct ble_pdu ll_rcv_packet; -static uint32_t ll_conn_events; -static uint32_t errors_recovered; - -int ll_power; -uint8_t is_first_data_packet; - -static uint64_t ll_random_address = 0xC5BADBADBAD1; /* Uninitialized */ -static uint64_t ll_public_address = 0xC5BADBADBADF; /* Uninitialized */ -static uint8_t ll_channel_map[5] = {0xff, 0xff, 0xff, 0xff, 0x1f}; - -static uint8_t ll_filter_duplicates; - -int ll_pseudo_rand(int max_plus_one) -{ - static uint32_t lfsr = 0x55555; - int lsb = lfsr & 1; - - lfsr = lfsr >> 1; - if (lsb) - lfsr ^= 0x80020003; /* Bits 32, 22, 2, 1 */ - return lfsr % max_plus_one; -} - -uint8_t ll_set_tx_power(uint8_t *params) -{ - /* Add checking */ - ll_power = params[0]; - return HCI_SUCCESS; -} - -uint8_t ll_read_tx_power(void) -{ - return ll_power; -} - -/* LE Information */ -uint8_t ll_read_buffer_size(uint8_t *return_params) -{ - return_params[0] = LL_MAX_DATA_PACKET_LENGTH & 0xff; - return_params[1] = (LL_MAX_DATA_PACKET_LENGTH >> 8) & 0xff; - return_params[2] = LL_MAX_DATA_PACKETS; - return HCI_SUCCESS; -} - -uint8_t ll_read_local_supported_features(uint8_t *return_params) -{ - uint64_t supported_features = LL_SUPPORTED_FEATURES; - - memcpy(return_params, &supported_features, sizeof(supported_features)); - return HCI_SUCCESS; -} - -uint8_t ll_read_supported_states(uint8_t *return_params) -{ - uint64_t supported_states = LL_SUPPORTED_STATES; - - memcpy(return_params, &supported_states, sizeof(supported_states)); - return HCI_SUCCESS; -} - -uint8_t ll_set_host_channel_classification(uint8_t *params) -{ - memcpy(ll_channel_map, params, sizeof(ll_channel_map)); - return HCI_SUCCESS; -} - -/* Advertising */ -uint8_t ll_set_scan_response_data(uint8_t *params) -{ - if (params[0] > BLE_MAX_ADV_PAYLOAD_OCTETS) - return HCI_ERR_Invalid_HCI_Command_Parameters; - - if (ll_state == ADVERTISING) - return HCI_ERR_Controller_Busy; - - memcpy(&ll_scan_rsp_pdu.payload[BLUETOOTH_ADDR_OCTETS], ¶ms[1], - params[0]); - ll_scan_rsp_pdu.header.adv.length = params[0] + BLUETOOTH_ADDR_OCTETS; - - return HCI_SUCCESS; -} - -uint8_t ll_set_adv_data(uint8_t *params) -{ - if (params[0] > BLE_MAX_ADV_PAYLOAD_OCTETS) - return HCI_ERR_Invalid_HCI_Command_Parameters; - - if (ll_state == ADVERTISING) - return HCI_ERR_Controller_Busy; - - /* Skip the address */ - memcpy(&ll_adv_pdu.payload[BLUETOOTH_ADDR_OCTETS], ¶ms[1], - params[0]); - ll_adv_pdu.header.adv.length = params[0] + BLUETOOTH_ADDR_OCTETS; - - return HCI_SUCCESS; -} - -uint8_t ll_reset(void) -{ - ll_state = UNINITIALIZED; - radio_disable(); - - ble_radio_clear_allow_list(); - - return HCI_SUCCESS; -} - -static uint8_t ll_state_change_request(enum ll_state_t next_state) -{ - /* Initialize the radio if it hasn't been initialized */ - if (ll_state == UNINITIALIZED) { - if (ble_radio_init(BLE_ADV_ACCESS_ADDRESS, BLE_ADV_CRCINIT) - != EC_SUCCESS) - return HCI_ERR_Hardware_Failure; - ll_state = STANDBY; - } - - /* Only change states when the link layer is in STANDBY */ - if (next_state != STANDBY && ll_state != STANDBY) - return HCI_ERR_Controller_Busy; - - ll_state = next_state; - - return HCI_SUCCESS; -} - -uint8_t ll_set_advertising_enable(uint8_t *params) -{ - uint8_t rv; - - if (params[0]) { - rv = ll_state_change_request(ADVERTISING); - if (rv == HCI_SUCCESS) - task_wake(TASK_ID_BLE_LL); - } else { - rv = ll_state_change_request(STANDBY); - } - - return rv; -} - -uint8_t ll_set_scan_enable(uint8_t *params) -{ - uint8_t rv; - - if (params[0]) { - ll_filter_duplicates = params[1]; - rv = ll_state_change_request(SCANNING); - if (rv == HCI_SUCCESS) - task_wake(TASK_ID_BLE_LL); - } else { - rv = ll_state_change_request(STANDBY); - } - - return HCI_SUCCESS; -} - -void set_empty_data_packet(struct ble_pdu *pdu) -{ - /* LLID == 1 means incomplete or empty data packet */ - pdu->header.data.llid = 1; - pdu->header.data.nesn = 1; - pdu->header.data.sn = 0; - pdu->header.data.md = 0; - pdu->header.data.length = 0; - pdu->header_type_adv = 0; -} - -/* Connection state */ - -/** - * This function serves to take data from a CONNECT_REQ packet and copy it - * into a struct, conn_params, which defines the parameter of the connection. - * It also fills a remapping table, another essential element of the link - * layer connection. - */ -uint8_t initialize_connection(void) -{ - int cur_offset = 0, i = 0; - uint8_t final_octet = 0; - uint8_t remap_arr[5]; - uint8_t *payload_start = (uint8_t *)(ll_rcv_packet.payload); - - num_consecutive_failures = 0; - - /* Copy data into the appropriate portions of memory */ - memcpy((uint8_t *)&(conn_params.init_a), - payload_start, CONNECT_REQ_INITA_LEN); - cur_offset += CONNECT_REQ_INITA_LEN; - - memcpy((uint8_t *)&(conn_params.adv_a), - payload_start+cur_offset, CONNECT_REQ_ADVA_LEN); - cur_offset += CONNECT_REQ_ADVA_LEN; - - memcpy(&(conn_params.access_addr), - payload_start+cur_offset, CONNECT_REQ_ACCESS_ADDR_LEN); - cur_offset += CONNECT_REQ_ACCESS_ADDR_LEN; - - conn_params.crc_init_val = 0; - memcpy(&(conn_params.crc_init_val), - payload_start+cur_offset, CONNECT_REQ_CRC_INIT_VAL_LEN); - cur_offset += CONNECT_REQ_CRC_INIT_VAL_LEN; - - memcpy(&(conn_params.win_size), - payload_start+cur_offset, CONNECT_REQ_WIN_SIZE_LEN); - cur_offset += CONNECT_REQ_WIN_SIZE_LEN; - - memcpy(&(conn_params.win_offset), - payload_start+cur_offset, CONNECT_REQ_WIN_OFFSET_LEN); - cur_offset += CONNECT_REQ_WIN_OFFSET_LEN; - - memcpy(&(conn_params.interval), - payload_start+cur_offset, CONNECT_REQ_INTERVAL_LEN); - cur_offset += CONNECT_REQ_INTERVAL_LEN; - - memcpy(&(conn_params.latency), - payload_start+cur_offset, CONNECT_REQ_LATENCY_LEN); - cur_offset += CONNECT_REQ_LATENCY_LEN; - - memcpy(&(conn_params.timeout), - payload_start+cur_offset, CONNECT_REQ_TIMEOUT_LEN); - cur_offset += CONNECT_REQ_TIMEOUT_LEN; - - conn_params.channel_map = 0; - memcpy(&(conn_params.channel_map), - payload_start+cur_offset, CONNECT_REQ_CHANNEL_MAP_LEN); - cur_offset += CONNECT_REQ_CHANNEL_MAP_LEN; - - memcpy(&final_octet, payload_start+cur_offset, - CONNECT_REQ_HOP_INCREMENT_AND_SCA_LEN); - - /* last 5 bits of final_octet: */ - conn_params.hop_increment = final_octet & 0x1f; - /* first 3 bits of final_octet: */ - conn_params.sleep_clock_accuracy = (final_octet & 0xe0) >> 5; - - /* Set up channel mapping table */ - for (i = 0; i < 5; ++i) - remap_arr[i] = *(((uint8_t *)&(conn_params.channel_map))+i); - fill_remapping_table(&remap_table, remap_arr, - conn_params.hop_increment); - - /* Calculate transmission window parameters */ - conn_params.transmitWindowSize = conn_params.win_size * 1250; - conn_params.transmitWindowOffset = conn_params.win_offset * 1250; - conn_params.connInterval = conn_params.interval * 1250; - /* The following two lines convert ms -> microseconds */ - conn_params.connLatency = 1000 * conn_params.latency; - conn_params.connSupervisionTimeout = 10000 * conn_params.timeout; - /* All these times are in microseconds! */ - - /* Check for common transmission errors */ - if (conn_params.hop_increment < 5 || conn_params.hop_increment > 16) { - for (i = 0; i < 5; ++i) - CPRINTF("ERROR!! ILLEGAL HOP_INCREMENT!!\n"); - return HCI_ERR_Invalid_LMP_Parameters; - } - - is_first_data_packet = 1; - return HCI_SUCCESS; -} - -/* Allow List */ -uint8_t ll_clear_allow_list(void) -{ - if (ble_radio_clear_allow_list() == EC_SUCCESS) - return HCI_SUCCESS; - else - return HCI_ERR_Hardware_Failure; -} - -uint8_t ll_read_allow_list_size(uint8_t *return_params) -{ - if (ble_radio_read_allow_list_size(return_params) == EC_SUCCESS) - return HCI_SUCCESS; - else - return HCI_ERR_Hardware_Failure; -} - -uint8_t ll_add_device_to_allow_list(uint8_t *params) -{ - if (ble_radio_add_device_to_allow_list(¶ms[1], params[0]) == - EC_SUCCESS) - return HCI_SUCCESS; - else - return HCI_ERR_Host_Rejected_Due_To_Limited_Resources; -} - -uint8_t ll_remove_device_from_allow_list(uint8_t *params) -{ - if (ble_radio_remove_device_from_allow_list(¶ms[1], params[0]) == - EC_SUCCESS) - return HCI_SUCCESS; - else - return HCI_ERR_Hardware_Failure; -} - -/* Connections */ -uint8_t ll_read_remote_used_features(uint8_t *params) -{ - uint16_t handle = params[0] | (((uint16_t)params[1]) << 8); - - CPRINTS("Read remote used features for handle %d", handle); - /* Check handle */ - return HCI_SUCCESS; -} - -/* RF PHY Testing */ -static int ll_test_packets; - -uint8_t ll_receiver_test(uint8_t *params) -{ - int rv; - - ll_test_packets = 0; - - /* See if the link layer is busy */ - rv = ll_state_change_request(TEST_RX); - if (rv) - return rv; - - rv = ble_test_rx_init(params[0]); - if (rv) - return rv; - - CPRINTS("Start Rx test"); - task_wake(TASK_ID_BLE_LL); - - return HCI_SUCCESS; -} - -uint8_t ll_transmitter_test(uint8_t *params) -{ - int rv; - - ll_test_packets = 0; - - /* See if the link layer is busy */ - rv = ll_state_change_request(TEST_TX); - if (rv) - return rv; - - rv = ble_test_tx_init(params[0], params[1], params[2]); - if (rv) - return rv; - - CPRINTS("Start Tx test"); - task_wake(TASK_ID_BLE_LL); - - return HCI_SUCCESS; -} - -uint8_t ll_test_end(uint8_t *return_params) -{ - CPRINTS("End (%d packets)", ll_test_packets); - - ble_test_stop(); - - if (ll_state == TEST_RX) { - return_params[0] = ll_test_packets & 0xff; - return_params[1] = (ll_test_packets >> 8); - ll_test_packets = 0; - } else { - return_params[0] = 0; - return_params[1] = 0; - ll_test_packets = 0; - } - return ll_reset(); -} - -uint8_t ll_set_random_address(uint8_t *params) -{ - /* No checking. The host should know the rules. */ - memcpy(&ll_random_address, params, - sizeof(struct hciLeSetRandomAddress)); - return HCI_SUCCESS; -} - -uint8_t ll_set_scan_params(uint8_t *params) -{ - if (ll_state == SCANNING) - return HCI_ERR_Controller_Busy; - - memcpy(&ll_scan_params, params, sizeof(struct hciLeSetScanParams)); - - return HCI_SUCCESS; -} - -uint8_t ll_set_advertising_params(uint8_t *params) -{ - if (ll_state == ADVERTISING) - return HCI_ERR_Controller_Busy; - - memcpy(&ll_adv_params, params, sizeof(struct hciLeSetAdvParams)); - - switch (ll_adv_params.advType) { - case BLE_ADV_HEADER_PDU_TYPE_ADV_NONCONN_IND: - case BLE_ADV_HEADER_PDU_TYPE_ADV_SCAN_IND: - if (ll_adv_params.advIntervalMin < - (100000 / LL_ADV_INTERVAL_UNIT_US)) /* 100ms */ - return HCI_ERR_Invalid_HCI_Command_Parameters; - /* Fall through */ - case BLE_ADV_HEADER_PDU_TYPE_ADV_IND: - if (ll_adv_params.advIntervalMin > ll_adv_params.advIntervalMax) - return HCI_ERR_Invalid_HCI_Command_Parameters; - if (ll_adv_params.advIntervalMin < - (20000 / LL_ADV_INTERVAL_UNIT_US) || /* 20ms */ - ll_adv_params.advIntervalMax > - (10240000 / LL_ADV_INTERVAL_UNIT_US)) /* 10.24s */ - return HCI_ERR_Invalid_HCI_Command_Parameters; - ll_adv_interval_us = (((ll_adv_params.advIntervalMin + - ll_adv_params.advIntervalMax) / 2) * - LL_ADV_INTERVAL_UNIT_US); - /* Don't time out */ - ll_adv_timeout_us = -1; - break; - case BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND: - ll_adv_interval_us = LL_ADV_DIRECT_INTERVAL_US; - ll_adv_timeout_us = LL_ADV_DIRECT_TIMEOUT_US; - break; - default: - return HCI_ERR_Invalid_HCI_Command_Parameters; - } - - /* Initialize the ADV PDU */ - ll_adv_pdu.header_type_adv = 1; - ll_adv_pdu.header.adv.type = ll_adv_params.advType; - ll_adv_pdu.header.adv.txaddr = ll_adv_params.useRandomAddress; - - if (ll_adv_params.useRandomAddress) - memcpy(ll_adv_pdu.payload, &ll_random_address, - BLUETOOTH_ADDR_OCTETS); - else - memcpy(ll_adv_pdu.payload, &ll_public_address, - BLUETOOTH_ADDR_OCTETS); - - if (ll_adv_params.advType == BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND) { - ll_adv_pdu.header.adv.rxaddr = - ll_adv_params.directRandomAddress; - memcpy(&ll_adv_pdu.payload[BLUETOOTH_ADDR_OCTETS], - ll_adv_params.directAddr, - sizeof(ll_adv_params.directAddr)); - ll_adv_pdu.header.adv.length = 12; - } else { - ll_adv_pdu.header.adv.rxaddr = 0; - } - - /* All other types get data from SetAdvertisingData */ - - /* Initialize the Scan Rsp PDU */ - ll_scan_rsp_pdu.header_type_adv = 1; - ll_scan_rsp_pdu.header.adv.type = BLE_ADV_HEADER_PDU_TYPE_SCAN_RSP; - ll_scan_rsp_pdu.header.adv.txaddr = ll_adv_params.useRandomAddress; - - if (ll_adv_params.useRandomAddress) - memcpy(ll_scan_rsp_pdu.payload, &ll_random_address, - BLUETOOTH_ADDR_OCTETS); - else - memcpy(ll_scan_rsp_pdu.payload, &ll_public_address, - BLUETOOTH_ADDR_OCTETS); - - ll_scan_rsp_pdu.header.adv.rxaddr = 0; - - return HCI_SUCCESS; -} - -static uint32_t tx_end, rsp_end, tx_rsp_end; -struct ble_pdu ll_rcv_packet; - -/** - * Advertises packet that has already been generated on given channel. - * - * This function also processes any incoming scan requests. - * - * @param chan The channel on which to advertise. - * @returns EC_SUCCESS on packet reception, otherwise error. - */ -int ble_ll_adv(int chan) -{ - int rv; - - ble_radio_init(BLE_ADV_ACCESS_ADDRESS, BLE_ADV_CRCINIT); - - /* Change channel */ - NRF51_RADIO_FREQUENCY = NRF51_RADIO_FREQUENCY_VAL(chan2freq(chan)); - NRF51_RADIO_DATAWHITEIV = chan; - - ble_tx(&ll_adv_pdu); - - while (!RADIO_DONE) - ; - - tx_end = get_time().le.lo; - - if (ll_adv_pdu.header.adv.type == - BLE_ADV_HEADER_PDU_TYPE_ADV_NONCONN_IND) - return EC_SUCCESS; - - rv = ble_rx(&ll_rcv_packet, 16000, 1); - - if (rv != EC_SUCCESS) - return rv; - - while (!RADIO_DONE) - ; - - tx_rsp_end = get_time().le.lo; - - /* Check for valid responses */ - switch (ll_rcv_packet.header.adv.type) { - case BLE_ADV_HEADER_PDU_TYPE_SCAN_REQ: - /* Scan requests are only allowed for ADV_IND and SCAN_IND */ - if ((ll_adv_pdu.header.adv.type != - BLE_ADV_HEADER_PDU_TYPE_ADV_IND && - ll_adv_pdu.header.adv.type != - BLE_ADV_HEADER_PDU_TYPE_ADV_SCAN_IND) || - /* The advertising address needs to match */ - (memcmp(&ll_rcv_packet.payload[BLUETOOTH_ADDR_OCTETS], - &ll_adv_pdu.payload[0], BLUETOOTH_ADDR_OCTETS))) { - /* Don't send the scan response */ - radio_disable(); - return rv; - } - break; - case BLE_ADV_HEADER_PDU_TYPE_CONNECT_REQ: - /* Don't send a scan response */ - radio_disable(); - /* Connecting is only allowed for ADV_IND and ADV_DIRECT_IND */ - if (ll_adv_pdu.header.adv.type != - BLE_ADV_HEADER_PDU_TYPE_ADV_IND && - ll_adv_pdu.header.adv.type != - BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND) - return rv; - /* The advertising address needs to match */ - if (memcmp(&ll_rcv_packet.payload[BLUETOOTH_ADDR_OCTETS], - &ll_adv_pdu.payload[0], BLUETOOTH_ADDR_OCTETS)) - return rv; - /* The InitAddr address needs to match for ADV_DIRECT_IND */ - if (ll_adv_pdu.header.adv.type == - BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND && - memcmp(&ll_adv_pdu.payload[BLUETOOTH_ADDR_OCTETS], - &ll_rcv_packet.payload[0], BLUETOOTH_ADDR_OCTETS)) - return rv; - - /* Mark time that connect was received */ - time_of_connect_req = NRF51_TIMER_CC(0, 1); - - /* - * Enter connection state upon receiving - * a connect request packet - */ - ll_state = CONNECTION; - - return rv; - break; - default: /* Unhandled response packet */ - radio_disable(); - return rv; - break; - } - - CPRINTF("ADV %u Response %u %u\n", tx_end, rsp_end, tx_rsp_end); - - return rv; -} - -int ble_ll_adv_event(void) -{ - int chan_idx; - int rv = EC_SUCCESS; - - for (chan_idx = 0; chan_idx < 3; chan_idx++) { - if (ll_adv_params.advChannelMap & BIT(chan_idx)) { - rv = ble_ll_adv(chan_idx + 37); - if (rv != EC_SUCCESS) - return rv; - } - } - - return rv; -} - - -void print_connection_state(void) -{ - CPRINTF("vvvvvvvvvvvvvvvvvvvCONNECTION STATEvvvvvvvvvvvvvvvvvvv\n"); - CPRINTF("Number of connections events processed: %d\n", ll_conn_events); - CPRINTF("Recovered from %d bad receives.\n", errors_recovered); - CPRINTF("Access addr(hex): %x\n", conn_params.access_addr); - CPRINTF("win_size(hex): %x\n", conn_params.win_size); - CPRINTF("win_offset(hex): %x\n", conn_params.win_offset); - CPRINTF("interval(hex): %x\n", conn_params.interval); - CPRINTF("latency(hex): %x\n", conn_params.latency); - CPRINTF("timeout(hex): %x\n", conn_params.timeout); - CPRINTF("channel_map(hex): %llx\n", conn_params.channel_map); - CPRINTF("hop(hex): %x\n", conn_params.hop_increment); - CPRINTF("SCA(hex): %x\n", conn_params.sleep_clock_accuracy); - CPRINTF("transmitWindowOffset: %d\n", conn_params.transmitWindowOffset); - CPRINTF("connInterval: %d\n", conn_params.connInterval); - CPRINTF("transmitWindowSize: %d\n", conn_params.transmitWindowSize); - CPRINTF("^^^^^^^^^^^^^^^^^^^CONNECTION STATE^^^^^^^^^^^^^^^^^^^\n"); -} - -int connected_communicate(void) -{ - int rv; - long sleep_time; - int offset = 0; - uint64_t listen_time; - uint8_t comm_channel = get_next_data_channel(&remap_table); - - if (num_consecutive_failures > 0) { - ble_radio_init(conn_params.access_addr, - conn_params.crc_init_val); - NRF51_RADIO_FREQUENCY = - NRF51_RADIO_FREQUENCY_VAL(chan2freq(comm_channel)); - NRF51_RADIO_DATAWHITEIV = comm_channel; - listen_time = last_receive_time + conn_params.connInterval - - get_time().val + conn_params.transmitWindowSize; - - /* - * This listens for 1.25 times the expected amount - * of time. This is a margin of error. This line is - * only called when a connection has failed (a missed - * packet). The peripheral and the controller could have - * missed this packet due to a disagreement on when - * the packet should have arrived. We listen for - * slightly longer than expected in the case that - * there was a timing disagreement. - */ - rv = ble_rx(&ll_rcv_packet, - listen_time + (listen_time >> 2), 0); - } else { - if (!is_first_data_packet) { - sleep_time = receive_time + - conn_params.connInterval - get_time().val; - /* - * The time slept is 31/32 (96.875%) of the calculated - * required sleep time because the code to receive - * packets requires time to set up. - */ - usleep(sleep_time - (sleep_time >> 5)); - } else { - last_receive_time = time_of_connect_req; - sleep_time = TRANSMIT_WINDOW_OFFSET_CONSTANT + - conn_params.transmitWindowOffset + - time_of_connect_req - get_time().val; - if (sleep_time >= 0) { - /* - * Radio is on for longer than needed for first - * packet to make sure that it is received. - */ - usleep(sleep_time - (sleep_time >> 2)); - } else { - return EC_ERROR_TIMEOUT; - } - } - - ble_radio_init(conn_params.access_addr, - conn_params.crc_init_val); - NRF51_RADIO_FREQUENCY = - NRF51_RADIO_FREQUENCY_VAL(chan2freq(comm_channel)); - NRF51_RADIO_DATAWHITEIV = comm_channel; - - /* - * Timing the transmit window is very hard to do when the code - * executing has actual effect on the timing. To combat this, - * the radio starts a little early, and terminates when the - * window normally should. The variable 'offset' represents - * how early the window opens in microseconds. - */ - if (!is_first_data_packet) - offset = last_receive_time + conn_params.connInterval - - get_time().val; - else - offset = 0; - - rv = ble_rx(&ll_rcv_packet, - offset + conn_params.transmitWindowSize, - 0); - } - - /* - * The radio shortcuts have been set up so that transmission - * occurs automatically after receiving. The radio just needs - * to know where to find the packet to be sent. - */ - NRF51_RADIO_PACKETPTR = (uint32_t)packet_tb_sent; - - receive_time = NRF51_TIMER_CC(0, 1); - if (rv != EC_SUCCESS) - receive_time = last_receive_time + conn_params.connInterval; - - while (!RADIO_DONE) - ; - - last_receive_time = receive_time; - is_first_data_packet = 0; - - return rv; -} - -static uint32_t ll_adv_events; -static timestamp_t deadline; -static uint32_t start, end; - -void bluetooth_ll_task(void) -{ - uint64_t last_rx_time = 0; - CPRINTS("LL task init"); - - while (1) { - switch (ll_state) { - case ADVERTISING: - - if (deadline.val == 0) { - CPRINTS("ADV @%pP", &ll_adv_pdu); - deadline.val = get_time().val + - (uint32_t)ll_adv_timeout_us; - ll_adv_events = 0; - } - - ble_ll_adv_event(); - ll_adv_events++; - - if (ll_state == CONNECTION) { - receive_time = 0; - break; - } - /* sleep for 0-10ms */ - usleep(ll_adv_interval_us + ll_pseudo_rand(10000)); - - if (get_time().val > deadline.val) { - ll_state = STANDBY; - break; - } - break; - case STANDBY: - deadline.val = 0; - CPRINTS("Standby %d events", ll_adv_events); - ll_adv_events = 0; - ll_conn_events = 0; - task_wait_event(-1); - connection_initialized = 0; - errors_recovered = 0; - break; - case TEST_RX: - if (ble_test_rx() == HCI_SUCCESS) - ll_test_packets++; - /* Packets come every 625us, sleep to save power */ - usleep(300); - break; - case TEST_TX: - start = get_time().le.lo; - ble_test_tx(); - ll_test_packets++; - end = get_time().le.lo; - usleep(625 - 82 - (end-start)); /* 625us */ - break; - case UNINITIALIZED: - ble_radio_init(BLE_ADV_ACCESS_ADDRESS, BLE_ADV_CRCINIT); - ll_adv_events = 0; - task_wait_event(-1); - connection_initialized = 0; - packet_tb_sent = &tx_packet_1; - set_empty_data_packet(&tx_packet_1); - break; - case CONNECTION: - if (!connection_initialized) { - if (initialize_connection() != HCI_SUCCESS) { - ll_state = STANDBY; - break; - } - connection_initialized = 1; - last_rx_time = NRF51_TIMER_CC(0, 1); - } - - if (connected_communicate() == EC_SUCCESS) { - if (num_consecutive_failures > 0) - ++errors_recovered; - num_consecutive_failures = 0; - last_rx_time = get_time().val; - } else { - num_consecutive_failures++; - if ((get_time().val - last_rx_time) > - conn_params.connSupervisionTimeout) { - - ll_state = STANDBY; - CPRINTF("EXITING CONNECTION STATE " - "DUE TO TIMEOUT.\n"); - } - } - ++ll_conn_events; - - if (ll_state == STANDBY) { - CPRINTF("Exiting connection state/Entering " - "Standby state after %d connections " - "events\n", ll_conn_events); - print_connection_state(); - } - break; - default: - CPRINTS("Unhandled State ll_state = %d", ll_state); - ll_state = UNINITIALIZED; - task_wait_event(-1); - } - } -} - |