Reputation: 564
I've started using RxBluetoothKit with good results for a peripheral we are developing. It works quite well and I am able to perform the transactions we need.
I have a design pattern question. We have a couple of commands where our API includes multi-step commands. For example, the App writes a command start code, the Peripheral confirms with an ACK, then the App writes the command, waits for an ACK, issues another command, waits for another ACK, etc. This can go on until the App issues a command stop code, which will be at some indeterminate point in the future — when the user tells the app to stop, for example.
Is there an appropriate coding idiom or pattern in the Rx world for accomplishing this? I am new to Rx in general, and am curious what might be the simplest, cleanest implementation of something of this sort.
Thanks.
Upvotes: 0
Views: 569
Reputation: 51
Details as always depend on your very specific use case. I like to think about Rx as stream based building blocks which needs to be connected to model your business logic.
There is one example how it may look like:
enum DeviceService: String, ServiceIdentifier {
case myService = "ffff"
var uuid: CBUUID {
return CBUUID(string: self.rawValue)
}
}
enum DeviceCharacteristic: String, CharacteristicIdentifier {
case startCharacteristic = "0001"
case stopCharacteristic = "0002"
case ackCharacteristic = "ffff"
case command1Characteristic = "0003"
case command2Characteristic = "0004"
var uuid: CBUUID {
return CBUUID(string: self.rawValue)
}
var service: ServiceIdentifier {
return DeviceService.myService
}
}
let peripheral : Peripheral? = nil
// Some internal command 1
let command1 = peripheral!.writeValue(Data(bytes: [0xff, 0xfe]),
for: DeviceCharacteristic.command1Characteristic,
type: .withResponse)
// Some internal command 2
let command2 = peripheral!.writeValue(Data(bytes: [0xdd, 0xee]),
for: DeviceCharacteristic.command2Characteristic,
type: .withResponse)
func batchCommands(commands: [Observable<Characteristic>]) -> Observable<Characteristic> {
let commandsWithAck = commands.map { command in
return command.flatMap { characteristic in
return peripheral!.monitorValueUpdate(for: DeviceCharacteristic.ackCharacteristic).take(1)
}
}
let start = peripheral!.writeValue(Data(bytes: [0x01]),
for: DeviceCharacteristic.startCharacteristic,
type: .withResponse)
let stop = peripheral!.writeValue(Data(bytes: [0x00]),
for: DeviceCharacteristic.startCharacteristic,
type: .withResponse)
return start.concat(Observable.concat(commandsWithAck)).concat(stop)
}
// Call it:
let subscription = batchCommands(commands: [command1, command2])
.subscribe(onNext: nil, onError: nil, onCompleted: nil, onDisposed: nil)
There, start
and stop
observables can be changed to monitor user's behaviour and emit items when actual start/stop action should took place.
Upvotes: 1