Skip to content

Commit f6a9c21

Browse files
authored
feat(gfps_service): Add Google Fast Pair Service (#161)
* feat(gfps_service): Add Google Fast Pair Service * Add google/nearby submodule under external folder * Add gfps_service component implementing the device specific google/nearby support as well as a wrapper service for GFPS * Add gfps_service example * Update and rebuild docs (and clean up some extraneous files) * Update CI * rebuild docs * readme: update
1 parent a104339 commit f6a9c21

File tree

130 files changed

+3188
-462
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+3188
-462
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ jobs:
5555
target: esp32
5656
- path: 'components/ft5x06/example'
5757
target: esp32s3
58+
- path: 'components/gfps_service/example'
59+
target: esp32s3
5860
- path: 'components/gt911/example'
5961
target: esp32s3
6062
- path: 'components/hid-rp/example'

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@
3434
[submodule "external/hid-rp"]
3535
path = external/hid-rp
3636
url = https://github.com/intergatedcircuits/hid-rp
37+
[submodule "external/nearby"]
38+
path = external/nearby
39+
url = git@github.com:google/nearby
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
idf_component_register(
2+
INCLUDE_DIRS "../../external/nearby/embedded/client/source" "../../external/nearby/embedded/common/source" "../../external/nearby/embedded/common/target" "include"
3+
SRC_DIRS "../../external/nearby/embedded/client/source" "../../external/nearby/embedded/common/source" "../../external/nearby/embedded/common/source/mbedtls" "src"
4+
REQUIRES "esp_hw_support" "esp-nimble-cpp" "mbedtls" "nvs_flash" "logger" "task" "timer" "base_component"
5+
)
6+
add_definitions(-DNEARBY_TRACE_LEVEL=6) # log levels are VERBOSE=1, DEBUG, INFO, WARN, ERROR, OFF=6
7+
add_definitions(-DNEARBY_PLATFORM_USE_MBEDTLS=1)
8+
add_definitions(-DNEARBY_FP_ENABLE_BATTERY_NOTIFICATION=0)
9+
add_definitions(-DNEARBY_FP_ENABLE_ADDITIONAL_DATA=0)
10+
add_definitions(-DNEARBY_FP_MESSAGE_STREAM=0)
11+
# add_definitions(-DNEARBY_PLATFORM_HAS_SE)
12+
# add_definitions(-DNEARBY_FP_HAVE_BLE_ADDRESS_ROTATION=0)
13+
# add_definitions(-DNEARBY_FP_ENABLE_SASS=0) # smart audio source switching
14+
add_definitions(-DNEARBY_FP_RETROACTIVE_PAIRING=1) # not sure what this is...
15+
add_definitions(-DNEARBY_FP_BLE_ONLY=1)
16+
add_definitions(-DNEARBY_FP_PREFER_BLE_BONDING=1)
17+
add_definitions(-DNEARBY_FP_PREFER_LE_TRANSPORT=1)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
menu "GFPS Configuration"
2+
config GFPS_MODEL_ID
3+
hex "GFPS Model ID"
4+
default 0x0
5+
help
6+
Set the model id (24 bit) used for Google Fast Pair Service (GFPS)
7+
8+
config GFPS_ANTISPOOFING_PRIVATE_KEY
9+
string "GFPS Anti-Spoofing Private Key"
10+
default ""
11+
help
12+
Set the GFPS anti-spoofing private key, as a base64 uncompressed string.
13+
endmenu
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
7+
8+
# add the component directories that we want to use
9+
set(EXTRA_COMPONENT_DIRS
10+
"../../../components/"
11+
)
12+
13+
set(
14+
COMPONENTS
15+
"main esptool_py ble_gatt_server gfps_service"
16+
CACHE STRING
17+
"List of components to include"
18+
)
19+
20+
project(gfps_service_example)
21+
22+
set(CMAKE_CXX_STANDARD 20)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Google Fast Pair Service (GFPS) Service Example
2+
3+
This example shows how to use the `espp::GfpsService` class together with the
4+
`espp::BleGattServer` class to create and manage a BLE GATT server that provides
5+
support for Google Fast Pair Service (GFPS) using the
6+
[nearby/embedded](https://github.com/google/nearby) framework.
7+
8+
NOTE: this example uses a pre-registered device. If you want to register your
9+
own device(s), you must do that on the [nearby/devices
10+
dashboard](https://developers.google.com/nearby/devices).
11+
12+
## How to use example
13+
14+
### Hardware Required
15+
16+
This example should run on any ESP32s3 development board as it requires no
17+
peripheral connections.
18+
19+
### Build and Flash
20+
21+
Build the project and flash it to the board, then run monitor tool to view serial output:
22+
23+
```
24+
idf.py -p PORT flash monitor
25+
```
26+
27+
(Replace PORT with the name of the serial port to use.)
28+
29+
(To exit the serial monitor, type ``Ctrl-]``.)
30+
31+
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
32+
33+
## Example Output
34+
35+
![CleanShot 2024-02-29 at 09 51 07](https://github.com/esp-cpp/espp/assets/213467/dbd44440-56dd-4a61-8448-9a1e4543d73b)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRC_DIRS "."
2+
INCLUDE_DIRS ".")
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include <chrono>
2+
#include <vector>
3+
4+
#include "ble_gatt_server.hpp"
5+
#include "gfps_service.hpp"
6+
7+
using namespace std::chrono_literals;
8+
9+
extern "C" void app_main(void) {
10+
espp::Logger logger({.tag = "Gfps Service Example", .level = espp::Logger::Verbosity::INFO});
11+
logger.info("Starting");
12+
13+
//! [gfps service example]
14+
15+
// NOTE: esp-nimble-cpp already depends on nvs_flash and initializes
16+
// nvs_flash in the NimBLEDevice::init(), so we don't have to do that
17+
// to store bonding info
18+
19+
// create the GATT server
20+
espp::BleGattServer ble_gatt_server;
21+
std::string device_name = "ESP++ GFPS Example";
22+
ble_gatt_server.set_log_level(espp::Logger::Verbosity::INFO);
23+
ble_gatt_server.set_callbacks({
24+
.connect_callback = [&](NimBLEConnInfo &conn_info) { logger.info("Device connected"); },
25+
.disconnect_callback = [&](NimBLEConnInfo &conn_info) { logger.info("Device disconnected"); },
26+
.authentication_complete_callback =
27+
[&](NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
28+
});
29+
ble_gatt_server.init(device_name);
30+
ble_gatt_server.set_advertise_on_disconnect(true);
31+
32+
// let's create a GFPS service
33+
espp::GfpsService gfps_service;
34+
gfps_service.init(ble_gatt_server.server());
35+
36+
// now that we've made the input characteristic, we can start the service
37+
gfps_service.start();
38+
ble_gatt_server.start_services(); // starts the device info service and battery service
39+
// NOTE: we could also directly start them ourselves if we wanted to
40+
// control the order of starting the services
41+
// e.g.:
42+
// ble_gatt_server.battery_service().start();
43+
// ble_gatt_server.device_info_service().start();
44+
45+
// now start the gatt server
46+
ble_gatt_server.start();
47+
48+
// let's set some of the service data
49+
auto &battery_service = ble_gatt_server.battery_service();
50+
battery_service.set_battery_level(99);
51+
52+
auto &device_info_service = ble_gatt_server.device_info_service();
53+
uint8_t vendor_source = 0x02; // USB
54+
uint16_t vid = 0x045E; // Microsoft
55+
uint16_t pid = 0x02FD; // Xbox One Controller
56+
uint16_t product_version = 0x0100;
57+
device_info_service.set_pnp_id(vendor_source, vid, pid, product_version);
58+
device_info_service.set_manufacturer_name("ESP-CPP");
59+
// NOTE: this is NOT required to be the same as the GFPS SKU Name
60+
device_info_service.set_model_number("espp-gfps-01");
61+
device_info_service.set_serial_number("1234567890");
62+
device_info_service.set_software_version("1.0.0");
63+
device_info_service.set_firmware_version("1.0.0");
64+
device_info_service.set_hardware_version("1.0.0");
65+
66+
// now lets start advertising
67+
espp::BleGattServer::AdvertisingData adv_data = {
68+
.name = device_name,
69+
.appearance = 0x03C4, // Gamepad
70+
.services = {},
71+
.service_data =
72+
{// these are the service data that we want to advertise
73+
{gfps_service.uuid(), gfps_service.get_service_data()}},
74+
};
75+
espp::BleGattServer::AdvertisingParameters adv_params = {};
76+
ble_gatt_server.start_advertising(adv_data, adv_params);
77+
78+
// now lets update the battery level every second
79+
uint8_t battery_level = 99;
80+
while (true) {
81+
auto start = std::chrono::steady_clock::now();
82+
83+
// update the battery level
84+
battery_service.set_battery_level(battery_level);
85+
battery_level = (battery_level % 100) + 1;
86+
87+
// sleep
88+
std::this_thread::sleep_until(start + 1s);
89+
}
90+
//! [gfps service example]
91+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Name, Type, SubType, Offset, Size
2+
nvs, data, nvs, 0x9000, 0x6000
3+
phy_init, data, phy, 0xf000, 0x1000
4+
factory, app, factory, 0x10000, 2M
5+
littlefs, data, spiffs, , 1M
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
CONFIG_IDF_TARGET="esp32s3"
2+
3+
# on the ESP32S3, which has native USB, we need to set the console so that the
4+
# CLI can be configured correctly:
5+
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
6+
7+
# Common ESP-related
8+
#
9+
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
10+
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
11+
12+
CONFIG_FREERTOS_HZ=1000
13+
14+
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
15+
16+
#
17+
# BT config
18+
#
19+
CONFIG_BT_ENABLED=y
20+
CONFIG_BT_BLUEDROID_ENABLED=n
21+
CONFIG_BT_NIMBLE_ENABLED=y
22+
CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y
23+
CONFIG_BT_NIMBLE_NVS_PERSIST=y
24+
CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=100
25+
CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
26+
27+
# NOTE: we can support extended advertising (longer advertisement packets) by
28+
# enabling the following:
29+
# CONFIG_BT_NIMBLE_EXT_ADV=y
30+
#
31+
# HOWEVER: we don't currently support this as the API to ble_gatt_server will
32+
# need to support this compile-time definition.
33+
34+
# Set the default Tx power level (P9 = +9dBm = the default)
35+
# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P9=y
36+
37+
# Support modem sleep (low power mode)
38+
# CONFIG_BT_CTRL_MODEM_SLEEP=y
39+
40+
# Set the ESP-NIMBLE-CPP Config
41+
CONFIG_NIMBLE_CPP_LOG_LEVEL_NONE=y

0 commit comments

Comments
 (0)