diff options
author | Myles Watson <mylesgw@chromium.org> | 2014-12-23 16:58:01 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-08-02 23:20:41 -0700 |
commit | ef137bdecce224d7d6877e609ee84dd6984b74fc (patch) | |
tree | ff970ba0325b24e9c712b82cfd8e0a40f15ae6ea | |
parent | d173f84190988a9abbb06873c9456c3388602678 (diff) | |
download | chrome-ec-ef137bdecce224d7d6877e609ee84dd6984b74fc.tar.gz |
common: Add Bluetooth LE support
Add data structures, defines, and helper functions to parse
packets and implement frequency hopping.
BUG=None
BRANCH=None
TEST=None
Change-Id: I0f7a7d4bee55e00343f6f87f304fb2ba57cb6ec0
Signed-off-by: Myles Watson <mylesgw@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/362174
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Levi Oliver <levio@google.com>
-rw-r--r-- | common/bluetooth_le.c | 192 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | include/bluetooth_le.h | 393 |
3 files changed, 586 insertions, 0 deletions
diff --git a/common/bluetooth_le.c b/common/bluetooth_le.c new file mode 100644 index 0000000000..78b2d934bd --- /dev/null +++ b/common/bluetooth_le.c @@ -0,0 +1,192 @@ +/* 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.h" +#include "util.h" +#include "console.h" + +#define CPRINTF(format, args...) cprintf(CC_BLUETOOTH_LE, format, ## args) + +/* + * Convert from BLE Channel to frequency + * + * Bluetooth 4.1 Vol 6 pg 36 4.1 Table 1.1 + */ + +#define CHAN_0_MHZ 2404 +#define CHAN_11_MHZ 2428 +#define CHAN_37_MHZ 2402 +#define CHAN_38_MHZ 2426 +#define CHAN_39_MHZ 2480 + +int chan2freq(int channel) +{ + int freq; + + ASSERT(channel < 40 && channel >= 0); + + switch (channel) { + case 37: /* Advertising */ + freq = CHAN_37_MHZ; + break; + case 38: /* Advertising */ + freq = CHAN_38_MHZ; + break; + case 39: /* Advertising */ + freq = CHAN_39_MHZ; + break; + default: + /* Data Channels */ + if (channel < 11) + freq = channel * 2 + CHAN_0_MHZ; + else + freq = (channel - 11) * 2 + CHAN_11_MHZ; + } + return freq; +} + +/* BLE 4.1 Vol 6 2.3.3.1 */ + +void fill_remapping_table(struct remapping_table *rt, uint8_t map[5], + int hop_increment) +{ + int i; + + rt->num_used_channels = 0; + rt->last_unmapped_channel = 0; + rt->hop_increment = hop_increment; + + for (i = 0; i < 37; i++) + if (map[i / 8] & (1 << (i % 8))) + rt->remapping_index[rt->num_used_channels++] = i; + memcpy(rt->map, map, sizeof(rt->map)); +} + +/* BLE 4.1 Vol 6 4.5.8 */ + +int select_data_channel(struct remapping_table *rt) +{ + rt->last_unmapped_channel = + (rt->last_unmapped_channel + rt->hop_increment) % 37; + + /* Check if the channel is mapped */ + if (rt->map[rt->last_unmapped_channel / 8] & + (1 << (rt->last_unmapped_channel % 8))) + return rt->last_unmapped_channel; + else + return rt->remapping_index + [rt->last_unmapped_channel % rt->num_used_channels]; +} + +/* BLE 4.1 Vol 3 Part C 11 */ + +/* Pack advertising structures for sending */ +uint8_t *pack_adv(uint8_t *dest, int length, int type, const uint8_t *data) +{ + /* Add the structure length */ + dest[0] = (uint8_t)length+1; + /* Add the structure type */ + dest[1] = (uint8_t)type; + /* Add the data */ + memcpy(&dest[2], data, length); + + /* Return a pointer to the next structure */ + return &dest[2+length]; +} + +uint8_t *pack_adv_int(uint8_t *dest, int length, int type, int data) +{ + /* Add the structure length */ + dest[0] = (uint8_t)length+1; + /* Add the structure type */ + dest[1] = (uint8_t)type; + /* Add the data */ + memcpy(&dest[2], &data, length); + + /* Return a pointer to the next structure */ + return &dest[2+length]; +} + +uint8_t *pack_adv_addr(uint8_t *dest, uint64_t addr) +{ + memcpy(&dest[0], &addr, BLUETOOTH_ADDR_OCTETS); + + /* Return a pointer to the next structure */ + return &dest[BLUETOOTH_ADDR_OCTETS]; +} + +/* Parse advertising structures that have been received */ +const uint8_t *unpack_adv(const uint8_t *src, int *length, int *type, + const uint8_t **data) +{ + /* Get the structure length */ + *length = *(src++); + /* Get the structure type */ + *type = *(src++); + /* Get the data */ + *data = src; + + /* Return a pointer to the next structure */ + return src + *length; +} + +static void mem_dump(uint8_t *mem, int len) +{ + int i; + uint8_t value; + + for (i = 0; i < len; i++) { + value = mem[i]; + if (i % 8 == 0) + CPRINTF("\n%08x: %02x", &mem[i], value); + else + CPRINTF(" %02x", value); + } + CPRINTF("\n"); +} + +void dump_ble_addr(uint8_t *mem, char *name) +{ + int i; + + for (i = 5; i > 0; i--) + CPRINTF("%02x.", mem[i]); + CPRINTF("%02x %s\n", mem[0], name); +} + +void dump_ble_packet(struct ble_pdu *ble_p) +{ + int curr_offs; + + if (ble_p->header_type_adv) { + CPRINTF("BLE packet @ %p: type %d, len %d, %s %s\n", + ble_p, ble_p->header.adv.type, ble_p->header.adv.length, + (ble_p->header.adv.txaddr ? " TXADDR" : ""), + (ble_p->header.adv.rxaddr ? " RXADDR" : "")); + + curr_offs = 0; + + if (ble_p->header.adv.type == + BLE_ADV_HEADER_PDU_TYPE_SCAN_REQ) { + dump_ble_addr(ble_p->payload, "ScanA"); + curr_offs += BLUETOOTH_ADDR_OCTETS; + } else if (ble_p->header.adv.type == + BLE_ADV_HEADER_PDU_TYPE_CONNECT_REQ) { + dump_ble_addr(ble_p->payload, "InitA"); + curr_offs += BLUETOOTH_ADDR_OCTETS; + } + /* All packets have AdvA */ + dump_ble_addr(ble_p->payload + curr_offs, "AdvA"); + curr_offs += BLUETOOTH_ADDR_OCTETS; + + if (ble_p->header.adv.type == + BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND) + dump_ble_addr(ble_p->payload + curr_offs, "InitA"); + else + mem_dump(ble_p->payload + curr_offs, + ble_p->header.adv.length - curr_offs); + } +} + diff --git a/common/build.mk b/common/build.mk index 2e0eb3e946..9a11df345d 100644 --- a/common/build.mk +++ b/common/build.mk @@ -25,6 +25,7 @@ common-$(CONFIG_BACKLIGHT_LID)+=backlight_lid.o common-$(CONFIG_BATTERY_BQ27541)+=battery.o common-$(CONFIG_BATTERY_BQ27621)+=battery.o common-$(CONFIG_BATTERY_SMART)+=battery.o +common-$(CONFIG_BLUETOOTH_LE)+=bluetooth_le.o common-$(CONFIG_BUTTON_COUNT)+=button.o common-$(CONFIG_CAPSENSE)+=capsense.o common-$(CONFIG_CASE_CLOSED_DEBUG)+=case_closed_debug.o diff --git a/include/bluetooth_le.h b/include/bluetooth_le.h new file mode 100644 index 0000000000..65be0d0fbd --- /dev/null +++ b/include/bluetooth_le.h @@ -0,0 +1,393 @@ +/* Copyright (c) 2014 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. + */ + +/* Bluetooth LE packet formats, etc. */ + +/* + * Since the fields are all little endian, + * + * uint16_t two_octets; + * + * is used in place of + * + * uint8_t two_single_octets[2]; + * + * in many places. + */ + +#ifndef __CROS_EC_BLE_H +#define __CROS_EC_BLE_H + +#include "common.h" +#include "util.h" + +#define BLUETOOTH_ADDR_OCTETS 6 + +/* + * GAP assigned numbers + * https://www.bluetooth.org/en-us/specification/ + * assigned-numbers/generic-access-profile + */ +#define GAP_FLAGS 0x01 +#define GAP_INCOMP_16_BIT_UUID 0x02 +#define GAP_COMP_16_BIT_UUID 0x03 +#define GAP_INCOMP_32_BIT_UUID 0x04 +#define GAP_COMP_32_BIT_UUID 0x05 +#define GAP_INCOMP_128_BIT_UUID 0x06 +#define GAP_COMP_128_BIT_UUID 0x07 +#define GAP_SHORT_NAME 0x08 +#define GAP_COMPLETE_NAME 0x09 +#define GAP_TX_POWER_LEVEL 0x0A +#define GAP_CLASS_OF_DEVICE 0x0D +#define GAP_SIMPLE_PAIRING_HASH 0x0E +#define GAP_SIMPLE_PAIRING_HASH_192 0x0E +#define GAP_SIMPLE_PAIRING_RAND 0x0F +#define GAP_SIMPLE_PAIRING_RAND_192 0x0F +#define GAP_DEVICE_ID 0x10 +#define GAP_SECURITY_MANAGER_TK 0x10 +#define GAP_SECURITY_MANAGER_OOB_FLAGS 0x11 +#define GAP_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 +#define GAP_SERVICE_SOLICITATION_UUID_16 0x14 +#define GAP_SERVICE_SOLICITATION_UUID_32 0x1F +#define GAP_SERVICE_SOLICITATION_UUID_128 0x15 +#define GAP_SERVICE_DATA 0x16 +#define GAP_SERVICE_DATA_UUID_16 0x16 +#define GAP_SERVICE_DATA_UUID_32 0x20 +#define GAP_SERVICE_DATA_UUID_128 0x21 +#define GAP_LE_SECURE_CONNECTIONS_CONFIRMATION 0x22 +#define GAP_LE_SECURE_CONNECTIONS_RAND 0x23 +#define GAP_PUBLIC_TARGET_ADDRESS 0x17 +#define GAP_RANDOM_TARGET_ADDRESS 0x18 +#define GAP_APPEARANCE 0x19 +#define GAP_ADVERTISING_INTERVAL 0x1A +#define GAP_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B +#define GAP_LE_ROLE 0x1C +#define GAP_SIMPLE_PAIRING_HASH_256 0x1D +#define GAP_SIMPLE_PAIRING_RAND_256 0x1E +#define GAP_3D_INFORMATION_DATA 0x3D +#define GAP_MANUFACTURER_SPECIFIC_DATA 0xFF + + +/* org.bluetooth.characteristic.gap.appearance.xml */ +#define GAP_APPEARANCE_HID_KEYBOARD 961 + +/* org.bluetooth.service.human_interface_device.xml */ +#define GATT_SERVICE_HID_UUID 0x1812 + +/* Bluetooth Core Supplement v5 */ + +/* Bluetooth Core Supplement v5 1.3 */ +#define GAP_FLAGS_LE_LIM_DISC 0x01 +#define GAP_FLAGS_LE_GEN_DISC 0x02 +#define GAP_FLAGS_LE_NO_BR_EDR 0x04 + +/* Bluetooth Core Supplement v5 1.3 */ + + +/* BLE 4.1 Vol 6 section 2.3 pg 38+ */ + +/* Advertising PDU Header + * 16 Bits: + * 4 bit type + * 1 bit TxAddr + * 1 bit RxAddr + * 6 bit length (length of the payload in bytes) + */ + +struct ble_adv_header { + uint8_t type; + uint8_t txaddr; + uint8_t rxaddr; + uint8_t length; +}; + +#define BLE_ADV_HEADER_PDU_TYPE_SHIFT 0 +#define BLE_ADV_HEADER_TXADD_SHIFT 6 +#define BLE_ADV_HEADER_RXADD_SHIFT 7 +#define BLE_ADV_HEADER_LENGTH_SHIFT 8 + +#define BLE_ADV_HEADER(type, tx, rx, length) \ + ((uint16_t) \ + ((((length) & 0x3f) << BLE_ADV_HEADER_LENGTH_SHIFT) | \ + (((rx) & 0x1) << BLE_ADV_HEADER_RXADD_SHIFT) | \ + (((tx) & 0x1) << BLE_ADV_HEADER_TXADD_SHIFT) | \ + (((type) & 0xf) << BLE_ADV_HEADER_PDU_TYPE_SHIFT))) + +#define BLE_ADV_HEADER_PDU_TYPE_ADV_IND 0 +#define BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND 1 +#define BLE_ADV_HEADER_PDU_TYPE_ADV_NONCONN_IND 2 +#define BLE_ADV_HEADER_PDU_TYPE_SCAN_REQ 3 +#define BLE_ADV_HEADER_PDU_TYPE_SCAN_RSP 4 +#define BLE_ADV_HEADER_PDU_TYPE_CONNECT_REQ 5 +#define BLE_ADV_HEADER_PDU_TYPE_ADV_SCAN_IND 6 + +#define BLE_ADV_HEADER_PUBLIC_ADDR 0 +#define BLE_ADV_HEADER_RANDOM_ADDR 1 + +/* BLE 4.1 Vol 3 Part C 10.8 */ +#define BLE_RANDOM_ADDR_MSBS_PRIVATE 0x00 +#define BLE_RANDOM_ADDR_MSBS_RESOLVABLE_PRIVATE 0x40 +#define BLE_RANDOM_ADDR_MSBS_RFU 0x80 +#define BLE_RANDOM_ADDR_MSBS_STATIC 0xC0 + +#define BLE_ADV_ACCESS_ADDRESS 0x8E89BED6 + +#define BLE_MAX_ADV_PAYLOAD_OCTETS 37 + +/* BLE 4.1 Vol 6 2.3.3.1 */ +struct ble_ll_data { + uint8_t aa[4]; /* Access Address */ + uint8_t crc_init[3]; + uint8_t win_size; /* Transmit Window Size */ + uint16_t win_offset; /* Transmit Window Offset */ + uint16_t interval; /* Connection Interval */ + uint16_t latency; /* Connection Slave Latency */ + uint16_t timeout; /* Connection Supervision Timeout */ + uint8_t chm[5]; /* 37-bit Channel Map */ + uint8_t hop_and_sca; /* Hop Increment and Sleep-clock Accuracy */ +} __packed; + +/* LL SCA Values. They are shifted left 5 bits for Hop values */ +#define BLE_LL_SCA_251_PPM_TO_500_PPM (0 << 5) +#define BLE_LL_SCA_151_PPM_TO_250_PPM (1 << 5) +#define BLE_LL_SCA_101_PPM_TO_150_PPM (2 << 5) +#define BLE_LL_SCA_076_PPM_TO_100_PPM (3 << 5) +#define BLE_LL_SCA_051_PPM_TO_075_PPM (4 << 5) +#define BLE_LL_SCA_031_PPM_TO_050_PPM (5 << 5) +#define BLE_LL_SCA_021_PPM_TO_030_PPM (6 << 5) +#define BLE_LL_SCA_000_PPM_TO_020_PPM (7 << 5) + +/* BLE 4.1 Vol 6 section 2.4 pg 45 */ + +/* Data PDU Header + * 16 Bits: + * 2 bit LLID ( Control or Data ) + * 1 bit NESN ( Next expected sequence number ) + * 1 bit SN ( Sequence Number ) + * 1 bit MD ( More Data ) + * 5 bit length ( length of the payload + MIC in bytes ) + * + * This struct isn't packed, since it isn't sent to the radio. + * + */ + +struct ble_data_header { + uint8_t llid; + uint8_t nesn; + uint8_t sn; + uint8_t md; + uint8_t length; +}; + +#define BLE_DATA_HEADER_LLID_SHIFT 0 +#define BLE_DATA_HEADER_NESN_SHIFT 2 +#define BLE_DATA_HEADER_SN_SHIFT 3 +#define BLE_DATA_HEADER_MD_SHIFT 4 +#define BLE_DATA_HEADER_LENGTH_SHIFT 8 + +#define BLE_DATA_HEADER_LLID_DATANOSTART 1 +#define BLE_DATA_HEADER_LLID_DATASTART 2 +#define BLE_DATA_HEADER_LLID_CONTROL 3 + +#define BLE_DATA_HEADER(llid, nesn, sn, md, length) \ + ((uint16_t) \ + ((((length) & 0x1f) << BLE_DATA_HEADER_LENGTH_SHIFT) | \ + (((MD) & 0x1) << BLE_DATA_HEADER_MD_SHIFT) | \ + (((SN) & 0x1) << BLE_DATA_HEADER_SN_SHIFT) | \ + (((NESN) & 0x1) << BLE_DATA_HEADER_NESN_SHIFT) | \ + (((llid) & 0x3) << BLE_DATA_HEADER_LLID_SHIFT))) + +#define BLE_MAX_DATA_PAYLOAD_OCTETS 31 +#define BLE_MAX_PAYLOAD_OCTETS BLE_MAX_ADV_PAYLOAD_OCTETS + +union ble_header { + struct ble_adv_header adv; + struct ble_data_header data; +}; + +struct ble_pdu { + union ble_header header; + uint8_t header_type_adv; + uint8_t payload[BLE_MAX_PAYLOAD_OCTETS]; + uint32_t mic; /* Only included in PDUs with encrypted payloads. */ +}; + +struct ble_packet { + /* uint8_t preamble; */ + uint32_t access_address; + struct ble_pdu pdu; + /* uint32_t crc; */ +}; + +/* LL Control PDU Opcodes BLE 4.1 Vol 6 2.4.2 */ +#define BLE_LL_CONNECTION_UPDATE_REQ 0x00 +#define BLE_LL_CHANNEL_MAP_REQ 0x01 +#define BLE_LL_TERMINATE_IND 0x02 +#define BLE_LL_ENC_REQ 0x03 +#define BLE_LL_ENC_RSP 0x04 +#define BLE_LL_START_ENC_REQ 0x05 +#define BLE_LL_START_ENC_RSP 0x06 +#define BLE_LL_UNKNOWN_RSP 0x07 +#define BLE_LL_FEATURE_REQ 0x08 +#define BLE_LL_FEATURE_RSP 0x09 +#define BLE_LL_PAUSE_ENC_REQ 0x0A +#define BLE_LL_PAUSE_ENC_RSP 0x0B +#define BLE_LL_VERSION_IND 0x0C +#define BLE_LL_REJECT_IND 0x0D +#define BLE_LL_SLAVE_FEATURE_REQ 0x0E +#define BLE_LL_CONNECTION_PARAM_REQ 0x0F +#define BLE_LL_CONNECTION_PARAM_RSP 0x10 +#define BLE_LL_REJECT_IND_EXT 0x11 +#define BLE_LL_PING_REQ 0x12 +#define BLE_LL_PING_RSP 0x13 +#define BLE_LL_RFU 0x14 + +/* BLE 4.1 Vol 6 4.6 Table 4.3 */ +#define BLE_LL_FEATURE_LE_ENCRYPTION 0x00 +#define BLE_LL_FEATURE_CONN_PARAMS_REQ 0x01 +#define BLE_LL_FEATURE_EXT_REJ_IND 0x02 +#define BLE_LL_FEATURE_SLAVE_FEAT_EXCHG 0x03 +#define BLE_LL_FEATURE_LE_PING 0x04 + +struct ble_ll_connection_update_req { + uint8_t win_size; + uint16_t win_offset; + uint16_t interval; + uint16_t latency; + uint16_t timeout; + uint16_t instant; +} __packed; + +struct ble_ll_channel_map_req { + uint8_t map[5]; + uint16_t instant; +} __packed; + +/* ble_ll_terminate_ind: single-byte error code */ + +struct ble_ll_enc_req { + uint8_t rand[8]; + uint16_t ediv; + uint8_t skdm[8]; + uint8_t ivm[4]; +} __packed; + +struct ble_ll_enc_rsp { + uint8_t skds[8]; + uint8_t ivs[4]; +} __packed; + +/* ble_ll_start_enc_req has no CtrData field */ + +/* ble_ll_start_enc_rsp has no CtrData field */ + +/* ble_ll_unknown_rsp: single-byte error code */ + +struct ble_ll_feature_req { + uint8_t feature_set[8]; +} __packed; + +struct ble_ll_feature_rsp { + uint8_t feature_set[8]; +} __packed; + +/* ble_ll_pause_enc_req has no CtrData field */ + +/* ble_ll_pause_enc_rsp has no CtrData field */ + +#define BLE_LL_VERS_NR_4_0 6 +#define BLE_LL_VERS_NR_4_1 7 + +struct ble_ll_version_ind { + uint8_t vers_nr; /* Version Number */ + uint16_t comp_id; /* Company ID */ + uint16_t sub_vers_nr; /* Subversion Number */ +} __packed; + +/* ble_ll_reject_ind: single-byte error code */ + +struct ble_ll_slave_feature_req { + uint8_t feature_set[8]; +} __packed; + +/* ble_ll_connection_param (req and rsp) */ + +struct ble_ll_connection_param { + uint16_t interval_min; /* times 1.25 ms */ + uint16_t interval_max; /* times 1.25 ms */ + uint16_t latency; /* connection events */ + uint16_t timeout; /* times 10 ms */ + uint8_t preferred_periodicity; /* times 1.25 ms */ + uint16_t reference_conn_event_count; /* base for offsets*/ + uint16_t offset0; /* Anchor offset from reference (preferred) */ + uint16_t offset1; + uint16_t offset2; + uint16_t offset3; + uint16_t offset4; + uint16_t offset5; /* least preferred */ +} __packed; + +struct ble_ll_reject_ind_ext { + uint8_t reject_opcode; + uint8_t error_code; +} __packed; + +/* ble_ll_ping_req has no CtrData field */ + +/* ble_ll_ping_rsp has no CtrData field */ + +/* BLE 4.1 Vol 6 4.5.8 */ +struct remapping_table { + uint8_t remapping_index[37]; + uint8_t map[5]; + int num_used_channels; + int hop_increment; + int last_unmapped_channel; +}; + +/* BLE 4.1 Vol 6 4.5.9 */ +struct connection_data { + int transmit_seq_num; + int next_expected_seq_num; + struct remapping_table rt; + /* Add timing information */ +}; + +/* BLE 4.1 Vol 6 1.4.1 */ +int chan2freq(int channel); + +/* BLE 4.1 Vol 6 2.3.3.1 */ +void fill_remapping_table(struct remapping_table *rt, uint8_t map[5], + int hop_increment); + +void ble_tx(struct ble_pdu *pdu); + +int ble_ll_rx(struct ble_pdu *pdu, int timeout, int adv); + +int ble_radio_init(void); + +/* BLE 4.1 Vol 6 4.5.8 */ +int select_data_channel(struct remapping_table *rt); + +/* BLE 4.1 Vol 3 Part C 11 */ +uint8_t *pack_adv(uint8_t *dest, int length, int type, const uint8_t *data); +uint8_t *pack_adv_int(uint8_t *dest, int length, int type, int data); +uint8_t *pack_adv_addr(uint8_t *dest, uint64_t addr); + +const uint8_t *unpack_adv(const uint8_t *src, int *length, int *type, + const uint8_t **data); + +void dump_ble_addr(uint8_t *mem, char *name); + +void dump_ble_packet(struct ble_pdu *ble_p); + +/* Radio-specific white list handling */ +int ble_radio_clear_white_list(void); +int ble_radio_read_white_list_size(uint8_t *ret_size); +int ble_radio_add_device_to_white_list(const uint8_t *addr_ptr, uint8_t rand); +int ble_radio_remove_device_from_white_list(const uint8_t *addr_ptr, + uint8_t rand); + +#endif /* __CROS_EC_BLE_H */ |