/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "applib/bluetooth/ble_ibeacon.h" #include #include "clar.h" // Stubs /////////////////////////////////////////////////////////// #include "stubs_logging.h" #include "stubs_passert.h" #include "stubs_pbl_malloc.h" #include "stubs_pebble_tasks.h" #include "stubs_rand_ptr.h" #include "stubs_ble_syscalls.h" // The test data and descriptions in this file are captured using the FrontLine // Bluetooth sniffer. // AD Element, Length: 26, AD Type: Manufacturer Specific, Manufacturer ID: // Apple, Inc. (0x004c) Additional Data: 0x 02 15 97 6e bb 18 d3 e9 43 c0 8a // 63 8d 2b 60 d9 04 2a 00 0c 00 22 c5 // This excludes the "Manufacturer Specific" opcode (0xff) but it // includes the Apple Inc company ID: static BLEAdData *create_apple_ibeacon_ad_data(void) { static const uint8_t apple_ibeacon_ad_element[] = { 0x1a, // 26 bytes 0xff, // Manufacturer Specific AD Type 0x4c, 0x00, // Apple 0x02, // iBeacon 0x15, // Number of bytes to follow 0x97, 0x6e, 0xbb, 0x18, 0xd3, 0xe9, 0x43, 0xc0, // Proximity UUID 0x8a, 0x63, 0x8d, 0x2b, 0x60, 0xd9, 0x04, 0x2a, 0x00, 0x0c, // Minor (BE) 0x00, 0x22, // Major (BE) 0xc5 // TX Power }; const size_t ad_data_length = sizeof(apple_ibeacon_ad_element); BLEAdData *ad_data = (BLEAdData *) malloc(sizeof(BLEAdData) + ad_data_length); ad_data->ad_data_length = ad_data_length; ad_data->scan_resp_data_length = 0; memcpy(ad_data->data, apple_ibeacon_ad_element, ad_data_length); return ad_data; } void test_ble_ibeacon__parse_ibeacon_data(void) { BLEAdData *apple_ibeacon_ad_data = create_apple_ibeacon_ad_data(); BLEiBeacon ibeacon; const int8_t rssi = -60; bool is_ibeacon = ble_ibeacon_parse(apple_ibeacon_ad_data, rssi, &ibeacon); cl_assert(is_ibeacon); uint8_t uuid_bytes[] = "\x97\x6e\xbb\x18\xd3\xe9\x43\xc0\x8a\x63\x8d\x2b" \ "\x60\xd9\x04\x2a"; Uuid uuid = UuidMakeFromBEBytes(uuid_bytes); cl_assert(uuid_equal(&ibeacon.uuid, &uuid)); cl_assert_equal_i(ibeacon.major, 12); cl_assert_equal_i(ibeacon.minor, 34); cl_assert_equal_i(ibeacon.rssi, -60); cl_assert_equal_i(ibeacon.calibrated_tx_power, -59); // cl_assert_equal_i(ibeacon.distance_cm, 110); free(apple_ibeacon_ad_data); } void test_ble_ibeacon__ibeacon_compose(void) { BLEAdData *apple_ibeacon_ad_data = create_apple_ibeacon_ad_data(); BLEiBeacon ibeacon; const int8_t rssi = -60; ble_ibeacon_parse(apple_ibeacon_ad_data, rssi, &ibeacon); BLEAdData *new_ibeacon_ad_data = ble_ad_create(); cl_assert_equal_b(ble_ibeacon_compose(&ibeacon, new_ibeacon_ad_data), true); const size_t ad_data_size = apple_ibeacon_ad_data->ad_data_length + apple_ibeacon_ad_data->scan_resp_data_length; cl_assert_equal_i(new_ibeacon_ad_data->ad_data_length, apple_ibeacon_ad_data->ad_data_length); cl_assert_equal_i(new_ibeacon_ad_data->scan_resp_data_length, apple_ibeacon_ad_data->scan_resp_data_length); cl_assert_equal_i(memcmp(new_ibeacon_ad_data->data, apple_ibeacon_ad_data->data, ad_data_size), 0); free(apple_ibeacon_ad_data); ble_ad_destroy(new_ibeacon_ad_data); } static BLEAdData *create_too_short_ad_data(void) { static const uint8_t too_short_ad_element[] = { 0x1a, // 26 bytes 0xff, // Manufacturer Specific AD Type 0x4c, 0x00, // Apple 0x02, // iBeacon 0x14, // Number of bytes to follow -- Internally inconsistent! 0x97, 0x6e, 0xbb, 0x18, 0xd3, 0xe9, 0x43, 0xc0, // Proximity UUID 0x8a, 0x63, 0x8d, 0x2b, 0x60, 0xd9, 0x04, 0x2a, 0x00, 0x0c, // Minor (BE) 0x00, 0x22, // Major (BE) 0xc5 // TX Power }; BLEAdData *ad_data = (BLEAdData *) malloc(sizeof(BLEAdData) + sizeof(too_short_ad_element)); ad_data->ad_data_length = sizeof(too_short_ad_element); ad_data->scan_resp_data_length = 0; return ad_data; } void test_ble_ibeacon__ibeacon_data_too_short(void) { BLEAdData *too_short_to_ibeacon = create_too_short_ad_data(); bool is_ibeacon = ble_ibeacon_parse(too_short_to_ibeacon, 0, NULL); cl_assert(!is_ibeacon); free(too_short_to_ibeacon); }