gopro / OpenGoPro

An open source interface specification to communicate with a GoPro camera with accompanying demos and tutorials.
https://gopro.github.io/OpenGoPro/
MIT License
679 stars 150 forks source link

Add Swift code sample for multi packet response handling #168

Open rhoenschrat opened 2 years ago

rhoenschrat commented 2 years ago

Some Bluetooth responses are sent in multiple packages. Would be very helpful to see an Swift code example on how to properly deal with such a response.

An additional Swift demo project reading the full camera status would perfectly demonstrate this topic.

tcamise-gpsw commented 2 years ago

Hello. I plan on updating the swift demo at some point in the next several weeks and will implement this.

tcamise-gpsw commented 1 year ago

Quick update...I have not had any time to work on this and do not see it happening any time soon either. It is still in the queue though.

rhoenschrat commented 1 year ago

Meanwhile I'm working on my implementation, but I have issues with the sequence of multi package responses. The sequence is never correct. Some sequence packages do not appear, others are sent multiple times.

2022-12-16 07:35:06.124238+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 21 58 53 00 01 01 01 02 01 02 03 01 00 04 01 FF 06 01 00 08 <
2022-12-16 07:35:06.124837+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 83 00 1E 0A 48 65 72 6F 39 42 6C 61 63 6B 1F 01 00 20 01 00 <
2022-12-16 07:35:06.125498+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 83 00 1E 0A 48 65 72 6F 39 42 6C 61 63 6B 1F 01 00 20 01 00 <
2022-12-16 07:35:06.126657+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 83 00 1E 0A 48 65 72 6F 39 42 6C 61 63 6B 1F 01 00 20 01 00 <
2022-12-16 07:35:06.127108+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 87 00 00 00 05 BF 0B 00 37 01 01 38 01 00 3A 01 00 3B 04 00 <
2022-12-16 07:35:06.127818+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 87 00 00 00 05 BF 0B 00 37 01 01 38 01 00 3A 01 00 3B 04 00 <
2022-12-16 07:35:06.128304+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 87 00 00 00 05 BF 0B 00 37 01 01 38 01 00 3A 01 00 3B 04 00 <
2022-12-16 07:35:06.128756+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 87 00 00 00 05 BF 0B 00 37 01 01 38 01 00 3A 01 00 3B 04 00 <
2022-12-16 07:35:06.129286+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 87 00 00 00 05 BF 0B 00 37 01 01 38 01 00 3A 01 00 3B 04 00 <
2022-12-16 07:35:06.150955+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 88 00 00 00 3C 04 00 00 01 F4 3D 01 02 3E 04 00 00 00 00 3F <
2022-12-16 07:35:06.151451+0100 GoProBluetoothInfo[3300:1263216] Query Response -> Data > 89 01 00 40 04 00 00 0F 53 41 01 00 42 01 64 43 01 64 44 01 <
2022-12-16 07:35:06.153235+0100 GoProBluetoothInfo[3300:1263221] Query Response -> Data > 8A 00 45 01 00 46 01 2D 4A 01 00 4B 01 00 4C 01 01 4D 01 00 <
2022-12-16 07:35:06.153804+0100 GoProBluetoothInfo[3300:1263221] Query Response -> Data > 8C 01 00 58 01 00 59 01 0C 5A 01 00 5B 01 00 5D 04 00 00 00 <
2022-12-16 07:35:06.154399+0100 GoProBluetoothInfo[3300:1263221] Query Response -> Data > 8D 00 5E 04 00 01 00 00 5F 04 00 02 00 00 60 04 00 00 03 E8 <
2022-12-16 07:35:06.155034+0100 GoProBluetoothInfo[3300:1263221] Query Response -> Data > 8D 00 5E 04 00 01 00 00 5F 04 00 02 00 00 60 04 00 00 03 E8 <
2022-12-16 07:35:06.181515+0100 GoProBluetoothInfo[3300:1263222] Query Response -> Data > 8E 61 04 00 00 00 00 62 04 00 00 00 00 63 04 00 00 0D 21 64 <
2022-12-16 07:35:06.182164+0100 GoProBluetoothInfo[3300:1263222] Query Response -> Data > 80 00 6A 01 00 6B 04 FF FF FF FF 6C 01 00 6D 01 00 6E 01 00 <
2022-12-16 07:35:06.182670+0100 GoProBluetoothInfo[3300:1263222] Query Response -> Data > 80 00 6A 01 00 6B 04 FF FF FF FF 6C 01 00 6D 01 00 6E 01 00 <
2022-12-16 07:35:06.183356+0100 GoProBluetoothInfo[3300:1263222] Query Response -> Data > 81 71 01 00 <

I tried it multiple times with my HERO8 and HERO9, but never manage to get a full status update in correct sequence. This is when using the code of the EnableWifiDemo that is using an own DispatcherQueue. I have an old implementation that does not use any DispatcherQueue and/or queue.async commands, and this is working fine. Any idea!?

rhoenschrat commented 1 year ago

@tcamise-gpsw One more finding. The listing above was from my NSLog output. It does not matter if I do the NSLog in my observer callback, or directly in the "didUpdateValueFor" delegate. I did another run with the PackatLogger active at the same time. The log in my app is again giving me the wrong sequence:

2022-12-16 11:00:36.150794+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 21 58 13 00 01 01 01 02 01 04 03 01 00 04 01 FF 06 01 00 08 <
2022-12-16 11:00:36.151269+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 80 01 00 09 01 00 0A 01 00 0B 01 00 0D 04 00 00 00 00 0E 04 <
2022-12-16 11:00:36.153264+0100 GoProBluetoothInfo[3488:1343495] Query Response -> Data > 81 00 00 00 00 11 01 01 13 01 00 14 01 00 15 04 00 00 00 00 <
2022-12-16 11:00:36.153724+0100 GoProBluetoothInfo[3488:1343495] Query Response -> Data > 85 00 00 25 04 00 00 00 06 26 04 00 00 00 00 27 04 00 00 00 <
2022-12-16 11:00:36.154107+0100 GoProBluetoothInfo[3488:1343495] Query Response -> Data > 85 00 00 25 04 00 00 00 06 26 04 00 00 00 00 27 04 00 00 00 <
2022-12-16 11:00:36.154580+0100 GoProBluetoothInfo[3488:1343495] Query Response -> Data > 85 00 00 25 04 00 00 00 06 26 04 00 00 00 00 27 04 00 00 00 <
2022-12-16 11:00:36.155056+0100 GoProBluetoothInfo[3488:1343495] Query Response -> Data > 85 00 00 25 04 00 00 00 06 26 04 00 00 00 00 27 04 00 00 00 <
2022-12-16 11:00:36.181105+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 86 06 29 01 00 2A 01 00 2D 01 00 31 04 00 00 00 00 36 08 00 <
2022-12-16 11:00:36.210741+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 87 00 00 00 05 BF 0B 00 37 01 01 38 01 00 3A 01 00 3B 04 00 <
2022-12-16 11:00:36.211483+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8A 00 45 01 00 46 01 61 4A 01 00 4B 01 00 4C 01 01 4D 01 00 <
2022-12-16 11:00:36.212512+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8C 01 00 58 01 00 59 01 0C 5A 01 00 5B 01 00 5D 04 00 00 00 <
2022-12-16 11:00:36.213192+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8C 01 00 58 01 00 59 01 0C 5A 01 00 5B 01 00 5D 04 00 00 00 <
2022-12-16 11:00:36.213824+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8C 01 00 58 01 00 59 01 0C 5A 01 00 5B 01 00 5D 04 00 00 00 <
2022-12-16 11:00:36.214310+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8C 01 00 58 01 00 59 01 0C 5A 01 00 5B 01 00 5D 04 00 00 00 <
2022-12-16 11:00:36.215882+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8F 04 00 00 00 00 65 01 00 66 01 00 67 01 00 68 01 01 69 01 <
2022-12-16 11:00:36.216503+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8F 04 00 00 00 00 65 01 00 66 01 00 67 01 00 68 01 01 69 01 <
2022-12-16 11:00:36.216940+0100 GoProBluetoothInfo[3488:1343493] Query Response -> Data > 8F 04 00 00 00 00 65 01 00 66 01 00 67 01 00 68 01 01 69 01 <

but the order in the Packet Logger is correct:

Dec 16 11:00:36.060  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 2158 5300 0101 0102 0104 0301 0004 01FF…  
Dec 16 11:00:36.062  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8001 0009 0100 0A01 000B 0100 0D04 0000…  
Dec 16 11:00:36.063  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8100 0000 0011 0101 1301 0014 0100 1504…  
Dec 16 11:00:36.092  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8216 0100 1701 0018 0100 1A01 001B 0100…  
Dec 16 11:00:36.092  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8300 1E0A 4865 726F 3942 6C61 636B 1F01…  
Dec 16 11:00:36.092  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8421 0100 2204 0000 1EA6 2304 0000 2763…  
Dec 16 11:00:36.092  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8500 0025 0400 0000 0626 0400 0000 0027…  
Dec 16 11:00:36.093  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8606 2901 002A 0100 2D01 0031 0400 0000…  
Dec 16 11:00:36.093  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8700 0000 05BF 0B00 3701 0138 0100 3A01…  
Dec 16 11:00:36.095  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8800 0000 3C04 0000 01F4 3D01 023E 0400…  
Dec 16 11:00:36.095  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8901 0040 0400 000F 5341 0100 4201 6443…  
Dec 16 11:00:36.096  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8A00 4501 0046 0161 4A01 004B 0100 4C01…  
Dec 16 11:00:36.121  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8B4E 0101 4F01 0051 0101 5201 0153 0101…  
Dec 16 11:00:36.121  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8C01 0058 0100 5901 0C5A 0100 5B01 005D…  
Dec 16 11:00:36.121  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8D00 5E04 0001 0000 5F04 0002 0000 6004…  
Dec 16 11:00:36.122  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8E61 0400 0000 0062 0400 0000 0063 0400…  
Dec 16 11:00:36.126  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8F04 0000 0000 6501 0066 0100 6701 0068…  
Dec 16 11:00:36.126  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8000 6A01 006B 04FF FFFF FF6C 0100 6D01…  
Dec 16 11:00:36.126  ATT Receive      0x0040  F3:B6:82:F7:2A:B1  Handle Value Notification - Handle:0x003F - Value: 8171 0100

This supports my suspect, that the DispatcherQueue and async setup might cause the issue!?

rhoenschrat commented 1 year ago

I think I found the issue. It's a race condition problem. Looks like the characteristic.value is a reference. And whenever the observer callback is called, it takes the current value of the characteristic instead of the one at the time the task was added to the dispatch queue. I simply made a copy of the characteristic value before dispatching it to the observer callback. Now the sequence of the packages is fine for me.

     func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        if let data = characteristic.value {
            let dispatchData = Data(data)
            queue.async { [weak self] in
                if characteristic.isNotifying {
                    let observer = self?.characteristicObservers[characteristic.uuid]
                    observer?(dispatchData)
                } else {
                    if error != nil {
                        self?.readCharacteristicCallbacks.first?(.failure(error!))
                    } else {
                        self?.readCharacteristicCallbacks.first?(.success(dispatchData))
                    }
                    _ = self?.readCharacteristicCallbacks.removeFirst()
                }
            }
        }
    }