Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

@ -0,0 +1,21 @@
/*
* 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 <stdint.h>
typedef struct GAPLEAdvertisingJobTerm GAPLEAdvertisingJobTerm;
const GAPLEAdvertisingJobTerm *bt_driver_adv_reconnect_get_job_terms(size_t *num_terms_out);

View file

@ -0,0 +1,48 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "util/attributes.h"
#include <bluetooth/bluetooth_types.h>
#include <bluetooth/conn_event_stats.h>
#define NUM_LE_CHANNELS 37
typedef struct PACKED LEChannelMap {
uint8_t byte0;
uint8_t byte1;
uint8_t byte2;
uint8_t byte3;
uint8_t byte4;
} LEChannelMap;
bool bt_driver_analytics_get_connection_quality(const BTDeviceInternal *address,
uint8_t *link_quality_out, int8_t *rssi_out);
bool bt_driver_analytics_collect_ble_parameters(const BTDeviceInternal *addr,
LEChannelMap *le_chan_map_res);
void bt_driver_analytics_external_collect_chip_specific_parameters(void);
void bt_driver_analytics_external_collect_bt_chip_heartbeat(void);
//! Returns true iff there are connection event stats to report
bool bt_driver_analytics_get_conn_event_stats(SlaveConnEventStats *stats);

View file

@ -0,0 +1,281 @@
/*
* 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.
*/
#pragma once
#include "util/uuid.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
//! Bluetooth error codes.
typedef enum {
//! The operation was successful.
BTErrnoOK = 0,
//! Connection established succesfully.
BTErrnoConnected = BTErrnoOK,
//! One or more parameters were invalid.
BTErrnoInvalidParameter = 1,
//! The connection was terminated because it timed out. Examples of cause for
//! a connection timeout are: devices going out of range of each other or
//! lost packets due to RF interference.
BTErrnoConnectionTimeout = 2,
//! The connection was terminated by the remote device.
BTErrnoRemotelyTerminated = 3,
//! The connection was terminated by the system.
BTErrnoLocallyTerminatedBySystem = 4,
//! The connection was terminated by the application.
BTErrnoLocallyTerminatedByApp = 5,
//! The system did not have enough resources for the operation.
BTErrnoNotEnoughResources = 6,
//! The remote device does not support pairing.
BTErrnoPairingNotSupported = 7,
//! The pairing failed because the user did not confirm.
BTErrnoPairingConfirmationFailed = 8,
//! The pairing failed because it timed out.
BTErrnoPairingTimeOut = 9,
//! The pairing failed because Out-of-Band data was not available.
BTErrnoPairingOOBNotAvailable = 10,
//! The requested operation cannot be performed in the current state.
BTErrnoInvalidState = 11,
//! GATT Service Discovery timed out
BTErrnoServiceDiscoveryTimeout = 12,
//! GATT Service Discovery failed due to disconnection
BTErrnoServiceDiscoveryDisconnected = 13,
//! GATT Service Discovery was restarted because the remote device indicated that it changed
//! its GATT database. Prior BLEService, BLECharacteristic and BLEDescriptor handles must be
//! invalidated when receiving this status code. The system will automatically start the
//! service discovery process again, therefore apps do not need to call
//! ble_client_discover_services_and_characteristics() again.
BTErrnoServiceDiscoveryDatabaseChanged = 14,
//! Errors after this value are internal Bluetooth stack errors that could not
//! be mapped onto more meaningful errors by the system.
BTErrnoInternalErrorBegin = 9000,
//! Errors after this fvalue are HCI errors that could not be mapped into more
//! meaningful errors by the system.
BTErrnoHCIErrorBegin = 10000,
//! Other, uncategorized error.
//! @internal This is also the highest allowed value (14 bits all set).
//! See PebbleBLEGATTClientEvent for why.
BTErrnoOther = 0x3fff,
} BTErrno;
//! Error values that can be returned by the server in response to read, write
//! and subscribe operations. These error values correspond to the (G)ATT error
//! codes as specified in the Bluetooth 4.0 Specification, Volume 3, Part F,
//! 3.4.1.1, Table 3.3.
typedef enum {
BLEGATTErrorSuccess = 0x00,
BLEGATTErrorInvalidHandle = 0x01,
BLEGATTErrorReadNotPermitted = 0x02,
BLEGATTErrorWriteNotPermitted = 0x03,
BLEGATTErrorInvalidPDU = 0x04,
BLEGATTErrorInsufficientAuthentication = 0x05,
BLEGATTErrorRequestNotSupported = 0x06,
BLEGATTErrorInvalidOffset = 0x07,
BLEGATTErrorInsufficientAuthorization = 0x08,
BLEGATTErrorPrepareQueueFull = 0x09,
BLEGATTErrorAttributeNotFound = 0x0A,
BLEGATTErrorAttributeNotLong = 0x0B,
BLEGATTErrorInsufficientEncrpytionKeySize = 0x0C,
BLEGATTErrorInvalidAttributeValueLength = 0x0D,
BLEGATTErrorUnlikelyError = 0x0E,
BLEGATTErrorInsufficientEncryption = 0x0F,
BLEGATTErrorUnsupportedGroupType = 0x10,
BLEGATTErrorInsufficientResources = 0x11,
BLEGATTErrorApplicationSpecificErrorStart = 0x80,
BLEGATTErrorApplicationSpecificErrorEnd = 0xFC,
BLEGATTErrorCCCDImproperlyConfigured = 0xFD,
BLEGATTErrorProcedureAlreadyInProgress = 0xFE,
BLEGATTErrorOutOfRange = 0xFF,
BLEGATTErrorRequestTimeOut = 0x100,
BLEGATTErrorRequestPrepareWriteDataMismatch = 0x101,
BLEGATTErrorLocalInsufficientResources = 0x102,
} BLEGATTError;
//! @internal Macro to map Bluetopia errors to BTErrno
#define BTErrnoWithBluetopiaError(e) ((int) BTErrnoInternalErrorBegin - e)
//! @internal Macro to map HCI errors to BTErrno
#define BTErrnoWithHCIError(e) ((int) BTErrnoHCIErrorBegin + e)
//! Property bits of a characteristic
//! See the Bluetooth 4.0 Specification, Volume 3, Part G,
//! 3.3.1.1 "Characteristic Properties" for more details.
//! @see ble_characteristic_get_properties
typedef enum {
BLEAttributePropertyNone = 0,
BLEAttributePropertyBroadcast = (1 << 0),
BLEAttributePropertyRead = (1 << 1),
BLEAttributePropertyWriteWithoutResponse = (1 << 2),
BLEAttributePropertyWrite = (1 << 3),
BLEAttributePropertyNotify = (1 << 4),
BLEAttributePropertyIndicate = (1 << 5),
BLEAttributePropertyAuthenticatedSignedWrites = (1 << 6),
BLEAttributePropertyExtendedProperties = (1 << 7),
// Properties for Characteristics & Descriptors that
// are hosted by the local server:
BLEAttributePropertyReadingRequiresEncryption = (1 << 8),
BLEAttributePropertyWritingRequiresEncryption = (1 << 9),
} BLEAttributeProperty;
//! Opaque reference to a service object.
typedef uintptr_t BLEService;
//! Opaque reference to a characteristic object.
typedef uintptr_t BLECharacteristic;
//! Opaque reference to a descriptor object.
typedef uintptr_t BLEDescriptor;
_Static_assert(sizeof(BLEDescriptor) == sizeof(uintptr_t), "BLEDescriptor is invalid size");
_Static_assert(sizeof(BLECharacteristic) == sizeof(uintptr_t), "BLECharacteristic is invalid size");
#define BLE_SERVICE_INVALID ((BLEService) 0)
#define BLE_CHARACTERISTIC_INVALID ((BLECharacteristic) 0)
#define BLE_DESCRIPTOR_INVALID ((BLEDescriptor) 0)
//! Identifier for a device bonding.
//! They stay the same across reboots, so they can be persisted by apps.
typedef uint8_t BTBondingID;
#define BT_BONDING_ID_INVALID ((BTBondingID) ~0)
typedef struct __attribute__((__packed__)) BTDeviceAddress {
uint8_t octets[6];
} BTDeviceAddress;
//! Size of a BTDeviceAddress struct
#define BT_DEVICE_ADDRESS_SIZE (sizeof(BTDeviceAddress))
//! Print format for printing BTDeviceAddress structs
//! @see BT_DEVICE_ADDRESS_XPLODE
#define BT_DEVICE_ADDRESS_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
#define BT_DEVICE_ADDRESS_FMT_BUFFER_SIZE (18)
#define BD_ADDR_FMT "0x%02X%02X%02X%02X%02X%02X"
#define BT_ADDR_FMT_BUFFER_SIZE_BYTES (15)
#define BT_DEVICE_NAME_BUFFER_SIZE (20)
//! Macro decompose a BTDeviceAddress struct into its parts, so it can be used
//! with the BT_DEVICE_ADDRESS_FMT format macro
#define BT_DEVICE_ADDRESS_XPLODE(a) \
(a).octets[5], (a).octets[4], (a).octets[3], \
(a).octets[2], (a).octets[1], (a).octets[0]
#define BT_DEVICE_ADDRESS_XPLODE_PTR(a) \
(a)->octets[5], (a)->octets[4], (a)->octets[3], \
(a)->octets[2], (a)->octets[1], (a)->octets[0]
//! Data structure that represents a remote Bluetooth device.
//! The fields of the structure are opaque. Its contents should not be changed
//! or relied upon by the application.
typedef struct BTDevice {
union {
uint32_t opaque[2];
uint64_t opaque_64;
};
} BTDevice;
//! @internal The internal layout of the opaque BTDevice. This should not be
//! exported. It can also never be changed in size. It has to be exactly as
//! large as the BTDevice struct.
typedef struct __attribute__((__packed__)) BTDeviceInternal {
union {
struct __attribute__((__packed__)) {
BTDeviceAddress address;
bool is_classic:1;
bool is_random_address:1;
//! !!! WARNING: If you're adding more flags here, you need to update
//! the bt_device_bits field in PebbleBLEGATTClientEvent and PebbleBLEConnectionEvent !!!
uint16_t zero:14;
};
BTDevice opaque;
};
} BTDeviceInternal;
#define BT_DEVICE_INVALID ((const BTDevice) {})
#define BT_DEVICE_INTERNAL_INVALID ((const BTDeviceInternal) {})
_Static_assert(sizeof(BTDeviceInternal) == sizeof(BTDevice),
"BTDeviceInternal should be equal in size to BTDevice");
//! Opaque data structure representing an advertisment report and optional
//! scan response. Use the ble_ad... functions to query its contents.
struct BLEAdData;
//! @internal
//! The maximum size in bytes of an advertising report.
#define GAP_LE_AD_REPORT_DATA_MAX_LENGTH (31)
//! Flags used in an LE Advertising packet. Listed in
//! Supplement to Bluetooth Core Specification | CSSv6, Part A, 1.3.1
#define GAP_LE_AD_FLAGS_LIM_DISCOVERABLE_MASK (1 << 0)
#define GAP_LE_AD_FLAGS_GEN_DISCOVERABLE_MASK (1 << 1)
#define GAP_LE_AD_FLAGS_BR_EDR_NOT_SUPPORTED_MASK (1 << 2)
#define GAP_LE_AD_FLAGS_LE_BR_EDR_SIMULT_CONTROLLER_MASK (1 << 3)
#define GAP_LE_AD_FLAGS_LE_BR_EDR_SIMULT_HOST_MASK (1 << 4)
#define LL_CONN_INTV_MIN_SLOTS (6) // 1.25ms / slot
#define LL_CONN_INTV_MAX_SLOTS (3200) // 1.25ms / slot
#define LL_SUPERVISION_TIMEOUT_MIN_MS (100)
//! Advertisment and scan response data
//! @internal Exported as forward struct
typedef struct BLEAdData {
//! Lengths of the raw advertisment data
uint8_t ad_data_length;
//! Lengths of the raw scan response data
uint8_t scan_resp_data_length;
//! The raw advertisement data, concatenated with the raw scan response data.
uint8_t data[0];
} BLEAdData;
//! Macro that does the same as bt_uuid_expand_32bit / bt_uuid_expand_16bit, but at compile-time
#define BT_UUID_EXPAND(u) \
(0xff & ((uint32_t) u) >> 24), \
(0xff & ((uint32_t) u) >> 16), \
(0xff & ((uint32_t) u) >> 8), \
(0xff & ((uint32_t) u) >> 0), \
0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0x80, \
0x5F, 0x9B, 0x34, 0xFB

View file

@ -0,0 +1,54 @@
/*
* 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.
*/
#pragma once
#include "util/attributes.h"
#include <bluetooth/sm_types.h>
//! Packed, because this is serialized for the host-controller protocol.
typedef struct PACKED BleBonding {
SMPairingInfo pairing_info;
//! True if the remote device is capable of talking PPoGATT.
bool is_gateway:1;
//! True if the local device address should be pinned.
bool should_pin_address:1;
//! @note bt_persistent_storage_... uses only 5 bits to store this!
//! @see BleBondingFlag
uint8_t flags:5;
uint8_t rsvd:1;
//! Valid iff should_pin_address is true
BTDeviceAddress pinned_address;
} BleBonding;
//! Called by the FW after starting the Bluetooth stack to register existing bondings.
//! @note When the Bluetooth is torn down, there won't be any "remove" calls. If needed, the BT
//! driver lib should clean up itself in bt_driver_stop().
void bt_driver_handle_host_added_bonding(const BleBonding *bonding);
//! Called by the FW when a bonding is removed (i.e. user "Forgot" a bonding from Settings).
void bt_driver_handle_host_removed_bonding(const BleBonding *bonding);
//! Called by the BT driver after succesfully pairing a new device.
//! @param addr The address that is used to refer to the connection. This is used to associate
//! the bonding with the GAPLEConnection.
extern void bt_driver_cb_handle_create_bonding(const BleBonding *bonding,
const BTDeviceAddress *addr);

View file

@ -0,0 +1,41 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <bluetooth/bluetooth_types.h>
bool bt_driver_advert_advertising_enable(uint32_t min_interval_ms, uint32_t max_interval_ms,
bool enable_scan_resp);
void bt_driver_advert_advertising_disable(void);
bool bt_driver_advert_client_get_tx_power(int8_t *tx_power);
void bt_driver_advert_set_advertising_data(const BLEAdData *ad_data);
// FIXME: These are ugly. They are used because of the workarounds with the TI chips.
bool bt_driver_advert_is_connectable(void);
bool bt_driver_advert_client_has_cycled(void);
void bt_driver_advert_client_set_cycled(bool has_cycled);
bool bt_driver_advert_should_not_cycle(void);

View file

@ -0,0 +1,31 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
typedef struct CommSession CommSession;
//! Figures out the optimal thread to execute `bt_driver_run_send_next_job` on
//! and schedules a job to do so
bool bt_driver_comm_schedule_send_next_job(CommSession *session);
//! @return The PebbleTask that is used with bt_driver_comm_schedule_send_next_job() to perform
//! the sending of pending data.
bool bt_driver_comm_is_current_task_send_next_task(void);
extern void bt_driver_run_send_next_job(CommSession *session, bool is_callback);

View file

@ -0,0 +1,67 @@
/*
* 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.
*/
#pragma once
#include <bluetooth/bluetooth_types.h>
#include <bluetooth/hci_types.h>
#include <stdbool.h>
void bt_driver_test_start(void);
void bt_driver_test_enter_hci_passthrough(void);
void bt_driver_test_handle_hci_passthrough_character(char c, bool *should_context_switch);
bool bt_driver_test_enter_rf_test_mode(void);
void bt_driver_test_set_spoof_address(const BTDeviceAddress *addr);
void bt_driver_test_stop(void);
bool bt_driver_test_selftest(void);
bool bt_driver_test_mfi_chip_selftest(void);
void bt_driver_le_transmitter_test(
uint8_t tx_channel, uint8_t tx_packet_length, uint8_t packet_payload);
void bt_driver_le_test_end(void);
void bt_driver_le_receiver_test(uint8_t rx_channel);
typedef void (*BTDriverResponseCallback)(HciStatusCode status, const uint8_t *payload);
void bt_driver_register_response_callback(BTDriverResponseCallback callback);
void bt_driver_start_unmodulated_tx(uint8_t tx_channel);
void bt_driver_stop_unmodulated_tx(void);
typedef enum BtlePaConfig {
BtlePaConfig_Disable,
BtlePaConfig_Enable,
BtlePaConfig_Bypass,
BtlePaConfigCount
} BtlePaConfig;
void bt_driver_le_test_pa(BtlePaConfig option);
typedef enum BtleCoreDump {
BtleCoreDump_UserRequest,
BtleCoreDump_ForceHardFault,
BtleCoreDump_Watchdog,
BtleCoreDumpCount
} BtleCoreDump;
void bt_driver_core_dump(BtleCoreDump type);
void bt_driver_send_sleep_test_cmd(bool force_ble_sleep);

View file

@ -0,0 +1,30 @@
/*
* 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.
*/
#pragma once
#include <bluetooth/bluetooth_types.h>
#include <stdbool.h>
//! @param address Pass NULL to disconnect the "active" remote.
void bt_driver_classic_disconnect(const BTDeviceAddress* address);
bool bt_driver_classic_is_connected(void);
bool bt_driver_classic_copy_connected_address(BTDeviceAddress* address);
bool bt_driver_classic_copy_connected_device_name(char name[BT_DEVICE_NAME_BUFFER_SIZE]);

View file

@ -0,0 +1,29 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
typedef struct SlaveConnEventStats {
uint32_t num_conn_events; // BLE Connection Events that have elapsed
uint32_t num_conn_events_skipped; // The number of events the controller never tried to listen for
uint32_t num_sync_errors; // Events where slave did not see a packet from Master
uint32_t num_type_errors;
uint32_t num_len_errors;
uint32_t num_crc_errors; // Events that ended due to a packet CRC error
uint32_t num_mic_errors; // Events that ended due to a packet MIC error
} SlaveConnEventStats;

View file

@ -0,0 +1,21 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
void bt_driver_classic_update_connectability(void);

View file

@ -0,0 +1,39 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include "util/attributes.h"
// The reason the headers that define these lengths aren't included is because this header
// is included by the various number of bt_driver implementations. They don't know what "mfg"
// is, etc.
// NOTE: These sizes are asserted in a .c file to be in sync with the FW
#define MODEL_NUMBER_LEN (10) // MFG_HW_VERSION_SIZE + 1
#define MANUFACTURER_LEN (18) // sizeof("Pebble Technology")
#define SERIAL_NUMBER_LEN (13) // MFG_SERIAL_NUMBER_SIZE + 1
#define FW_REVISION_LEN (32) // FW_METADATA_VERSION_TAG_BYTES)
#define SW_REVISION_LEN (6) // Fmt: xx.xx\0
typedef struct PACKED DisInfo {
char model_number[MODEL_NUMBER_LEN];
char manufacturer[MANUFACTURER_LEN];
char serial_number[SERIAL_NUMBER_LEN];
char fw_revision[FW_REVISION_LEN];
char sw_revision[SW_REVISION_LEN];
} DisInfo;

View file

@ -0,0 +1,21 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
bool bt_driver_supports_bt_classic(void);

View file

@ -0,0 +1,29 @@
/*
* 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.
*/
#pragma once
#include "comm/ble/gap_le_advert.h"
//! @note The client should hold the `bt_lock` when calling these functions.
//! Also note that these functions are a workaround and should ideally not be used.
//! They are kept around to assist with a bug in the TI Bluetooth chips.
extern GAPLEAdvertisingJobRef gap_le_advert_get_current_job(void);
extern GAPLEAdvertisingJobRef gap_le_advert_get_jobs(void);
extern GAPLEAdvertisingJobTag gap_le_advert_get_job_tag(GAPLEAdvertisingJobRef job);

View file

@ -0,0 +1,124 @@
/*
* 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.
*/
#pragma once
#include <inttypes.h>
#include <bluetooth/bluetooth_types.h>
#include <bluetooth/sm_types.h>
#include "util/attributes.h"
#include "bluetooth/hci_types.h"
#include "util/attributes.h"
typedef enum BleAddressType {
BleAddressType_Public,
BleAddressType_Random
} BleAddressType;
#ifndef __clang__
_Static_assert(sizeof(BleAddressType) == 1, "BleAddressType is not 1 byte in size");
#endif
// All values in ms
// Used for ConnectionCompleteEvents
typedef struct PACKED BleConnectionParams {
uint16_t conn_interval_1_25ms;
uint16_t slave_latency_events;
uint16_t supervision_timeout_10ms;
} BleConnectionParams;
// Matches data from "LL_VERSION_IND" - v4.2 2.4.2.13
typedef struct PACKED BleRemoteVersionInfo {
uint8_t version_number;
uint16_t company_identifier;
uint16_t subversion_number;
} BleRemoteVersionInfo;
typedef struct PACKED BleRemoteVersionInfoReceivedEvent {
BTDeviceInternal peer_address;
BleRemoteVersionInfo remote_version_info;
} BleRemoteVersionInfoReceivedEvent;
// Structs providing data from various Ble Events. I attempted to comment below
// what section of the BT Core Spec more info about the event can be found
// "LE Connection Complete Event" - v4.2 7.7.65.1
typedef struct PACKED BleConnectionCompleteEvent {
BleConnectionParams conn_params;
BTDeviceInternal peer_address;
HciStatusCode status;
bool is_master;
bool is_resolved;
SMIdentityResolvingKey irk;
uint16_t handle;
} BleConnectionCompleteEvent;
// "Disconnection Complete Event" - v4.2 7.7.5
typedef struct PACKED BleDisconnectionCompleteEvent {
BTDeviceInternal peer_address;
HciStatusCode status;
HciDisconnectReason reason;
uint16_t handle;
} BleDisconnectionCompleteEvent;
// "LE Connection Update Complete Event" - v4.2 7.7.65.3
typedef struct PACKED BleConnectionUpdateCompleteEvent {
BleConnectionParams conn_params;
//! Using BTDeviceAddress instead of BTDeviceInternal, because Bluetopia's event doesn't contain
//! the address type.
BTDeviceAddress dev_address;
HciStatusCode status;
} BleConnectionUpdateCompleteEvent; // 7.7.65.3
// Note: This will likely change to work with Dialog
// "Encryption Change Event" - v4.2 7.7.8
typedef struct PACKED BleEncryptionChange {
//! Using BTDeviceAddress instead of BTDeviceInternal, because Bluetopia's event doesn't contain
//! the address type.
BTDeviceAddress dev_address;
HciStatusCode status;
bool encryption_enabled;
} BleEncryptionChange;
typedef struct PACKED BleAddressAndIRKChange {
//! Current (or old in case is_address_updated == true) device address info.
BTDeviceInternal device;
//! True if the "new_device" field is valid and underlying stack started using a different address
//! to refer to the connection.
bool is_address_updated;
BTDeviceInternal new_device;
//! True if the "irk" field is valid
bool is_resolved;
SMIdentityResolvingKey irk;
} BleAddressAndIRKChange;
//! Bluetooth LE GAP Connection Driver APIs
int bt_driver_gap_le_disconnect(const BTDeviceInternal *peer_address);
// Callbacks invoked by the bt_driver regarding different BLE Events. It is expected that consumers
// of this module provide an implementation for these callbacks
extern void bt_driver_handle_le_connection_complete_event(const BleConnectionCompleteEvent *event);
extern void bt_driver_handle_le_disconnection_complete_event(
const BleDisconnectionCompleteEvent *event);
extern void bt_driver_handle_le_encryption_change_event(const BleEncryptionChange *event);
extern void bt_driver_handle_le_conn_params_update_event(
const BleConnectionUpdateCompleteEvent *event);
extern void bt_driver_handle_le_connection_handle_update_address_and_irk(
const BleAddressAndIRKChange *e);
extern void bt_driver_handle_peer_version_info_event(const BleRemoteVersionInfoReceivedEvent *e);

View file

@ -0,0 +1,27 @@
/*
* 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.
*/
#pragma once
#include "comm/ble/gap_le_connection.h"
//! Bluetooth LE GAP Device name APIs
void bt_driver_gap_le_device_name_request_all(void);
void bt_driver_gap_le_device_name_request(const BTDeviceInternal *address);
//! The caller is expected to have implemented:
//! ctx will be kernel_free()'d
void bt_driver_store_device_name_kernelbg_cb(void *ctx);

View file

@ -0,0 +1,30 @@
/*
* 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.
*/
#pragma once
#include <inttypes.h>
#include "comm/ble/gap_le_scan.h"
//! Returns true on success, false on failure
bool bt_driver_start_le_scan(bool active_scan, bool use_white_list_filter, bool filter_dups,
uint16_t scan_interval_ms, uint16_t scan_window_ms);
//! Returns true on success, false on failure
bool bt_driver_stop_le_scan(void);
extern void bt_driver_cb_le_scan_handle_report(const GAPLERawAdReport *data, int length);

View file

@ -0,0 +1,164 @@
/*
* 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.
*/
#pragma once
#include <inttypes.h>
#include <bluetooth/bluetooth_types.h>
#include <bluetooth/gatt_discovery.h>
#include <bluetooth/hci_types.h>
#include "comm/ble/gap_le_connection.h"
#include "comm/ble/gatt_client_accessors.h"
#include "util/attributes.h"
// -- Gatt Device/Server Events
#define GATT_SERVICE_UUID ((uint16_t) 0x1801)
#define GATT_SERVICE_CHANGED_CHARACTERISTIC_UUID ((uint16_t) 0x2A05)
#define GATT_CCCD_UUID ((uint16_t) 0x2902)
//! Using BTDeviceAddress instead of BTDeviceInternal, with all these events, because Bluetopia's
//! events doesn't contain the address type.
typedef struct GattDeviceConnectionEvent {
BTDeviceAddress dev_address;
uint32_t connection_id;
uint16_t mtu;
} GattDeviceConnectionEvent;
typedef struct GattDeviceDisconnectionEvent {
BTDeviceAddress dev_address;
} GattDeviceDisconnectionEvent;
typedef struct GattDeviceBufferEmptyEvent {
BTDeviceAddress dev_address;
} GattDeviceBufferEmptyEvent;
typedef struct GattServerNotifIndicEvent {
BTDeviceAddress dev_address;
uint16_t attr_handle;
uint16_t attr_val_len;
uint8_t *attr_val;
void *context;
} GattServerNotifIndicEvent;
typedef struct GattDeviceMtuUpdateEvent {
BTDeviceAddress dev_address;
uint16_t mtu;
} GattDeviceMtuUpdateEvent;
// -- Service Changed Events
typedef struct GattServerChangedConfirmationEvent {
BTDeviceAddress dev_address;
uint32_t connection_id;
uint32_t transaction_id;
HciStatusCode status_code;
} GattServerChangedConfirmationEvent;
typedef struct GattServerReadSubscriptionEvent {
BTDeviceAddress dev_address;
uint32_t connection_id;
uint32_t transaction_id;
} GattServerReadSubscriptionEvent;
typedef struct GattServerSubscribeEvent {
BTDeviceAddress dev_address;
uint32_t connection_id;
bool is_subscribing;
} GattServerSubscribeEvent;
// -- Gatt Client Operations
typedef enum GattClientOpResponseType {
GattClientOpResponseRead,
GattClientOpResponseWrite,
} GattClientOpResponseType;
typedef struct GattClientOpResponseHdr {
GattClientOpResponseType type;
BLEGATTError error_code;
void *context;
} GattClientOpResponseHdr;
typedef struct GattClientOpReadReponse {
GattClientOpResponseHdr hdr;
uint16_t value_length;
uint8_t *value;
} GattClientOpReadReponse;
typedef struct GattClientOpWriteReponse {
GattClientOpResponseHdr hdr;
} GattClientOpWriteReponse;
// -- Gatt Data Structures
void bt_driver_gatt_acknowledge_indication(uint32_t connection_id, uint32_t transaction_id);
// TODO: This will probably need to be changed for the Dialog chip (doesn't have transaction ids)
void bt_driver_gatt_respond_read_subscription(uint32_t transaction_id, uint16_t response_code);
void bt_driver_gatt_send_changed_indication(uint32_t connection_id, const ATTHandleRange *data);
BTErrno bt_driver_gatt_write_without_response(GAPLEConnection *connection,
const uint8_t *value,
size_t value_length,
uint16_t att_handle);
BTErrno bt_driver_gatt_write(GAPLEConnection *connection,
const uint8_t *value,
size_t value_length,
uint16_t att_handle,
void *context);
BTErrno bt_driver_gatt_read(GAPLEConnection *connection,
uint16_t att_handle,
void *context);
//! The following are callbacks that the bt_driver implementation will call when handling events.
//! gatt callbacks
extern void bt_driver_cb_gatt_handle_connect(const GattDeviceConnectionEvent *event);
extern void bt_driver_cb_gatt_handle_disconnect(const GattDeviceDisconnectionEvent *event);
extern void bt_driver_cb_gatt_handle_buffer_empty(const GattDeviceBufferEmptyEvent *event);
extern void bt_driver_cb_gatt_handle_mtu_update(const GattDeviceMtuUpdateEvent *event);
extern void bt_driver_cb_gatt_handle_notification(const GattServerNotifIndicEvent *event);
//! @NOTE: The indication is unconditionally confirmed within the bt_driver as soon as one is
//! received.
extern void bt_driver_cb_gatt_handle_indication(const GattServerNotifIndicEvent *event);
//! gatt_service_changed callbacks
extern void bt_driver_cb_gatt_service_changed_server_confirmation(
const GattServerChangedConfirmationEvent *event);
extern void bt_driver_cb_gatt_service_changed_server_subscribe(
const GattServerSubscribeEvent *event);
extern void bt_driver_cb_gatt_service_changed_server_read_subscription(
const GattServerReadSubscriptionEvent *event);
extern void bt_driver_cb_gatt_client_discovery_handle_service_changed(GAPLEConnection *connection,
uint16_t handle);
extern void bt_driver_cb_gatt_client_operations_handle_response(GattClientOpResponseHdr *event);

View file

@ -0,0 +1,43 @@
/*
* 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.
*/
#pragma once
#include <bluetooth/bluetooth_types.h>
#include <bluetooth/gatt_service_types.h>
#include <util/attributes.h>
#include <stdint.h>
typedef struct GAPLEConnection GAPLEConnection;
typedef struct GATTService GATTService;
typedef struct GATTServiceNode GATTServiceNode;
BTErrno bt_driver_gatt_start_discovery_range(
const GAPLEConnection *connection, const ATTHandleRange *data);
BTErrno bt_driver_gatt_stop_discovery(GAPLEConnection *connection);
//! It's possible we are disconnected or the stack gets torn down while in the
//! middle of a discovery. This routine gets invoked if the connection gets
//! torn down or goes away so that the implementation can clean up any tracking
//! it has waiting for a discovery to complete
void bt_driver_gatt_handle_discovery_abandoned(void);
//! gatt_service_discovery callbacks
//! cb returns true iff the driver completed, false if a discovery retry was initiated
extern bool bt_driver_cb_gatt_client_discovery_complete(GAPLEConnection *connection, BTErrno errno);
extern void bt_driver_cb_gatt_client_discovery_handle_indication(
GAPLEConnection *connection, GATTService *service_discovered, BTErrno error);

View file

@ -0,0 +1,114 @@
/*
* 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.
*/
#pragma once
#include <util/uuid.h>
#include <stddef.h>
#include <stdint.h>
#include <util/attributes.h>
//! Below are the data structures to store information about a *remote* GATT
//! service and its characteristics and descriptors.
//!
//! It's designed for compactness and ease of serialization, at the cost of
//! CPU cycles to iterate over and access the data.
//! The GATTCharacteristic are tacked at the end of the struct. At the end of
//! each GATTCharacteristic, its descriptors are tacked on. Lastly, after all
//! the characteristics, an array of Included Service handles is tacked on.
//! Struct packing is not enabled at the moment, but could be if needed.
//! Handles for the Characteristics and Descriptors are stored as offsets from
//! the parent service handle to save one byte per characteristic.
//!
//! Ideas for more memory footprint optimizations:
//! - Create a shared list of UUIDs that can be referenced,
//! to avoid wasting 16 bytes of RAM per service, characteristic and descriptor?
typedef struct PACKED ATTHandleRange {
uint16_t start;
uint16_t end;
} ATTHandleRange;
//! Common header for GATTDescriptor, GATTCharacteristic and GATTService
typedef struct {
Uuid uuid;
} GATTObjectHeader;
typedef struct {
//! The UUID of the descriptor
Uuid uuid;
//! The offset of the handle with respect to service.att_handle
uint8_t att_handle_offset;
} GATTDescriptor;
_Static_assert(offsetof(GATTDescriptor, uuid) == offsetof(GATTObjectHeader, uuid), "");
typedef struct {
//! The UUID of the characteristic
Uuid uuid;
//! The offset of the handle with respect to service.att_handle
uint8_t att_handle_offset;
uint8_t properties;
uint8_t num_descriptors;
GATTDescriptor descriptors[];
} GATTCharacteristic;
_Static_assert(offsetof(GATTCharacteristic, uuid) == offsetof(GATTObjectHeader, uuid), "");
typedef struct GATTService {
//! The UUID of the service
Uuid uuid;
uint8_t discovery_generation;
//! The size in bytes of the GATTService blob, including all its
//! characteristics, descriptors and included service handles.
uint16_t size_bytes;
//! The ATT handle of the service
uint16_t att_handle;
//! Number of characteristics in the array
//! @note because GATTCharacteristic is variable length, it is not possible
//! to use array subscripting.
uint8_t num_characteristics;
//! The total number of descriptors in the service
uint8_t num_descriptors;
//! Size of the att_handles_included_services array
uint8_t num_att_handles_included_services;
//! Array with the characteristics of the service
GATTCharacteristic characteristics[];
//! Array with the ATT handles of Included Services
//! This array follows after the characteristics, when
//! num_att_handles_included_services > 0
//! uint16_t att_handles_included_services[];
} GATTService;
_Static_assert(offsetof(GATTService, uuid) == offsetof(GATTObjectHeader, uuid), "");
#define COMPUTE_GATTSERVICE_SIZE_BYTES(num_chars, num_descs, num_includes) \
(sizeof(GATTService) + sizeof(GATTCharacteristic) * (num_chars) + \
sizeof(GATTDescriptor) * (num_descs) + sizeof(uint16_t) * (num_includes))

View file

@ -0,0 +1,33 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
typedef enum {
HciStatusCode_Success = 0x00,
HciStatusCode_UnknownConnectionIdentifier = 0x02,
HciStatusCode_VS_Base = 0x50,
HciStatusCode_Max = UINT16_MAX
} HciStatusCode;
#ifndef __clang__
_Static_assert(sizeof(HciStatusCode) == 2, "packed structs expect the status code to be 2 bytes!");
#endif
// disconnect reasons are just status codes
typedef HciStatusCode HciDisconnectReason;

View file

@ -0,0 +1,43 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <bluetooth/bluetooth_types.h>
typedef struct {
uint16_t bpm;
bool is_on_wrist;
} BleHrmServiceMeasurement;
//! @return True if the BT driver lib supports exposing the GATT HRM service.
bool bt_driver_is_hrm_service_supported(void);
//! Adds or removes the HRM service from the GATT database, notifying any connected devices
//! by sending a "Service Changed" indication for the mutated handle range.
void bt_driver_hrm_service_enable(bool enable);
//! Sends the Heart Rate Measurement to all subscribed & connected devices.
void bt_driver_hrm_service_handle_measurement(const BleHrmServiceMeasurement *measurement,
const BTDeviceInternal *permitted_devices,
size_t num_permitted_devices);
//! Called when a connected device (un)subscribes to the GATT HRM service's "Heart Rate Measurement"
//! characteristic.
extern void bt_driver_cb_hrm_service_update_subscription(const BTDeviceInternal *device,
bool is_subscribed);

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
#pragma once
#include <bluetooth/bluetooth_types.h>
void bt_driver_id_set_local_device_name(const char device_name[BT_DEVICE_NAME_BUFFER_SIZE]);
void bt_driver_id_copy_local_identity_address(BTDeviceAddress *addr_out);
//! Configures the local address that the BT driver should use "on-air".
//! @note This address and the identity address are different things!
//! @note bt_lock() is held when this call is made.
//! @param allow_cycling True if the controller is allowed to cycle the address (implies address
//! pinning is *not* used!)
//! @param pinned_address The address to use, or NULL for "don't care".
void bt_driver_set_local_address(bool allow_cycling,
const BTDeviceAddress *pinned_address);
//! Copies a human-readable string of freeform info that uniquely identifies the Bluetooth chip.
//! Used by MFG for part tracking purposes.
//! @param[out] dest Buffer into which to copy the info.
//! @param[in] dest_size Size of dest in bytes.
void bt_driver_id_copy_chip_info_string(char *dest, size_t dest_size);
//! Generates a new private resolvable address using the current IRK (as passed with the
//! bt_driver_start() call when setting up the stack).
bool bt_driver_id_generate_private_resolvable_address(BTDeviceAddress *address_out);

View file

@ -0,0 +1,46 @@
/*
* 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.
*/
#pragma once
#include "util/attributes.h"
#include <bluetooth/sm_types.h>
#include <bluetooth/dis.h>
#include <stdbool.h>
typedef struct PACKED BTDriverConfig {
SM128BitKey root_keys[SMRootKeyTypeNum];
DisInfo dis_info;
BTDeviceAddress identity_addr;
bool is_hrm_supported_and_enabled;
} BTDriverConfig;
//! Function that performs one-time initialization of the BT Driver.
//! The main FW is expected to call this once at boot.
void bt_driver_init(void);
//! Starts the Bluetooth stack.
//! @return True if the stack started successfully.
bool bt_driver_start(BTDriverConfig *config);
//! Stops the Bluetooth stack.
//! @return True if the stack stopped successfully.
void bt_driver_stop(void);
//! Powers down the BT controller if has yet to be used
void bt_driver_power_down_controller_on_boot(void);

View file

@ -0,0 +1,29 @@
/*
* 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.
*/
#pragma once
#if BT_CONTROLLER_DA14681
// Larger MTU sizes appear to have a more considerable impact on throughput than one would expect
// (theoretical gain from 158 bytes - 512 bytes should only be ~3% but we are seeing up to ~30%
// bumps). More investigation needs to be done to understand exactly why. For now, let's bump the
// size so Android phones which support large MTUs can leverage it
#define ATT_MAX_SUPPORTED_MTU (339)
#else
// It's 158 bytes now because that's the maximum payload iOS 8 allows.
// On legacy products, only iOS uses LE so stick with this max buffer size
#define ATT_MAX_SUPPORTED_MTU (158)
#endif

View file

@ -0,0 +1,23 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
void bt_driver_le_pairability_set_enabled(bool enabled);
void bt_driver_classic_pairability_set_enabled(bool enabled);

View file

@ -0,0 +1,49 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
//! Forward declaration to internal, implementation specific state.
typedef struct PairingUserConfirmationCtx PairingUserConfirmationCtx;
//! Confirms a pairing request.
//! @param[in] ctx The pairing request context, as previously passed to
//! bt_driver_cb_pairing_confirm_handle_request.
//! @param[in] is_confirmed Pass true if the user confirmed the pairing.
void bt_driver_pairing_confirm(const PairingUserConfirmationCtx *ctx,
bool is_confirmed);
//! @param[in] ctx Pointer to opaque BT-driver-implementation specific context. The function can
//! use the pointer value this to distinguish one pairing process from another, but the pointer
//! should NOT be dereferenced by the FW side. Aside the fact that the struct is internal to
//! the FW and therefore shouldn't be able to look inside it, the memory can be free'd at all times
//! by the BT driver implementation. For example when the pairing process times out, the BT driver
//! might free the memory that ctx is pointing to.
//! @param[in] device_name Optional device name of the device that is attempting to pair. Pass NULL
//! if the device name is not available.
//! @param[in] confirmation_token Optional confirmation token. Pass NULL if not available.
//! @note This function should immediately copy the device name and confirmation token, so the
//! buffers do not have to continue existing after this function returns.
extern void bt_driver_cb_pairing_confirm_handle_request(const PairingUserConfirmationCtx *ctx,
const char *device_name,
const char *confirmation_token);
//! @param[in] ctx See bt_driver_cb_pairing_confirm_handle_request
//! @param[in] success True if the pairing process finished successfully.
extern void bt_driver_cb_pairing_confirm_handle_completed(const PairingUserConfirmationCtx *ctx,
bool success);

View file

@ -0,0 +1,71 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
#include "util/uuid.h"
//! @file This file contains Pebble-specific Bluetooth identifiers (numbers, UUIDs, etc.)
//! Also see https://pebbletechnology.atlassian.net/wiki/display/DEV/Pebble+GATT+Services
//! Bluetopia does not contain our Vendor ID, yet.
//! See Bluetooth Company Identifiers:
//! http://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm
//! Be careful not to use with with BT Classic! See sdp.c why.
#define PEBBLE_BT_VENDOR_ID (0x0154)
//! Our Bluetooth-SIG-Registered 16-bit UUID:
//! Pebble Technology Corporation
//! Pebble Smartwatch Service
#define PEBBLE_BT_PAIRING_SERVICE_UUID_16BIT (0xFED9)
//! The Service UUID of the "Pebble Protocol over GATT" (PPoGATT) service.
//! This UUID needs to be expanded using the Pebble Base UUID (@see pebble_bt_uuid_expand)
#define PEBBLE_BT_PPOGATT_SERVICE_UUID_32BIT (0x10000000)
#define PEBBLE_BT_PPOGATT_DATA_CHARACTERISTIC_UUID_32BIT (0x10000001)
#define PEBBLE_BT_PPOGATT_META_CHARACTERISTIC_UUID_32BIT (0x10000002)
//! The Service UUID of the "Pebble Protocol over GATT" (PPoGATT) service that the watch
//! publishes to operate as a Server instead of it's normal client role. This allows certain
//! sad Android phones to communicate with the watch
#define PEBBLE_BT_PPOGATT_WATCH_SERVER_SERVICE_UUID_32BIT (0x30000003)
#define PEBBLE_BT_PPOGATT_WATCH_SERVER_DATA_CHARACTERISTIC_UUID_32BIT (0x30000004)
#define PEBBLE_BT_PPOGATT_WATCH_SERVER_META_CHARACTERISTIC_UUID_32BIT (0x30000005)
#define PEBBLE_BT_PPOGATT_WATCH_SERVER_DATA_WR_CHARACTERISTIC_UUID_32BIT (0x30000006)
//! The Service UUID of the "Pebble App Launch" service.
//! This UUID needs to be expanded using the Pebble Base UUID (@see pebble_bt_uuid_expand)
#define PEBBLE_BT_APP_LAUNCH_SERVICE_UUID_32BIT (0x20000000)
#define PEBBLE_BT_APP_LAUNCH_CHARACTERISTIC_UUID_32BIT (0x20000001)
//! Assigns a 32-bit (or 16-bit) UUID that is based on the Pebble Base UUID,
//! XXXXXXXX-328E-0FBB-C642-1AA6699BDADA.
//! @param uuid The UUID storage to assign the constructed UUID to.
//! @param value The 32-bit (or 16-bit) UUID value to use.
//! @see bt_uuid_expand_32bit and bt_uuid_expand_16bit for functions that expand
//! using the BT SIG's Base UUID.
void pebble_bt_uuid_expand(Uuid *uuid, uint32_t value);
//! Macro that does the same as pebble_bt_uuid_expand, but then at compile-time
#define PEBBLE_BT_UUID_EXPAND(u) \
(0xff & ((uint32_t) u) >> 24), \
(0xff & ((uint32_t) u) >> 16), \
(0xff & ((uint32_t) u) >> 8), \
(0xff & ((uint32_t) u) >> 0), \
0x32, 0x8E, 0x0F, 0xBB, \
0xC6, 0x42, 0x1A, 0xA6, \
0x69, 0x9B, 0xDA, 0xDA

View file

@ -0,0 +1,248 @@
/*
* 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.
*/
#pragma once
#include "util/attributes.h"
#include <bluetooth/pebble_bt.h>
#include <bluetooth/responsiveness.h>
#define PEBBLE_BT_PAIRING_SERVICE_CONNECTION_STATUS_UUID PEBBLE_BT_UUID_EXPAND(1)
#define PEBBLE_BT_PAIRING_SERVICE_TRIGGER_PAIRING_UUID PEBBLE_BT_UUID_EXPAND(2)
#define PEBBLE_BT_PAIRING_SERVICE_GATT_MTU_UUID PEBBLE_BT_UUID_EXPAND(3)
// Note: UUID 4 was used by the 3.14-rc Android App for V0 of the Connection Param characteristic
// but never shipped externally
#define PEBBLE_BT_PAIRING_SERVICE_CONNECTION_PARAMETERS_UUID PEBBLE_BT_UUID_EXPAND(5)
typedef enum {
PebblePairingServiceGATTError_UnknownCommandID =
BLEGATTErrorApplicationSpecificErrorStart,
PebblePairingServiceGATTError_ConnParamsInvalidRemoteDesiredState,
PebblePairingServiceGATTError_ConnParamsMinSlotsTooSmall,
PebblePairingServiceGATTError_ConnParamsMinSlotsTooLarge,
PebblePairingServiceGATTError_ConnParamsMaxSlotsTooLarge,
PebblePairingServiceGATTError_ConnParamsSupervisionTimeoutTooSmall,
PebblePairingServiceGATTError_DeviceDoesNotSupportPLE,
} PebblePairingServiceGATTError;
//! The connectivity status, with respect to the device reading it.
typedef struct PACKED {
union {
struct {
//! true if the device that is reading the status is connected (always true)
bool ble_is_connected:1;
//! true if the device that is reading the status is bonded, false if not
bool ble_is_bonded:1;
//! true if the current LE link is encrypted, false if not
bool ble_is_encrypted:1;
//! true if the watch has a bonding to a gateway (LE-based).
bool has_bonded_gateway:1;
//! true if the watch supports writing the "Don't send slave security request" bit.
//! See https://pebbletechnology.atlassian.net/wiki/display/DEV/Pebble+GATT+Services
bool supports_pinning_without_security_request:1;
//! true if the reversed ppogatt was enabled at the time of bonding
bool is_reversed_ppogatt_enabled:1;
//! Reserved, leave zero for future use.
uint32_t rsvd:18;
//! The error of the last pairing process or all zeroes, if no pairing process has completed
//! or when there were no errors. Also see BT Spec 4.2, Vol 3, Part H, 3.5.5 Pairing Failed.
uint8_t last_pairing_result;
};
uint8_t bytes[4];
};
} PebblePairingServiceConnectivityStatus;
_Static_assert(sizeof(PebblePairingServiceConnectivityStatus) == 4, "");
typedef struct PACKED {
bool should_pin_address:1;
//! @note Not available in Bluetopia/cc2564x implementation
//! This flag and should_force_slave_security_request are mutually exclusive!
bool no_slave_security_request:1;
//! @note Not available in Bluetopia/cc2564x implementation
//! This flag and no_slave_security_request are mutually exclusive!
bool should_force_slave_security_request:1;
//! @note Not available in Bluetopia/cc2564x implementation
//! Flag to indicate that when re-pairing this device, the re-pairing should be accepted
//! automatically for this remote device (matching IRK or matching identity address).
//! @note This is a work-around for an Android 4.4.x bug. This opens up a security hole :( where
//! a phone could pretend to be the "trusted" phone and pair w/o the user even knowing about it.
//! @see https://pebbletechnology.atlassian.net/browse/PBL-39369
bool should_auto_accept_re_pairing:1;
//! @note Not available in Bluetopia/cc2564x implementation
//! Flag to indicate that the PPoGATT server/client roles should be reversed to support the
//! connected phone. Some older Android phones' GATT service API is completely busted. For those
//! poor phones, this bit is set before pairing. The Pebble includes a "reversed" PPoGATT service
//! that the phone app can connect to as GATT client, but this service only works if this bit
//! gets set *before pairing*. This is a security measure: 1. to prevent non-paired devices from
//! talking to the "reversed" PPoGATT service. 2. to prevent non-Pebble apps on paired phone that
//! does support normal PPoGATT from connecting to the "reversed" PPoGATT service.
//! @see ppogatt_emulated_server_wa.c
//! @see https://pebbletechnology.atlassian.net/browse/PBL-39634
bool is_reversed_ppogatt_enabled:1;
} PairingTriggerRequestData;
typedef struct PACKED {
//! interval_min_ms / 1.25 msec valid range: 7.5 msec to 4 seconds
uint16_t interval_min_1_25ms;
//! (interval_max_ms - interval_min_ms) / 1.25 msec
//! @note To fit the parent struct in the minimum GATT MTU, this field is a delta and only one
//! byte instead of the uint16_t that the BT spec uses.
uint8_t interval_max_delta_1_25ms;
//! Slave latency (in number of connection events)
//! @note To fit the parent struct in the minimum GATT MTU, this field is only one byte instead
//! of the uint16_t that the BT spec uses.
uint8_t slave_latency_events;
//! Supervision Timeout / 30 msec valid range: 100 msec to 32 seconds. To fit this into one
//! byte and to fit the parent struct in the minimum GATT MTU, the increments is not the standard
//! 10msec!
uint8_t supervision_timeout_30ms;
} PebblePairingServiceConnParamSet;
//! The connection parameters settings, with respect to connection to the device reading them.
typedef struct PACKED PebblePairingServiceConnParamsReadNotif {
//! Capability bits. Reserved for future use.
uint8_t packet_length_extension_supported:1;
uint8_t rsvd:7;
//! Current interval / 1.25 msec valid range: 7.5 msec to 4 seconds
uint16_t current_interval_1_25ms;
//! Current Slave latency (in number of connection events) actual max is 0x01F3, but in
//! practice values are much lower.
uint16_t current_slave_latency_events;
//! Current Supervision Timeout / 10 msec valid range: 100 msec to 32 seconds.
uint16_t current_supervision_timeout_10ms;
} PebblePairingServiceConnParamsReadNotif;
typedef enum PebblePairingServiceConnParamsWriteCmd {
//! Allows phone to change connection parameter set and take over control of parameter management
PebblePairingServiceConnParamsWriteCmd_SetRemoteParamMgmtSettings = 0x00,
//! Issues a connection parameter change request if the watch is not in the desired state
PebblePairingServiceConnParamsWriteCmd_SetRemoteDesiredState = 0x01,
//! Controls settings for BLE 4.2 Packet Length Extension feature
PebblePairingServiceConnParamsWriteCmd_EnablePacketLengthExtension = 0x02,
//! If written to disables Dialog BLE sleep mode (safeguard against PBL-39777 in case it affects
//! more watches in the future)
PebblePairingServiceConnParamsWriteCmd_InhibitBLESleep = 0x03,
PebblePairingServiceConnParamsWriteCmdCount,
} PebblePairingServiceConnParamsWriteCmd;
typedef struct PACKED PebblePairingServiceRemoteParamMgmtSettings {
//! If false/zero, Pebble should manage the connection parameters. If true/one, Pebble should
//! NOT manage the connection parameters. In this mode, Pebble will never request a
//! connection parameter change.
bool is_remote_device_managing_connection_parameters:1;
uint8_t rsvd:7;
//! Optional. Current parameters sets used by Pebble's Connection Parameter manager.
PebblePairingServiceConnParamSet connection_parameter_sets[];
} PebblePairingServiceRemoteParamMgmtSettings;
typedef struct PACKED PebblePairingServiceRemoteDesiredState {
//! The desired ResponseTime as desired by the remote device. The remote end can set this
//! value to a faster mode when it's about to transfer/receive a lot of data. For example,
//! when a lot of BlobDB operations are queued up, the watch doesn't know how much data is
//! queued up on the remote end. In this case, the remote could write "ResponseTimeMin" so
//! increase the speed temporarily. It's the remote end's responsibility to reset this to
//! ResponseTimeMax when the bulk transfer is done. As a safety measure, the watch is will
//! reset it back to ResponseTimeMax after 5 minutes. In case the phone app still wants to
//! keep a particular desired ResponseTime, the phone app is responsible for making sure to
//! write the value again before the 5 minute timer expires.
uint8_t state:2;
uint8_t rsvd:6;
} PebblePairingServiceRemoteDesiredState;
typedef struct PACKED PebblePairingServicePacketLengthExtension {
uint8_t trigger_ll_length_req:1;
uint8_t rsvd:7;
} PebblePairingServicePacketLengthExtension;
typedef struct PACKED PebblePairingServiceInhibitBLESleep {
uint8_t rsvd; // for future use
} PebblePairingServiceInhibitBLESleep;
//! The connection parameters settings, with respect to connection to the device writing them.
typedef struct PACKED PebblePairingServiceConnParamsWrite {
PebblePairingServiceConnParamsWriteCmd cmd:8;
union PACKED {
//! Valid iff cmd == PebblePairingServiceConnParamsWriteCmd_SetRemoteParamMgmtSettings
PebblePairingServiceRemoteParamMgmtSettings remote_param_mgmt_settings;
//! Valid iff cmd == PebblePairingServiceConnParamsWriteCmd_SetRemoteDesiredState
PebblePairingServiceRemoteDesiredState remote_desired_state;
//! Valid iff cmd == PebblePairingServiceConnParamsWriteCmd_EnablePacketLengthExtension
PebblePairingServicePacketLengthExtension ple_req;
//! Valid iff cmd == PebblePairingServiceConnParamsWriteCmd_InhibitBLESleep
PebblePairingServiceInhibitBLESleep ble_sleep;
};
} PebblePairingServiceConnParamsWrite;
#define PEBBLE_PAIRING_SERVICE_REMOTE_PARAM_MGTM_SETTINGS_SIZE_WITH_PARAM_SETS \
(sizeof(PebblePairingServiceRemoteParamMgmtSettings) + \
(sizeof(PebblePairingServiceConnParamSet) * NumResponseTimeState))
#define PEBBLE_PAIRING_SERVICE_CONN_PARAMS_WRITE_SIZE_WITH_PARAM_SETS \
(offsetof(PebblePairingServiceConnParamsWrite, remote_param_mgmt_settings) + \
PEBBLE_PAIRING_SERVICE_REMOTE_PARAM_MGTM_SETTINGS_SIZE_WITH_PARAM_SETS)
_Static_assert(NumResponseTimeState == 3, "");
_Static_assert(sizeof(PebblePairingServiceConnParamsReadNotif) <= 20, "Larger than minimum MTU!");
_Static_assert(PEBBLE_PAIRING_SERVICE_CONN_PARAMS_WRITE_SIZE_WITH_PARAM_SETS <= 20,
"Larger than minimum MTU!");
_Static_assert(sizeof(PebblePairingServiceConnParamsWrite) <= 20, "Larger than minimum MTU!");
_Static_assert(sizeof(PebblePairingServiceConnectivityStatus) <= 20, "Larger than minimum MTU!");
typedef struct GAPLEConnection GAPLEConnection;
//! Signals to the Pebble GATT service that status change has occured (pairing, encryption, ...),
//! allowing it to notify any BLE devices that are subscribed to connectivity status updates of the
//! change.
//! @param connection The connection for which the status was changed.
void bt_driver_pebble_pairing_service_handle_status_change(const GAPLEConnection *connection);
//! Signals to the Pebble GATT service the GATT MTU has changed, allowing it to notify any BLE
//! devices that are subscribed to GATT MTU characteristic.
//! @param connection The connection for which the GATT MTU has changed.
//! @note the caller is responsible for taking bt_lock!
void bt_driver_pebble_pairing_service_handle_gatt_mtu_change(const GAPLEConnection *connection);
//! Indicate to the FW that Connectivity Status characteristic has been unsubscribed from.
//! This is used to detect that the Pebble iOS app has been terminated.
extern void bt_driver_cb_pebble_pairing_service_handle_ios_app_termination_detected(void);
//! Indicate to the FW that the Connection Parameters characteristic has been written to with a new
//! values.
//! @param conn_params The value as written to the Connection Parameters characteristic. The BT
//! driver lib is expected to validate any written values and only call this function with valid
//! values.
//! @param conn_params_length The length of conn_params in bytes.
extern void bt_driver_cb_pebble_pairing_service_handle_connection_parameter_write(
const BTDeviceInternal *device,
const PebblePairingServiceConnParamsWrite *conn_params,
size_t conn_params_length);

View file

@ -0,0 +1,28 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
//! Called by the QEMU serial driver whenever Pebble Protocol data is received.
void qemu_transport_handle_received_data(const uint8_t *data, uint32_t length);
//! Called by qemu version of comm_init() to tell ISPP that it is connected
void qemu_transport_set_connected(bool is_connected);
bool qemu_transport_is_connected(void);

View file

@ -0,0 +1,50 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
//! Increments the reconnect-pause counter. When the counter is above
//! 0, reconnection attempts will not occur.
void bt_driver_reconnect_pause(void);
//! Decrements the reconnect-pause counter. When the counter drops to
//! 0, reconnection attempts will be free to proceed.
void bt_driver_reconnect_resume(void);
//! Attempt to reconnect to the last connected remote device and restore
//! connections to the Bluetooth Classic profile (iSPP).
//! This is an asynchonous operation. A call to this function returns quickly.
//! If the last connected remote device and services are already connected, or
//! if the device is not an iOS device, this function does not do much.
//! @param ignore_paused If true, this call will attempt to reconnect,
//! even if the reconnection manager is paused. If false, the call will not
//! attempt to reconnect if the manager is paused.
void bt_driver_reconnect_try_now(bool ignore_paused);
//! Resets the reconnection manager's interval to the minimum interval, so
//! the rate of reconnection attempts is temporarily increased. This
//! should be called right after disconnecting or at any time that the remote
//! device might be suspected to be coming back in range.
void bt_driver_reconnect_reset_interval(void);
//! Notifies the BT Driver of the platform bitfield we received from the
//! 'session remote version endpoint'. (Some drivers cache this information to
//! determine BT connection behavior (such as the reconnection algorithm for
//! bluetooth classic)
void bt_driver_reconnect_notify_platform_bitfield(uint32_t platform_bitfield);

View file

@ -0,0 +1,83 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
#include <inttypes.h>
#include <bluetooth/bluetooth_types.h>
#include "bluetooth/gap_le_connect.h"
#include "util/attributes.h"
typedef enum {
BtConsumerNone = 0,
// Every sub-module has its own consumer name. We try to enter & exit
// from low latency states within the same module
BtConsumerApp,
BtConsumerLePairing,
BtConsumerLeServiceDiscovery,
BtConsumerMusicServiceIndefinite,
BtConsumerMusicServiceMomentary,
BtConsumerPpAppFetch,
BtConsumerPpAppMessage,
BtConsumerPpAudioEndpoint,
BtConsumerPpGetBytes,
BtConsumerPpLogDump,
BtConsumerPpPutBytes,
BtConsumerPpScreenshot,
BtConsumerPpVoiceEndpoint,
BtConsumerPrompt,
BtConsumerTimelineActionMenu,
BtConsumerPRF,
BtConsumerPebblePairingServiceRemoteDevice,
BtConsumerUnitTests, // For unit testing
NumBtConsumer,
} BtConsumer;
typedef enum {
ResponseTimeInvalid = -1,
ResponseTimeMax = 0, // lowest throughput, most friendly power profile
ResponseTimeMiddle,
ResponseTimeMin, // highest throughput, least friendly power profile
NumResponseTimeState,
} ResponseTimeState;
//! Callback to call when the requested response time has been negotiated and granted.
typedef void (*ResponsivenessGrantedHandler)(void);
// Longest duration we want to be in Min latency for different modules
#define MIN_LATENCY_MODE_TIMEOUT_AUDIO_SECS (10)
#define MIN_LATENCY_MODE_TIMEOUT_APP_FETCH_SECS (5)
#define MIN_LATENCY_MODE_TIMEOUT_APP_MESSAGE_SECS (10)
#define MIN_LATENCY_MODE_TIMEOUT_CD_SECS (10)
#define MIN_LATENCY_MODE_TIMEOUT_PROTOCOL_RECV_SECS (60)
#define MIN_LATENCY_MODE_TIMEOUT_PUT_BYTES_SECS (60)
#define MIN_LATENCY_MODE_TIMEOUT_SCREENSHOT_SECS (5)
#define MIN_LATENCY_MODE_TIMEOUT_TIMELINE_ACTION_MENU_SECS (10)
#define MIN_LATENCY_MODE_TIMEOUT_VOICE_SECS (10)
//! Connection Parameters Update Request Packet
typedef struct PACKED { // PACKED since this struct is serialized
uint16_t interval_min_1_25ms;
uint16_t interval_max_1_25ms;
uint16_t slave_latency_events;
uint16_t supervision_timeout_10ms;
} BleConnectionParamsUpdateReq;
bool bt_driver_le_connection_parameter_update(
const BTDeviceInternal *addr, const BleConnectionParamsUpdateReq *req);

View file

@ -0,0 +1,86 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <bluetooth/bluetooth_types.h>
#include <util/attributes.h>
typedef enum {
SMRootKeyTypeEncryption,
SMRootKeyTypeIdentity,
SMRootKeyTypeNum,
} SMRootKeyType;
typedef struct PACKED SM128BitKey {
uint8_t data[16];
} SM128BitKey;
typedef SM128BitKey SMLongTermKey;
typedef SM128BitKey SMIdentityResolvingKey;
typedef SM128BitKey SMConnectionSignatureResolvingKey;
typedef struct PACKED SMLocalEncryptionInfo {
uint16_t ediv;
//! @note Only used by cc2564x/Bluetopia driver!
uint16_t div;
//! @note Only used by Dialog driver!
SMLongTermKey ltk;
//! @note Only used by Dialog driver!
uint64_t rand;
} SMLocalEncryptionInfo;
typedef struct PACKED SMRemoteEncryptionInfo {
SMLongTermKey ltk;
uint64_t rand;
uint16_t ediv;
} SMRemoteEncryptionInfo;
//! @note Some fields might not get populated/used, this depends on the BT Driver implementation.
//! @note Packed, because this is used in HC protocol messages.
typedef struct PACKED SMPairingInfo {
//! The encryption info that will be used when the local device is the slave.
SMLocalEncryptionInfo local_encryption_info;
//! The encryption info that will be used when the local device is the master.
SMRemoteEncryptionInfo remote_encryption_info;
SMIdentityResolvingKey irk;
BTDeviceInternal identity;
SMConnectionSignatureResolvingKey csrk;
//! True if div and ediv are valid
bool is_local_encryption_info_valid;
//! True if remote_encryption_info is valid
bool is_remote_encryption_info_valid;
//! True if irk and identity are valid
bool is_remote_identity_info_valid;
//! True if csrk is valid
bool is_remote_signing_info_valid;
//! @note NOT valid for cc2564x BT lib, only for Dialog BT lib!
bool is_mitm_protection_enabled;
} SMPairingInfo;

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
#pragma once
//! Should be called when a BT Classic disconnection occurs
void reconnect_android_update_disconnect_time(void);

View file

@ -0,0 +1,224 @@
/*
* 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.
*/
#pragma once
#include <logging/log_hashing.h>
/*
* This file defines the structures required for Binary Logging. Please see
* https://docs.google.com/document/d/1AyRGwr8CiilAViha56EiuRSZFiW0fWMcsTfzkNxByZ8
* for more information.
*/
// SLIP Framing (if not using PULSE). Packet is: END, <packet>, <crc32>, END
#define END 0xC0
#define ESC 0xDB
#define ESC_END 0xDC
#define ESC_ESC 0xDD
// Version
typedef struct BinLogMessage_Version {
union {
struct {
uint8_t reserved:4;
uint8_t unhashed_msg:1;
uint8_t parameterized:1;
uint8_t tick_count:1;
uint8_t time_date:1;
};
uint8_t version;
};
} BinLogMessage_Version;
#define BINLOGMSG_VERSION_UNHASHED_MSG (1 << 3)
#define BINLOGMSG_VERSION_PARAMETERIZED (1 << 2)
#define BINLOGMSG_VERSION_TICK_COUNT (1 << 1)
#define BINLOGMSG_VERSION_TIME_DATE (1 << 0)
_Static_assert(sizeof(BinLogMessage_Version) == 1, "BinLogMessage_Version size != 1");
// Time_Full
// The times are in UTC. All values are 0 based (i.e., hour is [0,23], minute is [0,59],
// second is [0,59], millisecond is [0,999]).
typedef struct Time_Full {
uint32_t reserved:5;
uint32_t hour:5;
uint32_t minute:6;
uint32_t second:6;
uint32_t millisecond:10;
} Time_Full;
// Time_Tick
// Total ticks = (count_high << 32) | count.
typedef struct Time_Tick {
uint16_t reserved;
uint16_t count_high;
uint32_t count;
} Time_Tick;
// Date
// The year is an offset from 2000 (e.g. year = 16 is 2016).
// All remaining values are 1 based (i.e., month is [1,12], day is [1,31]).
// An invalid/unknown date is identified by (year, month, day) = (0, 0, 0). Thus, Date = 0 is an
// invalid date, not the start of the epoch, which would be (0, 1, 1).
typedef struct Date {
uint16_t year:7;
uint16_t month:4;
uint16_t day:5;
} Date;
// MessageID
typedef struct MessageID {
union {
struct {
uint32_t msg_number:19; // LSB
uint32_t task_id:4;
uint32_t str_index_1:3;
uint32_t str_index_2:3;
uint32_t reserved:1;
uint32_t core_number:2; // MSB
};
uint32_t msg_id;
};
} MessageID;
_Static_assert(sizeof(MessageID) == 4, "MessageID size != 4");
typedef struct BinLogMessage_Header {
uint8_t version;
uint8_t length;
} BinLogMessage_Header;
typedef struct BinLogMessage_Header_v0 {
uint8_t version;
uint8_t length;
uint8_t reserved[2];
} BinLogMessage_Header_v0;
#define BINLOGMSG_VERSION_HEADER_V0 (0)
typedef struct BinLogMessage_Header_v1 {
uint8_t version;
uint8_t length;
Date date;
Time_Full time;
} BinLogMessage_Header_v1;
#define BINLOGMSG_VERSION_HEADER_V1 (BINLOGMSG_VERSION_TIME_DATE)
typedef struct BinLogMessage_Header_v2 {
uint8_t version;
uint8_t length;
uint8_t reserved[2];
Time_Tick tick_count;
} BinLogMessage_Header_v2;
#define BINLOGMSG_VERSION_HEADER_V2 (BINLOGMSG_VERSION_TICK_COUNT)
typedef struct BinLogMessage_Header_v3 {
uint8_t version;
uint8_t length;
Date date;
Time_Full time;
Time_Tick tick_count;
} BinLogMessage_Header_v3;
#define BINLOGMSG_VERSION_HEADER_V3 (BINLOGMSG_VERSION_TIME_DATE | BINLOGMSG_VERSION_TICK_COUNT)
typedef struct BinLogMessage_ParamBody {
MessageID msgid;
uint32_t payload[0];
} BinLogMessage_ParamBody;
typedef struct BinLogMessage_StringParam {
uint8_t length;
uint8_t string[0]; // string[length]
// uint8_t padding[((length + sizeof(length) + 3) % 4)]
} BinLogMessage_StringParam;
typedef uint32_t BinLogMessage_IntParam;
typedef struct BinLogMessage_UnhashedBody {
uint16_t line_number;
uint8_t filename[16];
uint8_t reserved:2;
uint8_t core_number:2;
uint8_t task_id:4;
uint8_t level;
uint8_t length;
uint8_t string[0]; // string[length];
// uint8_t padding[];
} BinLogMessage_UnhashedBody;
/*
int len = MAX(strlen(log_string), 255 - sizeof(BinLogMessage_Header_vX))
typedef struct BinLogMessage_SimpleBody {
uint8_t string[len];
uint8_t padding[((sizeof(BinLogMessage_Header_vX) + len + 3) % 4)];
} BinLogMessage_SimpleBody;
*/
typedef struct BinLogMessage_Param_v0 {
BinLogMessage_Header_v0 header;
BinLogMessage_ParamBody body;
} BinLogMessage_Param_v0;
#define BINLOGMSG_VERSION_PARAM_V0 (BINLOGMSG_VERSION_HEADER_V0 | BINLOGMSG_VERSION_PARAMETERIZED)
typedef struct BinLogMessage_Param_v1 {
BinLogMessage_Header_v1 header;
BinLogMessage_ParamBody body;
} BinLogMessage_Param_v1;
#define BINLOGMSG_VERSION_PARAM_V1 (BINLOGMSG_VERSION_HEADER_V1 | BINLOGMSG_VERSION_PARAMETERIZED)
typedef struct BinLogMessage_Param_v2 {
BinLogMessage_Header_v2 header;
BinLogMessage_ParamBody body;
} BinLogMessage_Param_v2;
#define BINLOGMSG_VERSION_PARAM_V2 (BINLOGMSG_VERSION_HEADER_V2 | BINLOGMSG_VERSION_PARAMETERIZED)
typedef struct BinLogMessage_Param_v3 {
BinLogMessage_Header_v3 header;
BinLogMessage_ParamBody body;
} BinLogMessage_Param_v3;
#define BINLOGMSG_VERSION_PARAM_V3 (BINLOGMSG_VERSION_HEADER_V3 | BINLOGMSG_VERSION_PARAMETERIZED)
typedef struct BinLogMessage_Unhashed_v0 {
BinLogMessage_Header_v0 header;
BinLogMessage_UnhashedBody body;
} BinLogMessage_Unhashed_v0;
#define BINLOGMSG_VERSION_UNHASHED_V0 (BINLOGMSG_VERSION_HEADER_V0 | BINLOGMSG_VERSION_UNHASHED_MSG)
typedef struct BinLogMessage_Unhashed_v1 {
BinLogMessage_Header_v1 header;
BinLogMessage_UnhashedBody body;
} BinLogMessage_Unhashed_v1;
#define BINLOGMSG_VERSION_UNHASHED_V1 (BINLOGMSG_VERSION_HEADER_V1 | BINLOGMSG_VERSION_UNHASHED_MSG)
typedef struct BinLogMessage_Unhashed_v2 {
BinLogMessage_Header_v2 header;
BinLogMessage_UnhashedBody body;
} BinLogMessage_Unhashed_v2;
#define BINLOGMSG_VERSION_UNHASHED_V2 (BINLOGMSG_VERSION_HEADER_V2 | BINLOGMSG_VERSION_UNHASHED_MSG)
typedef struct BinLogMessage_Unhashed_v3 {
BinLogMessage_Header_v3 header;
BinLogMessage_UnhashedBody body;
} BinLogMessage_Unhashed_v3;
#define BINLOGMSG_VERSION_UNHASHED_V3 (BINLOGMSG_VERSION_HEADER_V3 | BINLOGMSG_VERSION_UNHASHED_MSG)
typedef struct BinLogMessage_String_v1 {
BinLogMessage_Header_v1 header;
uint8_t string[0];
} BinLogMessage_String_v1;
#define BINLOGMSG_VERSION_STRING_V1 (BINLOGMSG_VERSION_HEADER_V1)

View file

@ -0,0 +1,232 @@
/*
* 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.
*/
/************************************************************************************************
* New Logging
*
* The NewLogging system provides in place hashing during the compile stage of building, removing
* logging strings from the source code and replacing them with a unique token, conserving space in
* the firmware.
*
* The unique token is (well, see below) actually just a pointer to a new section in the .elf
* named .log_strings. The .log_strings section is mapped to an unused portion of memory and
* isn't compiled into the final firmware binary image.
*
* Token format:
* The token is acually a packed uint32_t. The format is as follows:
* 31-29: num fmt conversions [0-7]
* 28-26: string index 2 [0-7], 1 based. 0 if no second string. 1-7 otherwise
* 25-23: string index 1 [0-7], 1 based. 0 if no first string. 1-7 otherwise
* 22-20: log level [0-5] mapped onto LOG_LEVEL_ALWAYS through LOG_LEVEL_DEBUG_VERBOSE
* 19: reserved
* 18- 0: Offset info .log_strings section. This allows 512 KB of strings.
*
* Note: it might not be necessary to use so many bits for the log level. Dynamic flitering might
* not be so important, and 'log to flash' could be 1 bit, or Curried to a set of function calls.
* These changes would require more work in the logging infrastructure.
*
* .log_strings Section is formatted as follows:
* - .log_string.header: "NL<M><m>:<offset-mask>=<token-list>"
* where:
* - <M> is XX major version -- increase means not backwards compatible change
* - <m> is YY minor version -- increase means backwards compatible change
* - <offset-mask> defines the number of bits used in the token for the section offset
* - <token-list>: <token>:<token-list>
* : '\0'
* - <token>: <file>
* : <line>
* : <level>
* : <color>
* : <fmt>
* - .log_core_number: "CORE<C>"
* where:
* - <C> is the core number. This will be two bits.
* For now, the primary core will be 00; the Bluetooth chip will be 01.
* These definitions will be different for every system -- all that matters is that they're
* internally consistent.
* - .log_string
* which is a list of <token-list> representing the log strings from the source code.
*
* Note: this code must be compiled with -Os or the codesize will explode!
*
* Limitations:
* - maximum 7 format conversions per print
* - maximum 2 string conversions per print
* - string parameters may not be flagged or formatted in any way --'%s' only.
* - printing the '%' is not supported -- '%%' is not allowed.
* - only 32 bit (or fewer) parameters currently supported automatically. Multi-word parameters
* require special handling.
* - errors are not automatically detected. This will have to be done later by a script. Sorry.
*
* Extensions (to be implemented at some point):
* - Colour groups/overrides
* - MAC/BT address print: format specifier: %M/m
* - ENUM print: %u[<enum name>]
*
* LogHash.dict:
* See https://pebbletechnology.atlassian.net/wiki/display/DEV/New+Logging.
***********************************************************************************************/
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "util/attributes.h"
#define NEW_LOG_VERSION "0101"
#define LOG_STRINGS_SECTION_ADDRESS 0xC0000000
#define PACKED_CORE_OFFSET 30 // 2 bits - Core number
#define PACKED_CORE_MASK 0x03
#define PACKED_NUM_FMT_OFFSET 29 // 3 bits - Number format conversions
#define PACKED_NUM_FMT_MASK 0x07
#define PACKED_STR1FMT_OFFSET 26 // 3 bits - indicies of string parameter 1 format conversion
#define PACKED_STR1FMT_MASK 0x07
#define PACKED_STR2FMT_OFFSET 23 // 3 bits - indicies of string parameter 2 format conversion
#define PACKED_STR2FMT_MASK 0x07
#define PACKED_STRFMTS_OFFSET 23 // 6 bits - indicies of string parameters 1 & 2.
#define PACKED_STRFMTS_MASK 0x3f
#define PACKED_LEVEL_OFFSET 20 // 3 bits - log level
#define PACKED_LEVEL_MASK 0x07
#define PACKED_HASH_OFFSET 0
#define PACKED_HASH_MASK 0x7FFFF // 19 bits - string table offset (512 KB)
#define MSGID_STR_AND_HASH_MASK ((PACKED_STRFMTS_MASK << PACKED_STRFMTS_OFFSET) | \
(PACKED_HASH_MASK << PACKED_HASH_OFFSET))
#define MSGID_CORE_AND_HASH_MASK ((PACKED_CORE_MASK << PACKED_CORE_OFFSET) | \
(PACKED_HASH_MASK << PACKED_HASH_OFFSET))
#ifndef STRINGIFY
#define STRINGIFY_NX(a) #a
#define STRINGIFY(a) STRINGIFY_NX(a)
#endif // STRINGIFY
/* Printf Format argument checking.
*
* NB: it's critical that the 'if (false)' tag is included before the call to
* PBL_LOG_x_printf_arg_check(). Without this obviously useless check, PBL_LOG_x_printf_arg_check()
* would not be optimised out and cause a) a linker error (missing function body), b) take up
* code space & time, and c) would cause the arguments passed to PBL_LOG (NEW_LOG_HASH) to be
* evaluated twice. This is fine with normal parameters, but could result in macros or functions
* being called twice and messing up globals in unexpected ways.
*/
void PBL_LOG_x_printf_arg_check(const char *fmt, ...) FORMAT_PRINTF(1, 2);
#define NEW_LOG_HASH(logfunc, level, color, fmt, ...) \
{ \
static const char str[] __attribute__((nocommon, section(".log_strings"))) = \
__FILE__ ":" STRINGIFY(__LINE__) ":" STRINGIFY(level) ":" color ":" fmt; \
logfunc((uint32_t)&str[LOG_SECTION_OFFSET(level, fmt)], ##__VA_ARGS__); \
if (0) PBL_LOG_x_printf_arg_check(fmt, ##__VA_ARGS__); \
}
ALWAYS_INLINE static uint32_t LOG_SECTION_OFFSET(const uint8_t level, const char *fmt) {
const char *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
const char *p5 = NULL, *p6 = NULL, *p7 = NULL, *p8 = NULL;
const char *s1 = NULL, *s2 = NULL, *s3 = NULL, *s4 = NULL;
const char *s5 = NULL, *s6 = NULL, *s7 = NULL;
// Search for % characters in fmt. p1-p8 point to the character immediately succeeding the first
// 8 % characters in fmt (or NULL, if there aren't 8 % characters in fmt).
p1 = __builtin_strchr(fmt, '%') ? (__builtin_strchr(fmt, '%') + 1) : NULL;
if (p1) p2 = __builtin_strchr(p1, '%') ? (__builtin_strchr(p1, '%') + 1) : NULL;
if (p2) p3 = __builtin_strchr(p2, '%') ? (__builtin_strchr(p2, '%') + 1) : NULL;
if (p3) p4 = __builtin_strchr(p3, '%') ? (__builtin_strchr(p3, '%') + 1) : NULL;
if (p4) p5 = __builtin_strchr(p4, '%') ? (__builtin_strchr(p4, '%') + 1) : NULL;
if (p5) p6 = __builtin_strchr(p5, '%') ? (__builtin_strchr(p5, '%') + 1) : NULL;
if (p6) p7 = __builtin_strchr(p6, '%') ? (__builtin_strchr(p6, '%') + 1) : NULL;
if (p7) p8 = __builtin_strchr(p7, '%') ? (__builtin_strchr(p7, '%') + 1) : NULL;
// Check that fmt doesn't contain the escaped % symbol, '%%'. It's too hard to handle correctly
// in every case.
if ((p1 + 1 == p2) || (p2 + 1 == p3) || (p3 + 1 == p4) || (p4 + 1 == p5) ||
(p5 + 1 == p6) || (p6 + 1 == p7) || (p7 + 1 == p8)) {
return 0;
}
// Count number of valid pointers by bool-inversion-twice
uint8_t num_params = !!p1 + !!p2 + !!p3 + !!p4 + !!p5 + !!p6 + !!p7 + !!p8;
// Check that there aren't more than 7 format conversions. We have only 3 bits per string index.
if (num_params > 7) {
return 0;
}
// Search for an 's' character succeeding the % characters in fmt. s1-s7 point to the first 's'
// charactres in fmt after the previously found % characters (or NULL if there aren't 7 's'
// characters in fmt).
if (p1) s1 = __builtin_strchr(p1, 's');
if (p2) s2 = __builtin_strchr(p2, 's');
if (p3) s3 = __builtin_strchr(p3, 's');
if (p4) s4 = __builtin_strchr(p4, 's');
if (p5) s5 = __builtin_strchr(p5, 's');
if (p6) s6 = __builtin_strchr(p6, 's');
if (p7) s7 = __builtin_strchr(p7, 's');
// See if the 's' characters immediately succeed the '%' characters. If so, set flag psX.
const int ps1 = p1 ? (p1 == s1) : 0;
const int ps2 = p2 ? (p2 == s2) : 0;
const int ps3 = p3 ? (p3 == s3) : 0;
const int ps4 = p4 ? (p4 == s4) : 0;
const int ps5 = p5 ? (p5 == s5) : 0;
const int ps6 = p6 ? (p6 == s6) : 0;
const int ps7 = p7 ? (p7 == s7) : 0;
// Count the number of '%s' parameters
const int num_s_params = ps1 + ps2 + ps3 + ps4 + ps5 + ps6 + ps7;
// We currently support only 2 string parameters.
if (num_s_params > 2) {
return 0;
}
// Format the (maximum) two string parameter indicies as:
// (1-based index of first %s << 3) | (1-based index of second %s << 0)
// If there is only one %s parameter, the index will be formatted as:
// (1-based index of first %s << 0)
const int a1 = ps1 ? 1 : 0;
const int a2 = ps2 ? (a1 << 3) + 2 : a1;
const int a3 = ps3 ? (a2 << 3) + 3 : a2;
const int a4 = ps4 ? (a3 << 3) + 4 : a3;
const int a5 = ps5 ? (a4 << 3) + 5 : a4;
const int a6 = ps6 ? (a5 << 3) + 6 : a5;
const int a7 = ps7 ? (a6 << 3) + 7 : a6;
const int string_indicies = a7;
// Convert level to packed_level
int packed_level = LOG_LEVEL_ALWAYS;
if (level == LOG_LEVEL_ERROR) {
packed_level = 1;
} else if (level == LOG_LEVEL_WARNING) {
packed_level = 2;
} else if (level == LOG_LEVEL_INFO) {
packed_level = 3;
} else if (level == LOG_LEVEL_DEBUG) {
packed_level = 4;
} else if (level == LOG_LEVEL_DEBUG_VERBOSE) {
packed_level = 5;
}
const uint32_t offset = (((num_params & PACKED_NUM_FMT_MASK) << PACKED_NUM_FMT_OFFSET) |
((packed_level & PACKED_LEVEL_MASK) << PACKED_LEVEL_OFFSET) |
((string_indicies & PACKED_STRFMTS_MASK) << PACKED_STRFMTS_OFFSET));
return (offset - LOG_STRINGS_SECTION_ADDRESS);
}

View file

@ -0,0 +1,31 @@
/*
* 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.
*/
#pragma once
/*
* chip_id.h
*
* This file specifies IDs for the different processors on our multi-processor devices.
* The IDs are used to differenetiate the source of system logs, core dumps, etc.
*
* The IDs must be unique within a platform and must fit in 2 bits.
* If we build a device with more than 4 log/core dump producing processors, this will need to be
* addressed.
*/
#define CORE_ID_MAIN_MCU 0
#define CORE_ID_BLE 1

View file

@ -0,0 +1,59 @@
/*
* 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.
*/
#pragma once
/*
* core_dump_structs.h
*
* This file specifies core_dump structures previously defined in fw/kernel/core_dump_private.h
* This is so the Dialog BLE core_dump code can use the same structures.
*
*/
#include "portmacro.h"
#include "util/attributes.h"
// Structure of thread info stored within a CORE_DUMP_CHUNK_KEY_THREAD chunk in the core dump
#define CORE_DUMP_THREAD_NAME_SIZE 16
typedef struct PACKED {
int8_t name[CORE_DUMP_THREAD_NAME_SIZE]; // Name, includes null termination
uint32_t id; // thread id
uint8_t running; // true if this thread is running
uint32_t registers[portCANONICAL_REG_COUNT]; // registers [r0-r12, sp, lr, pc, xpsr]
} CoreDumpThreadInfo;
// Structure of extra registers stored within a CORE_DUMP_CHUNK_KEY_EXTRA_REG chunk in the
// core dump
typedef struct PACKED {
uint32_t msp;
uint32_t psp;
uint8_t primask;
uint8_t basepri;
uint8_t faultmask;
uint8_t control;
} CoreDumpExtraRegInfo;
// We save all the important registers on entry to core_dump_reset() in a structure of this type
// on the core_dump_reset() stack and save a pointer to it in the s_saved_registers global.
// IMPORTANT!: There is assembly code near the top of core_dump_reset() that makes assumptions
// about the order and packing of this structure.
typedef struct PACKED {
uint32_t core_reg[portCANONICAL_REG_COUNT];
CoreDumpExtraRegInfo extra_reg;
} CoreDumpSavedRegisters;

141
src/include/pebbleos/cron.h Normal file
View file

@ -0,0 +1,141 @@
/*
* 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.
*/
#pragma once
#include <time.h>
#include "util/list.h"
//! @file cron.h
//! Wall-clock based timer system. Designed for use in things such as alarms, calendar events, etc.
//! Properly handles DST, etc.
typedef struct CronJob CronJob;
typedef void (*CronJobCallback)(CronJob *job, void* data);
//! Matches any possible value.
#define CRON_MINUTE_ANY (-1)
#define CRON_HOUR_ANY (-1)
#define CRON_MDAY_ANY (-1)
#define CRON_MONTH_ANY (-1)
#define WDAY_SUNDAY (1 << 0)
#define WDAY_MONDAY (1 << 1)
#define WDAY_TUESDAY (1 << 2)
#define WDAY_WEDNESDAY (1 << 3)
#define WDAY_THURSDAY (1 << 4)
#define WDAY_FRIDAY (1 << 5)
#define WDAY_SATURDAY (1 << 6)
#define WDAY_WEEKDAYS (WDAY_MONDAY | WDAY_TUESDAY | WDAY_WEDNESDAY | WDAY_THURSDAY | WDAY_FRIDAY)
#define WDAY_WEEKENDS (WDAY_SUNDAY | WDAY_SATURDAY)
#define WDAY_ANY (WDAY_WEEKENDS | WDAY_WEEKDAYS)
struct CronJob {
//! internal, no touchy
ListNode list_node;
//! Cached execution timestamp in UTC.
//! This is set by `cron_job_schedule`, and is required to never be changed once the job has been
//! added.
time_t cached_execute_time;
//! Callback that is called when the job fires.
CronJobCallback cb;
void* cb_data;
//! Occasionally, the system gets a clock change event for various reasons:
//! - User changed time-zones or a DST transition happened
//! - User changed the time
//! - Phone sent the current time and was different from ours, so we took theirs.
//! In the first case, the cron job's execute time will always be recalculated.
//! In the other two, we see if the time difference from the old time is >= this.
//! If it is, then we'll recalculate. Otherwise, we leave the calculated time alone.
//! In this way, 0 will always recalculate, and UINT32_MAX will never recalculate.
//!
//! Recalculating would essentially mean that a job that was "skipped over" will not fire until
//! the next match. If recalculation is not done, but the job was skipped over, it will fire
//! instantly.
//!
//! This value is specified in seconds.
uint32_t clock_change_tolerance;
int8_t minute; //!< 0-59, or CRON_MINUTE_ANY
int8_t hour; //!< 0-23, or CRON_HOUR_ANY
int8_t mday; //!< 0-30, or CRON_MDAY_ANY
int8_t month; //!< 0-11, or CRON_MONTH_ANY
//! Seconds to offset the cron execution time applied after regular cron job time calculation.
//! For example, a cron scheduled for Monday at 0:15 with an offset of negative 30min will fire
//! on Sunday at 23:45.
int32_t offset_seconds;
union {
uint8_t flags;
struct {
//! This should be any combination of WDAY_*. If zero, acts like WDAY_ANY.
uint8_t wday : 7;
//! If this flag is set, the resulting execution time may be equal to the local epoch.
//! Having it set could be used for some event that must happen at the specified time even if
//! that time is right now.
bool may_be_instant : 1;
};
};
};
//! Add a cron job. This will make the service hold a reference to the specified job, so it must
//! not leave scope or be destroyed until it is unscheduled.
//! The job only gets scheduled once. For re-scheduling, you can call this on the job again.
//! @params job pointer to the CronJob struct to be scheduled.
//! @returns time_t for when the job is destined to go off.
time_t cron_job_schedule(CronJob *job);
//! Schedule a cron job to run after another cron job.
//! This will make the service hold a reference to the new job, so it must
//! not leave scope or be destroyed until it is unscheduled.
//! @param job pointer to the CronJob after which we want our job to run. job must be scheduled.
//! @params new_job pointer to the CronJob struct to be scheduled. new_job must be unscheduled.
//! @returns time_t for when the job is destined to go off.
//! @note This API makes no guarantee that the two jobs will be scheduled back to back,
//! only that new_job will have the same scheduled time as job and that it will trigger
//! strictly after job.
time_t cron_job_schedule_after(CronJob *new_job, CronJob *job);
//! Remove a scheduled cron job.
//! @params job pointer to the CronJob struct to be unscheduled.
//! @return true if the job was successfully removed (false may indicate no job was
//! scheduled at all or the cb is currently executing)
bool cron_job_unschedule(CronJob *job);
//! Check if a cron job is scheduled.
//! @params job pointer to the CronJob struct to be checked for being scheduled.
//! @returns true if scheduled or pending deletion, false otherwise
bool cron_job_is_scheduled(CronJob *job);
//! Calculate cron job's destined execution time, from the current time.
//! @params job pointer to the CronJob struct to get the execution time for.
//! @returns time_t for when the job is destined to go off.
time_t cron_job_get_execute_time(const CronJob *job);
//! Calculate cron job's destined execution time if it were scheduled at the given time.
//! @params job pointer to the CronJob struct to get the execution time for.
//! @params local_epoch the epoch for getting the job's execution time.
//! @returns time_t for when the job is destined to go off.
time_t cron_job_get_execute_time_from_epoch(const CronJob *job, time_t local_epoch);

View file

@ -0,0 +1,138 @@
/*
* 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.
*/
#pragma once
/*
* firmware_metadata.h
*
* This file specifies the Firmware Metadata structure used in the .elf & .bin files to
* identify the build info, etc.
*/
#include "util/attributes.h"
#include <stdint.h>
#include <stdbool.h>
#define FW_METADATA_CURRENT_STRUCT_VERSION 0x1
#define FW_METADATA_VERSION_SHORT_BYTES 8
#define FW_METADATA_VERSION_TAG_BYTES 32
// NOTE: When adding new platforms, if they use the legacy defective CRC, the list in
// tools/fw_binary_info.py needs to be updated with the platform value.
typedef enum FirmwareMetadataPlatform {
FirmwareMetadataPlatformUnknown = 0,
FirmwareMetadataPlatformPebbleOneEV1 = 1,
FirmwareMetadataPlatformPebbleOneEV2 = 2,
FirmwareMetadataPlatformPebbleOneEV2_3 = 3,
FirmwareMetadataPlatformPebbleOneEV2_4 = 4,
FirmwareMetadataPlatformPebbleOnePointFive = 5,
FirmwareMetadataPlatformPebbleTwoPointZero = 6,
FirmwareMetadataPlatformPebbleSnowyEVT2 = 7,
FirmwareMetadataPlatformPebbleSnowyDVT = 8,
FirmwareMetadataPlatformPebbleSpaldingEVT = 9,
FirmwareMetadataPlatformPebbleBobbyDVT = 10,
FirmwareMetadataPlatformPebbleSpalding = 11,
FirmwareMetadataPlatformPebbleSilkEVT = 12,
FirmwareMetadataPlatformPebbleRobertEVT = 13,
FirmwareMetadataPlatformPebbleSilk = 14,
FirmwareMetadataPlatformPebbleOneBigboard = 0xff,
FirmwareMetadataPlatformPebbleOneBigboard2 = 0xfe,
FirmwareMetadataPlatformPebbleSnowyBigboard = 0xfd,
FirmwareMetadataPlatformPebbleSnowyBigboard2 = 0xfc,
FirmwareMetadataPlatformPebbleSpaldingBigboard = 0xfb,
FirmwareMetadataPlatformPebbleSilkBigboard = 0xfa,
FirmwareMetadataPlatformPebbleRobertBigboard = 0xf9,
FirmwareMetadataPlatformPebbleSilkBigboard2 = 0xf8,
FirmwareMetadataPlatformPebbleRobertBigboard2 = 0xf7,
} FirmwareMetadataPlatform;
// WARNING: changes in this struct must be reflected in:
// - iOS/PebblePrivateKit/PebblePrivateKit/PBBundle.m
struct PACKED FirmwareMetadata {
uint32_t version_timestamp;
char version_tag[FW_METADATA_VERSION_TAG_BYTES];
char version_short[FW_METADATA_VERSION_SHORT_BYTES];
bool is_recovery_firmware:1;
bool is_ble_firmware:1;
uint8_t reserved:6;
uint8_t hw_platform;
//! This should be the last field, since we put the meta data struct at the end of the fw binary.
uint8_t metadata_version;
};
typedef struct FirmwareMetadata FirmwareMetadata;
_Static_assert(sizeof(struct FirmwareMetadata) == (sizeof(uint32_t) +
FW_METADATA_VERSION_SHORT_BYTES + FW_METADATA_VERSION_TAG_BYTES + sizeof(uint8_t) +
sizeof(uint8_t) + sizeof(uint8_t)),
"FirmwareMetadata bitfields not packed correctly");
// Shared defines. Let's not duplicate this everywhere.
#ifdef RECOVERY_FW
#define FIRMWARE_METADATA_IS_RECOVERY_FIRMWARE (true)
#else
#define FIRMWARE_METADATA_IS_RECOVERY_FIRMWARE (false)
#endif
#if BOARD_BIGBOARD
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleOneBigboard)
#elif BOARD_BB2
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleOneBigboard2)
#elif BOARD_SNOWY_BB
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSnowyBigboard)
#elif BOARD_SNOWY_BB2
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSnowyBigboard2)
#elif BOARD_SNOWY_EVT2
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSnowyEVT2)
#elif BOARD_SNOWY_DVT
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSnowyDVT)
#elif BOARD_SNOWY_S3
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleBobbyDVT)
#elif BOARD_V2_0
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleTwoPointZero)
#elif BOARD_V1_5
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleOnePointFive)
#elif BOARD_EV2_4
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleOneEV2_4)
#elif BOARD_SPALDING_BB2
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSpaldingBigboard)
#elif BOARD_SPALDING_EVT
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSpaldingEVT)
#elif BOARD_SPALDING
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSpalding)
#elif BOARD_SILK_EVT
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSilkEVT)
#elif BOARD_SILK_BB
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSilkBigboard)
#elif BOARD_SILK
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSilk)
#elif BOARD_SILK_BB2
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleSilkBigboard2)
#elif BOARD_ROBERT_BB
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleRobertBigboard)
#elif BOARD_ROBERT_BB2
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleRobertBigboard2)
#elif BOARD_ROBERT_EVT
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformPebbleRobertEVT)
#else
#define FIRMWARE_METADATA_HW_PLATFORM (FirmwareMetadataPlatformUnknown)
#endif

6
src/include/wscript Normal file
View file

@ -0,0 +1,6 @@
def build(bld):
bld(export_includes=['.'],
use=['libc_includes', 'libutil_includes'],
name='root_includes')
# vim:filetype=python