Skip to content

Commit

Permalink
Update BLE examples. (#373)
Browse files Browse the repository at this point in the history
  • Loading branch information
floitsch authored Jan 9, 2023
1 parent f85f3a6 commit 256d2a9
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 60 deletions.
60 changes: 31 additions & 29 deletions docs/tutorials/ble/advertising.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ A BLE device can advertise itself for other devices to see it. So in the base fo
import ble
main:
device := ble.Device.default
adapter := ble.Adapter
peripheral := adapter.peripheral
advertiser := device.advertise
advertiser.start
data := ble.AdvertisementData
advertiser.wait_for_done
peripheral.start_advertise data
sleep --ms=10000
peripheral.stop_advertise
```

## Name
Expand All @@ -22,16 +24,15 @@ Sometimes it can be beneficial to advertise the name of the BLE device. That can
import ble
main:
device := ble.Device.default
adapter := ble.Adapter
peripheral := adapter.peripheral
data := ble.AdvertisementData
--name="Toit device"
advertiser := device.advertise
advertiser.set_data data
advertiser.start
--name="Toit device"
advertiser.wait_for_done
peripheral.start_advertise data
sleep --ms=10000
peripheral.stop_advertise
```

The name is included in all advertisements, so power and bandwidth is saved by omitting it.
Expand All @@ -43,19 +44,19 @@ To signal what services the device implements, service classes can be added to t
```toit
import ble
BATTERY_SERVICE ::= ble.uuid 0x180F
BATTERY_SERVICE ::= ble.BleUuid "180F"
main:
device := ble.Device.default
adapter := ble.Adapter
peripheral := adapter.peripheral
data := ble.AdvertisementData
--service_classes=[BATTERY_SERVICE]
--name="Toit device"
--service_classes=[BATTERY_SERVICE]
advertiser := device.advertise
advertiser.set_data data
advertiser.start
advertiser.wait_for_done
peripheral.start_advertise data
sleep --ms=10000
peripheral.stop_advertise
```

<Note type="info">
Expand All @@ -70,22 +71,23 @@ The manufacturer data field is a custom payload that can be sent with an adverti

For example, the manufacturer data field can be used to periodically broadcast a sensor value, e.g. the temperature or the GPS location, to make it available to all nearby devices.

In the following example, the values between 0 and 255 are broadcasted incrementally with a new value every 5 seconds.
In the following example, the manufacturer data is simply set to 'toit'.

```toit
import ble
INTERVAL ::= Duration --s=1
BATTERY_SERVICE ::= ble.BleUuid "180F"
main:
device := ble.Device.default
adapter := ble.Adapter
peripheral := adapter.peripheral
advertiser := device.advertise
advertiser.start --interval=INTERVAL
data := ble.AdvertisementData
--name="Toit device"
--service_classes=[BATTERY_SERVICE]
--manufacturer_data=#[0xFF, 0xFF, 't', 'o', 'i', 't']
256.repeat:
data := ble.AdvertisementData
--manufacturer_data=#[0xFF, 0xFF, it]
advertiser.set_data data
sleep INTERVAL
peripheral.start_advertise data
sleep --ms=1000000
peripheral.stop_advertise
```
64 changes: 42 additions & 22 deletions docs/tutorials/ble/client.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,31 @@ In order for a BLE device to establish a connection to a remote device, the devi

```toit
import ble
import uuid
// Find the address with the service.
find_with_service device/ble.Device service/uuid.Uuid -> ble.Address:
device.scan: | remote_device/ble.RemoteDevice |
if remote_device.data.service_classes.contains service:
return remote_device.address
SCAN_DURATION ::= Duration --s=3
find_with_service central/ble.Central service/ble.BleUuid:
central.scan --duration=SCAN_DURATION: | device/ble.RemoteScannedDevice |
if device.data.service_classes.contains service:
return device.address
throw "no device found"
```

With the address available, the connection can be established. In the following example, we use the `find_with_service` function to find a remote device with a battery service and establish a connection to that device.
With the address available, the connection can be established. In the following example, we use the `find_with_service` function to find a remote device with an advertised battery service and establish a connection to that device. Note that the device might also support services that are not explicitly advertised.

```toit
import ble
BATTERY_SERVICE ::= ble.uuid 0x180F
// The battery service is defined in the Bluetooth specification.
// Devices that implement the battery service should (but don't
// need to) advertise it.
// For custom services use a full 128-bit UUID.
BATTERY_SERVICE ::= ble.uuid "180F"
main:
device := ble.Device.default
address := find_with_service device BATTERY_SERVICE
client := device.connect address
adapter := ble.Adapter
central := adapter.central
address := find_with_service central BATTERY_SERVICE
remote_device := central.connect address
```

## Reading service characteristics
Expand All @@ -39,18 +43,34 @@ With the client in place, the battery service can be accessed. The battery servi
```toit
import ble
BATTERY_SERVICE ::= ble.uuid 0x180F
BATTERY_LEVEL ::= ble.uuid 0x2A19
BATTERY_SERVICE ::= ble.BleUuid "180F"
BATTERY_LEVEL ::= ble.BleUuid "2A19"
SCAN_DURATION ::= Duration --s=3
find_with_service central/ble.Central service/ble.BleUuid:
central.scan --duration=SCAN_DURATION: | device/ble.RemoteScannedDevice |
if device.data.service_classes.contains service:
return device.address
throw "no device found"
main:
device := ble.Device.default
adapter := ble.Adapter
central := adapter.central
address := find_with_service device BATTERY_SERVICE
client := device.connect address
service := client.read_service BATTERY_SERVICE
value := service.read_value BATTERY_LEVEL
address := find_with_service central BATTERY_SERVICE
remote_device := central.connect address
// Discover the battery service.
services := remote_device.discover_services [BATTERY_SERVICE]
battery_service/ble.RemoteService := services.first
// The battery level is a single-byte characteristic, between 0 and 100.
// Discover the battery level characteristic.
characteristics := battery_service.discover_characteristics [BATTERY_LEVEL]
battery_level_characteristic/ble.RemoteCharacteristic := characteristics.first
// Read the battery level which is a value between 0 and 100.
value := battery_level_characteristic.read
battery_level := value[0]
print "Battery level of $address: $battery_level"
print "Battery level of $address: $battery_level%"
```
21 changes: 12 additions & 9 deletions docs/tutorials/ble/scanning.mdx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
# Scanning

To start scanning and for nearby BLE devices, simply call `scan` on the `ble.Device`. The provided block will be called for each scan result:
To start scanning for nearby BLE devices, simply call `scan` on the adapter's
central. The provided block will be called for each scan result:

```toit
import ble
main:
device := ble.Device.default
adapter := ble.Adapter
central := adapter.central
device.scan: | remote_device/ble.RemoteDevice |
print "Found $remote_device"
central.scan: | device/ble.RemoteScannedDevice |
print "Found $device"
```

Here the scan will run indefinitely.
Expand All @@ -24,17 +26,18 @@ The following example shows how to scan for 3 seconds for the addresses of remot
```toit
import ble
BATTERY_SERVICE ::= ble.uuid 0x180F
BATTERY_SERVICE ::= ble.BleUuid "180F"
SCAN_DURATION ::= Duration --s=3
main:
device := ble.Device.default
adapter := ble.Adapter
central := adapter.central
addresses := []
device.scan --duration=SCAN_DURATION: | remote_device/ble.RemoteDevice |
if remote_device.data.service_classes.contains BATTERY_SERVICE:
addresses.add remote_device.address
central.scan --duration=SCAN_DURATION: | device/ble.RemoteScannedDevice |
if device.data.service_classes.contains BATTERY_SERVICE:
addresses.add device.address
print addresses
```
Expand Down

0 comments on commit 256d2a9

Please sign in to comment.