Getting Started
This guide covers how to define your protocol, generate code, and integrate bleRPC into your project.
1. Define Your Protocol
Create a .proto file defining your RPC messages. Each command is a Request/Response pair:
syntax = "proto3";
package blerpc;
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
message FlashReadRequest {
uint32 address = 1;
uint32 length = 2;
}
message FlashReadResponse {
uint32 address = 1;
bytes data = 2;
}
Commands are automatically discovered from matching *Request / *Response pairs. For example, EchoRequest + EchoResponse generates an echo command.
2. Code Generation
The generate-handlers tool generates handler stubs and client code for all supported languages.
Build the generator
cd tools/generate-handlers
go build -o generate-handlers .
Run code generation
./generate-handlers -root /path/to/blerpc
This generates the following files:
| Output | Description |
|---|---|
peripheral/src/generated_handlers.h | C handler declarations + lookup table |
peripheral/src/generated_handlers.c | C weak handler stubs |
peripheral_py/generated_handlers.py | Python handler stubs |
central/blerpc/generated/generated_client.py | Python client mixin |
central_android/.../GeneratedClient.kt | Kotlin abstract client |
central_ios/.../GeneratedClient.swift | Swift client protocol extension |
3. Platform Integration
iOS (Swift)
Dependencies
Add to your Xcode project via Swift Package Manager:
// Package.swift or Xcode > File > Add Package Dependencies
https://github.com/tdaira/blerpc-protocol-swift (from: 0.1.0)
https://github.com/apple/swift-protobuf.git (from: 1.28.0)
Generate Protobuf types
brew install swift-protobuf
protoc --swift_out=YourApp/Proto/ \
--swift_opt=Visibility=Public \
-I proto/ proto/blerpc.proto
Usage
let client = BlerpcClient()
try await client.connect()
// Type-safe RPC call
let response = try await client.echo(message: "hello")
print(response.message) // "hello"
// Read flash data
let flash = try await client.flashRead(address: 0, length: 8192)
print(flash.data.count) // 8192
client.disconnect()
Android (Kotlin)
Dependencies
Add to your build.gradle.kts:
repositories {
maven {
url = uri("https://maven.pkg.github.com/tdaira/blerpc-protocol-kt")
credentials { /* GitHub token */ }
}
}
dependencies {
implementation("com.blerpc:blerpc-protocol-kt:0.1.0")
}
Usage
val client = BlerpcClient(context)
client.connect()
val response = client.echo(message = "hello")
println(response.message) // "hello"
client.disconnect()
Python (macOS / Linux)
Dependencies
pip install bleak protobuf
pip install git+https://github.com/tdaira/blerpc-protocol.git
Generate Protobuf types
protoc --python_out=central/blerpc/generated/ \
-I proto/ proto/blerpc.proto
Usage
from blerpc.client import BlerpcClient
async with BlerpcClient() as client:
await client.connect()
resp = await client.echo(message="hello")
print(resp.message) # "hello"
flash = await client.flash_read(address=0, length=8192)
print(len(flash.data)) # 8192
Zephyr Peripheral (C)
Implement handlers
The generated handlers are __attribute__((weak)). Override them in your own source file:
// handlers.c
#include "generated_handlers.h"
#include "blerpc.pb.h"
int handle_echo(const uint8_t *req_data, size_t req_len,
pb_ostream_t *ostream) {
blerpc_EchoRequest req = blerpc_EchoRequest_init_zero;
pb_istream_t stream = pb_istream_from_buffer(req_data, req_len);
if (!pb_decode(&stream, blerpc_EchoRequest_fields, &req))
return -1;
blerpc_EchoResponse resp = blerpc_EchoResponse_init_zero;
strncpy(resp.message, req.message, sizeof(resp.message) - 1);
if (!pb_encode(ostream, blerpc_EchoResponse_fields, &resp))
return -1;
return 0;
}
Build
# nRF54L15
west build -b nrf54l15dk/nrf54l15/cpuapp peripheral
# EFR32xG22E
west build -b xg22_ek2710a peripheral -- -DBOARD_ROOT=/path/to/blerpc
4. Testing with Python Central
The easiest way to verify your peripheral is working:
# Flash the peripheral firmware
west flash
# Run the Python integration tests
cd central
python -m pytest tests/test_integration.py -v
Or use the interactive client:
python -c "
import asyncio
from blerpc.client import BlerpcClient
async def main():
client = BlerpcClient()
await client.connect()
resp = await client.echo(message='hello')
print(f'Echo: {resp.message}')
await client.disconnect()
asyncio.run(main())
"