peat-btle 0.3.2

Bluetooth Low Energy mesh transport for Peat Protocol
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# Windows Platform Integration Guide

This guide covers integrating `peat-btle` into Windows applications using the WinRT Bluetooth APIs.

## Requirements

| Feature | Minimum Windows Version |
|---------|-------------------------|
| BLE Scanning | Windows 10 1703 (Creators Update) |
| BLE Advertising | Windows 10 1703 |
| GATT Client | Windows 10 1703 |
| GATT Server | Windows 10 1803 (April 2018 Update) |
| Extended Advertising | Windows 10 1903 |
| Coded PHY | Windows 10 2004 |

### Hardware Requirements

- Bluetooth 4.0+ adapter (built-in or USB dongle)
- For BLE 5.0 features: Bluetooth 5.0+ adapter

## Architecture

```
┌─────────────────────────────────────────┐
│       WinRtBleAdapter (Rust)            │
├─────────────────────────────────────────┤
│     Watcher      │      Publisher       │
│   (scanning)     │    (advertising)     │
├─────────────────────────────────────────┤
│  GattClient      │    GattServer        │
│  (connecting,    │   (hosting Peat      │
│   reading)       │    service)          │
├─────────────────────────────────────────┤
│           WinRT Bluetooth APIs          │
└─────────────────────────────────────────┘
```

## Project Setup

### Cargo.toml

```toml
[dependencies]
peat-btle = { version = "0.1", features = ["windows"] }
windows = { version = "0.54", features = [
    "Devices_Bluetooth",
    "Devices_Bluetooth_Advertisement",
    "Devices_Bluetooth_GenericAttributeProfile",
    "Devices_Enumeration",
    "Foundation",
    "Foundation_Collections",
    "Storage_Streams",
]}
tokio = { version = "1", features = ["full"] }
log = "0.4"
```

### Basic Usage

```rust
use peat_btle::platform::windows::WinRtBleAdapter;
use peat_btle::{BleConfig, NodeId, MeshTransport};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create configuration
    let config = BleConfig::new(NodeId::new(0x12345678));

    // Create and initialize adapter
    let mut adapter = WinRtBleAdapter::new()?;
    adapter.init(&config).await?;

    // Start operations
    adapter.start().await?;

    println!("Peat BLE running on Windows...");
    println!("Address: {:?}", adapter.address());

    // Keep running
    loop {
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    }
}
```

## WinRT API Mapping

### Advertisement Watcher (Scanning)

```rust
use windows::Devices::Bluetooth::Advertisement::*;

// Create watcher
let watcher = BluetoothLEAdvertisementWatcher::new()?;

// Configure scan settings
watcher.SetScanningMode(BluetoothLEScanningMode::Active)?;

// Set filter for Peat service UUID
let filter = BluetoothLEAdvertisementFilter::new()?;
let advertisement = BluetoothLEAdvertisement::new()?;
let service_uuids = advertisement.ServiceUuids()?;
service_uuids.Append(PEAT_SERVICE_GUID)?;
filter.SetAdvertisement(&advertisement)?;
watcher.SetAdvertisementFilter(&filter)?;

// Handle received advertisements
watcher.Received(&TypedEventHandler::new(|_, args: &Option<_>| {
    if let Some(args) = args {
        let address = args.BluetoothAddress()?;
        let rssi = args.RawSignalStrengthInDBm()?;
        let advertisement = args.Advertisement()?;
        let name = advertisement.LocalName()?.to_string();

        // Process discovered device
        println!("Found: {} RSSI: {}", name, rssi);
    }
    Ok(())
}))?;

// Start scanning
watcher.Start()?;
```

### Advertisement Publisher (Advertising)

```rust
use windows::Devices::Bluetooth::Advertisement::*;
use windows::Storage::Streams::*;

// Create publisher
let publisher = BluetoothLEAdvertisementPublisher::new()?;

// Build advertisement data
let advertisement = BluetoothLEAdvertisement::new()?;
advertisement.SetLocalName(&HSTRING::from("PEAT_DEMO-12345678"))?;

// Add service UUID
let service_uuids = advertisement.ServiceUuids()?;
service_uuids.Append(PEAT_SERVICE_GUID)?;

// Add service data
let data_section = BluetoothLEAdvertisementDataSection::new()?;
data_section.SetDataType(0x16)?; // Service Data - 16-bit UUID

let writer = DataWriter::new()?;
writer.WriteUInt16(PEAT_SERVICE_UUID_16BIT)?;
writer.WriteBytes(&beacon_data)?;
data_section.SetData(&writer.DetachBuffer()?)?;

let data_sections = advertisement.DataSections()?;
data_sections.Append(&data_section)?;

publisher.SetAdvertisement(&advertisement)?;

// Start advertising
publisher.Start()?;
```

### GATT Client (Connecting)

```rust
use windows::Devices::Bluetooth::*;
use windows::Devices::Bluetooth::GenericAttributeProfile::*;

async fn connect_to_device(address: u64) -> Result<(), Box<dyn std::error::Error>> {
    // Get device from address
    let device = BluetoothLEDevice::FromBluetoothAddressAsync(address)?.await?;

    // Get Peat service
    let services = device.GetGattServicesForUuidAsync(PEAT_SERVICE_GUID)?.await?;
    let service = services.Services()?.GetAt(0)?;

    // Get document characteristic
    let chars = service.GetCharacteristicsForUuidAsync(DOC_CHAR_GUID)?.await?;
    let characteristic = chars.Characteristics()?.GetAt(0)?;

    // Enable notifications
    characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
        GattClientCharacteristicConfigurationDescriptorValue::Notify
    )?.await?;

    // Handle value changes
    characteristic.ValueChanged(&TypedEventHandler::new(|_, args: &Option<_>| {
        if let Some(args) = args {
            let reader = DataReader::FromBuffer(&args.CharacteristicValue()?)?;
            let len = reader.UnconsumedBufferLength()? as usize;
            let mut data = vec![0u8; len];
            reader.ReadBytes(&mut data)?;

            // Process received data
            println!("Received {} bytes", data.len());
        }
        Ok(())
    }))?;

    Ok(())
}
```

### GATT Server (Hosting Service)

```rust
use windows::Devices::Bluetooth::GenericAttributeProfile::*;

async fn create_gatt_server() -> Result<(), Box<dyn std::error::Error>> {
    // Create service parameters
    let service_params = GattLocalCharacteristicParameters::new()?;
    service_params.SetCharacteristicProperties(
        GattCharacteristicProperties::Read |
        GattCharacteristicProperties::Write |
        GattCharacteristicProperties::Notify
    )?;
    service_params.SetReadProtectionLevel(GattProtectionLevel::Plain)?;
    service_params.SetWriteProtectionLevel(GattProtectionLevel::Plain)?;

    // Create service provider
    let result = GattServiceProvider::CreateAsync(PEAT_SERVICE_GUID)?.await?;
    let provider = result.ServiceProvider()?;

    // Add document characteristic
    let char_result = provider.Service()?.CreateCharacteristicAsync(
        DOC_CHAR_GUID,
        &service_params
    )?.await?;
    let characteristic = char_result.Characteristic()?;

    // Handle read requests
    characteristic.ReadRequested(&TypedEventHandler::new(|_, args: &Option<_>| {
        if let Some(args) = args {
            let deferral = args.GetDeferral()?;
            let request = args.GetRequestAsync()?.get()?;

            let writer = DataWriter::new()?;
            writer.WriteBytes(&get_current_document())?;
            request.RespondWithValue(&writer.DetachBuffer()?)?;

            deferral.Complete()?;
        }
        Ok(())
    }))?;

    // Handle write requests
    characteristic.WriteRequested(&TypedEventHandler::new(|_, args: &Option<_>| {
        if let Some(args) = args {
            let deferral = args.GetDeferral()?;
            let request = args.GetRequestAsync()?.get()?;

            let reader = DataReader::FromBuffer(&request.Value()?)?;
            let len = reader.UnconsumedBufferLength()? as usize;
            let mut data = vec![0u8; len];
            reader.ReadBytes(&mut data)?;

            // Process received document
            process_document(&data);

            request.Respond()?;
            deferral.Complete()?;
        }
        Ok(())
    }))?;

    // Start advertising
    let adv_params = GattServiceProviderAdvertisingParameters::new()?;
    adv_params.SetIsDiscoverable(true)?;
    adv_params.SetIsConnectable(true)?;
    provider.StartAdvertising(&adv_params)?;

    Ok(())
}
```

## High-Level Integration with PeatMesh

```rust
use peat_btle::{PeatMesh, PeatMeshConfig, NodeId};
use peat_btle::observer::{PeatEvent, PeatObserver};
use std::sync::Arc;

struct WindowsObserver;

impl PeatObserver for WindowsObserver {
    fn on_event(&self, event: PeatEvent) {
        match event {
            PeatEvent::EmergencyReceived { from_node } => {
                println!("EMERGENCY from {:08X}!", from_node.as_u32());
                // Show Windows notification
            }
            PeatEvent::PeerDiscovered { peer } => {
                println!("Discovered: {}", peer.display_name());
            }
            _ => {}
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create mesh
    let config = PeatMeshConfig::new(
        NodeId::new(0x12345678),
        "WIN-1",
        "DEMO",
    );
    let mesh = Arc::new(PeatMesh::new(config));

    // Add observer
    mesh.add_observer(Arc::new(WindowsObserver));

    // Create WinRT adapter and integrate with mesh
    let adapter = WinRtBleAdapter::new()?;

    // ... set up callbacks to call mesh.on_ble_* methods

    // Run tick loop
    loop {
        let now_ms = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)?
            .as_millis() as u64;

        if let Some(doc) = mesh.tick(now_ms) {
            // Broadcast document to connected peers
        }

        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    }
}
```

## UWP App Integration

For UWP apps, add capabilities to `Package.appxmanifest`:

```xml
<Capabilities>
    <DeviceCapability Name="bluetooth" />
    <DeviceCapability Name="bluetoothAdapter" />
</Capabilities>
```

## Desktop App (Win32)

For Win32 desktop apps, no special capabilities are needed, but ensure:

1. App runs with appropriate permissions
2. Bluetooth adapter is enabled
3. User has granted Bluetooth access in Windows Settings

## Troubleshooting

### Common Issues

| Issue | Cause | Solution |
|-------|-------|----------|
| `E_ACCESSDENIED` | Missing capability | Add bluetooth capability |
| No devices found | Filter too strict | Check service UUID filter |
| GATT server fails | Wrong Windows version | Requires 1803+ |
| Connection drops | Range issues | Move devices closer |

### Debug Logging

```rust
use log::LevelFilter;
use env_logger::Builder;

fn setup_logging() {
    Builder::new()
        .filter_level(LevelFilter::Debug)
        .filter_module("peat_btle", LevelFilter::Trace)
        .init();
}
```

### Check Bluetooth State

```rust
use windows::Devices::Radios::*;

async fn check_bluetooth_state() -> Result<bool, Box<dyn std::error::Error>> {
    let radios = Radio::GetRadiosAsync()?.await?;

    for i in 0..radios.Size()? {
        let radio = radios.GetAt(i)?;
        if radio.Kind()? == RadioKind::Bluetooth {
            return Ok(radio.State()? == RadioState::On);
        }
    }

    Ok(false)
}
```

## Performance Considerations

1. **Scanning**: Use filters to reduce callback frequency
2. **Advertising**: Use 500ms+ intervals for battery efficiency
3. **GATT**: Request appropriate MTU for document size
4. **Threading**: WinRT callbacks run on thread pool - sync to UI thread as needed

## References

- [Windows.Devices.Bluetooth Namespace]https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth
- [Bluetooth GATT Server]https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-server
- [windows-rs crate]https://github.com/microsoft/windows-rs