add wifi request ble characteristic
This commit is contained in:
@@ -16,6 +16,8 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
static let serviceUUID = CBUUID(string: "A0B0C0D0-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
static let serviceUUID = CBUUID(string: "A0B0C0D0-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||||
static let feedTxUUID = CBUUID(string: "A0B0C0D1-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
static let feedTxUUID = CBUUID(string: "A0B0C0D1-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||||
static let controlRxUUID = CBUUID(string: "A0B0C0D2-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
static let controlRxUUID = CBUUID(string: "A0B0C0D2-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||||
|
// Read/Notify: 1-byte value (0x00=OFF, 0x01=ON) that requests Glass to enable Wi‑Fi.
|
||||||
|
static let wifiRequestTxUUID = CBUUID(string: "A0B0C0D3-E0F0-4A0B-9C0D-0E0F1A2B3C4D")
|
||||||
private static let restoreIdentifier = "iris.ble.peripheral.v1"
|
private static let restoreIdentifier = "iris.ble.peripheral.v1"
|
||||||
|
|
||||||
@Published private(set) var bluetoothState: CBManagerState = .unknown
|
@Published private(set) var bluetoothState: CBManagerState = .unknown
|
||||||
@@ -30,6 +32,7 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
@Published private(set) var droppedNotifyPackets: Int = 0
|
@Published private(set) var droppedNotifyPackets: Int = 0
|
||||||
@Published private(set) var lastNotifyAt: Date? = nil
|
@Published private(set) var lastNotifyAt: Date? = nil
|
||||||
@Published private(set) var lastDataAt: Date? = nil
|
@Published private(set) var lastDataAt: Date? = nil
|
||||||
|
@Published private(set) var wifiRequested: Bool = false
|
||||||
|
|
||||||
private let queue = DispatchQueue(label: "iris.ble.peripheral.queue")
|
private let queue = DispatchQueue(label: "iris.ble.peripheral.queue")
|
||||||
private lazy var peripheral = CBPeripheralManager(
|
private lazy var peripheral = CBPeripheralManager(
|
||||||
@@ -43,10 +46,13 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
private var service: CBMutableService?
|
private var service: CBMutableService?
|
||||||
private var feedTx: CBMutableCharacteristic?
|
private var feedTx: CBMutableCharacteristic?
|
||||||
private var controlRx: CBMutableCharacteristic?
|
private var controlRx: CBMutableCharacteristic?
|
||||||
|
private var wifiRequestTx: CBMutableCharacteristic?
|
||||||
|
|
||||||
private var subscribedCentralIds = Set<UUID>()
|
private var subscribedCentralIds = Set<UUID>()
|
||||||
private var centralMaxUpdateLength: [UUID: Int] = [:]
|
private var centralMaxUpdateLength: [UUID: Int] = [:]
|
||||||
private var lastReadValue: Data = Data()
|
private var lastReadValue: Data = Data()
|
||||||
|
private var wifiRequestValue: Data = Data([0x00])
|
||||||
|
private var wifiRequestNotifyPending: Bool = false
|
||||||
|
|
||||||
private struct PendingMessage {
|
private struct PendingMessage {
|
||||||
let msgId: UInt32
|
let msgId: UInt32
|
||||||
@@ -101,11 +107,23 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setWifiRequested(_ requested: Bool) {
|
||||||
|
queue.async { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
let newValue = Data([requested ? 0x01 : 0x00])
|
||||||
|
guard newValue != self.wifiRequestValue else { return }
|
||||||
|
self.wifiRequestValue = newValue
|
||||||
|
self.publish { self.wifiRequested = requested }
|
||||||
|
self.flushWifiRequestNotifyIfPossible()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func copyUUIDsToPasteboard() {
|
func copyUUIDsToPasteboard() {
|
||||||
let text = """
|
let text = """
|
||||||
SERVICE_UUID=\(Self.serviceUUID.uuidString)
|
SERVICE_UUID=\(Self.serviceUUID.uuidString)
|
||||||
FEED_TX_UUID=\(Self.feedTxUUID.uuidString)
|
FEED_TX_UUID=\(Self.feedTxUUID.uuidString)
|
||||||
CONTROL_RX_UUID=\(Self.controlRxUUID.uuidString)
|
CONTROL_RX_UUID=\(Self.controlRxUUID.uuidString)
|
||||||
|
WIFI_REQUEST_TX_UUID=\(Self.wifiRequestTxUUID.uuidString)
|
||||||
"""
|
"""
|
||||||
#if canImport(UIKit)
|
#if canImport(UIKit)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
@@ -116,6 +134,18 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
|
|
||||||
private func ensureService() {
|
private func ensureService() {
|
||||||
guard peripheral.state == .poweredOn else { return }
|
guard peripheral.state == .poweredOn else { return }
|
||||||
|
|
||||||
|
if let existingService = service {
|
||||||
|
let hasWifiChar = (existingService.characteristics ?? []).contains { $0.uuid == Self.wifiRequestTxUUID }
|
||||||
|
if wifiRequestTx == nil || !hasWifiChar {
|
||||||
|
stopAdvertising()
|
||||||
|
peripheral.removeAllServices()
|
||||||
|
service = nil
|
||||||
|
feedTx = nil
|
||||||
|
controlRx = nil
|
||||||
|
wifiRequestTx = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
guard service == nil else { return }
|
guard service == nil else { return }
|
||||||
|
|
||||||
let feedTx = CBMutableCharacteristic(
|
let feedTx = CBMutableCharacteristic(
|
||||||
@@ -130,11 +160,18 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
value: nil,
|
value: nil,
|
||||||
permissions: [.writeable]
|
permissions: [.writeable]
|
||||||
)
|
)
|
||||||
|
let wifiRequestTx = CBMutableCharacteristic(
|
||||||
|
type: Self.wifiRequestTxUUID,
|
||||||
|
properties: [.notify, .read],
|
||||||
|
value: nil,
|
||||||
|
permissions: [.readable]
|
||||||
|
)
|
||||||
let service = CBMutableService(type: Self.serviceUUID, primary: true)
|
let service = CBMutableService(type: Self.serviceUUID, primary: true)
|
||||||
service.characteristics = [feedTx, controlRx]
|
service.characteristics = [feedTx, controlRx, wifiRequestTx]
|
||||||
self.service = service
|
self.service = service
|
||||||
self.feedTx = feedTx
|
self.feedTx = feedTx
|
||||||
self.controlRx = controlRx
|
self.controlRx = controlRx
|
||||||
|
self.wifiRequestTx = wifiRequestTx
|
||||||
peripheral.add(service)
|
peripheral.add(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,6 +315,20 @@ final class BlePeripheralManager: NSObject, ObservableObject {
|
|||||||
publishNotifyQueueDepth()
|
publishNotifyQueueDepth()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func flushWifiRequestNotifyIfPossible() {
|
||||||
|
guard let wifiRequestTx else { return }
|
||||||
|
let hasSubscribers = !(wifiRequestTx.subscribedCentrals ?? []).isEmpty
|
||||||
|
guard hasSubscribers else {
|
||||||
|
wifiRequestNotifyPending = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if peripheral.updateValue(wifiRequestValue, for: wifiRequestTx, onSubscribedCentrals: nil) {
|
||||||
|
wifiRequestNotifyPending = false
|
||||||
|
} else {
|
||||||
|
wifiRequestNotifyPending = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func enqueuePendingMessage(_ message: PendingMessage) {
|
private func enqueuePendingMessage(_ message: PendingMessage) {
|
||||||
pendingMessages.append(message)
|
pendingMessages.append(message)
|
||||||
enforceNotifyQueueLimits()
|
enforceNotifyQueueLimits()
|
||||||
@@ -334,6 +385,7 @@ extension BlePeripheralManager: CBPeripheralManagerDelegate {
|
|||||||
self.service = restoredMutableService
|
self.service = restoredMutableService
|
||||||
self.feedTx = characteristics.first(where: { $0.uuid == Self.feedTxUUID }) as? CBMutableCharacteristic
|
self.feedTx = characteristics.first(where: { $0.uuid == Self.feedTxUUID }) as? CBMutableCharacteristic
|
||||||
self.controlRx = characteristics.first(where: { $0.uuid == Self.controlRxUUID }) as? CBMutableCharacteristic
|
self.controlRx = characteristics.first(where: { $0.uuid == Self.controlRxUUID }) as? CBMutableCharacteristic
|
||||||
|
self.wifiRequestTx = characteristics.first(where: { $0.uuid == Self.wifiRequestTxUUID }) as? CBMutableCharacteristic
|
||||||
}
|
}
|
||||||
|
|
||||||
self.publish {
|
self.publish {
|
||||||
@@ -362,6 +414,7 @@ extension BlePeripheralManager: CBPeripheralManagerDelegate {
|
|||||||
self.service = nil
|
self.service = nil
|
||||||
self.feedTx = nil
|
self.feedTx = nil
|
||||||
self.controlRx = nil
|
self.controlRx = nil
|
||||||
|
self.wifiRequestTx = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.ensureService()
|
self.ensureService()
|
||||||
@@ -380,6 +433,12 @@ extension BlePeripheralManager: CBPeripheralManagerDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
|
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
|
||||||
|
if characteristic.uuid == Self.wifiRequestTxUUID {
|
||||||
|
queue.async { [weak self] in
|
||||||
|
self?.flushWifiRequestNotifyIfPossible()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
guard characteristic.uuid == Self.feedTxUUID else { return }
|
guard characteristic.uuid == Self.feedTxUUID else { return }
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
@@ -400,6 +459,9 @@ extension BlePeripheralManager: CBPeripheralManagerDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
|
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
|
||||||
|
if characteristic.uuid == Self.wifiRequestTxUUID {
|
||||||
|
return
|
||||||
|
}
|
||||||
guard characteristic.uuid == Self.feedTxUUID else { return }
|
guard characteristic.uuid == Self.feedTxUUID else { return }
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
@@ -420,17 +482,25 @@ extension BlePeripheralManager: CBPeripheralManagerDelegate {
|
|||||||
func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
|
func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
self?.flushPendingMessages()
|
self?.flushPendingMessages()
|
||||||
|
if let self, self.wifiRequestNotifyPending {
|
||||||
|
self.flushWifiRequestNotifyIfPossible()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
|
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
|
||||||
guard request.characteristic.uuid == Self.feedTxUUID else {
|
|
||||||
peripheral.respond(to: request, withResult: .requestNotSupported)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let maxLen = max(0, request.central.maximumUpdateValueLength)
|
let maxLen = max(0, request.central.maximumUpdateValueLength)
|
||||||
|
if request.characteristic.uuid == Self.feedTxUUID {
|
||||||
request.value = maxLen > 0 ? lastReadValue.prefix(maxLen) : lastReadValue
|
request.value = maxLen > 0 ? lastReadValue.prefix(maxLen) : lastReadValue
|
||||||
peripheral.respond(to: request, withResult: .success)
|
peripheral.respond(to: request, withResult: .success)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if request.characteristic.uuid == Self.wifiRequestTxUUID {
|
||||||
|
request.value = maxLen > 0 ? wifiRequestValue.prefix(maxLen) : wifiRequestValue
|
||||||
|
peripheral.respond(to: request, withResult: .success)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
peripheral.respond(to: request, withResult: .requestNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
|
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
|
||||||
|
|||||||
@@ -34,6 +34,16 @@ struct BleStatusView: View {
|
|||||||
ble.start()
|
ble.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: Binding(get: { ble.wifiRequested }, set: { ble.setWifiRequested($0) })) {
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text("Request Wi-Fi (Glass)")
|
||||||
|
.font(.headline)
|
||||||
|
Text(ble.wifiRequested ? "On" : "Off")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("Connection")
|
Text("Connection")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
@@ -86,7 +96,7 @@ struct BleStatusView: View {
|
|||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("UUIDs")
|
Text("UUIDs")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
Text("Service: \(BlePeripheralManager.serviceUUID.uuidString)\nFEED_TX: \(BlePeripheralManager.feedTxUUID.uuidString)\nCONTROL_RX: \(BlePeripheralManager.controlRxUUID.uuidString)")
|
Text("Service: \(BlePeripheralManager.serviceUUID.uuidString)\nFEED_TX: \(BlePeripheralManager.feedTxUUID.uuidString)\nCONTROL_RX: \(BlePeripheralManager.controlRxUUID.uuidString)\nWIFI_REQUEST_TX: \(BlePeripheralManager.wifiRequestTxUUID.uuidString)")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.textSelection(.enabled)
|
.textSelection(.enabled)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public final class BleCentralClient {
|
|||||||
void onConnected();
|
void onConnected();
|
||||||
void onPing();
|
void onPing();
|
||||||
void onFeedJson(String json);
|
void onFeedJson(String json);
|
||||||
|
void onWifiRequest(boolean requested);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final UUID CCCD_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
|
private static final UUID CCCD_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
|
||||||
@@ -46,6 +47,7 @@ public final class BleCentralClient {
|
|||||||
private boolean scanning = false;
|
private boolean scanning = false;
|
||||||
private BluetoothDevice lastDevice = null;
|
private BluetoothDevice lastDevice = null;
|
||||||
private BluetoothGatt gatt = null;
|
private BluetoothGatt gatt = null;
|
||||||
|
private BluetoothGattDescriptor pendingWifiCccd = null;
|
||||||
private boolean subscribed = false;
|
private boolean subscribed = false;
|
||||||
|
|
||||||
private long lastNotificationAtMs = 0L;
|
private long lastNotificationAtMs = 0L;
|
||||||
@@ -265,6 +267,7 @@ public final class BleCentralClient {
|
|||||||
if (scanning) return;
|
if (scanning) return;
|
||||||
|
|
||||||
subscribed = false;
|
subscribed = false;
|
||||||
|
pendingWifiCccd = null;
|
||||||
stopLivenessCheck();
|
stopLivenessCheck();
|
||||||
lastNotificationAtMs = 0L;
|
lastNotificationAtMs = 0L;
|
||||||
lastPingAtMs = 0L;
|
lastPingAtMs = 0L;
|
||||||
@@ -347,6 +350,24 @@ public final class BleCentralClient {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BluetoothGattCharacteristic wifiRequestTx = service.getCharacteristic(Constants.WIFI_REQUEST_TX_UUID);
|
||||||
|
if (wifiRequestTx != null) {
|
||||||
|
Log.i(Constants.TAG_BLE, "Found characteristic " + Constants.WIFI_REQUEST_TX_UUID_STR + " (WIFI_REQUEST_TX)");
|
||||||
|
Log.i(Constants.TAG_BLE, "Enabling notifications for WIFI_REQUEST_TX");
|
||||||
|
boolean wifiNotifOk = gatt.setCharacteristicNotification(wifiRequestTx, true);
|
||||||
|
Log.i(Constants.TAG_BLE, "setCharacteristicNotification(WIFI_REQUEST_TX)=" + wifiNotifOk);
|
||||||
|
|
||||||
|
BluetoothGattDescriptor wifiCccd = wifiRequestTx.getDescriptor(CCCD_UUID);
|
||||||
|
if (wifiCccd == null) {
|
||||||
|
Log.w(Constants.TAG_BLE, "Missing WIFI_REQUEST_TX CCCD (0x2902)");
|
||||||
|
} else {
|
||||||
|
wifiCccd.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
||||||
|
pendingWifiCccd = wifiCccd;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(Constants.TAG_BLE, "Missing characteristic " + Constants.WIFI_REQUEST_TX_UUID_STR + " (WIFI_REQUEST_TX)");
|
||||||
|
}
|
||||||
|
|
||||||
BluetoothGattCharacteristic feedTx = service.getCharacteristic(Constants.FEED_TX_UUID);
|
BluetoothGattCharacteristic feedTx = service.getCharacteristic(Constants.FEED_TX_UUID);
|
||||||
if (feedTx == null) {
|
if (feedTx == null) {
|
||||||
closeGattInternal();
|
closeGattInternal();
|
||||||
@@ -358,7 +379,7 @@ public final class BleCentralClient {
|
|||||||
Log.i(Constants.TAG_BLE, "Enabling notifications for FEED_TX");
|
Log.i(Constants.TAG_BLE, "Enabling notifications for FEED_TX");
|
||||||
|
|
||||||
boolean notifOk = gatt.setCharacteristicNotification(feedTx, true);
|
boolean notifOk = gatt.setCharacteristicNotification(feedTx, true);
|
||||||
Log.i(Constants.TAG_BLE, "setCharacteristicNotification=" + notifOk);
|
Log.i(Constants.TAG_BLE, "setCharacteristicNotification(FEED_TX)=" + notifOk);
|
||||||
|
|
||||||
BluetoothGattDescriptor cccd = feedTx.getDescriptor(CCCD_UUID);
|
BluetoothGattDescriptor cccd = feedTx.getDescriptor(CCCD_UUID);
|
||||||
if (cccd == null) {
|
if (cccd == null) {
|
||||||
@@ -368,7 +389,7 @@ public final class BleCentralClient {
|
|||||||
}
|
}
|
||||||
cccd.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
cccd.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
||||||
boolean writeOk = gatt.writeDescriptor(cccd);
|
boolean writeOk = gatt.writeDescriptor(cccd);
|
||||||
Log.i(Constants.TAG_BLE, "writeDescriptor(CCCD)=" + writeOk);
|
Log.i(Constants.TAG_BLE, "writeDescriptor(FEED CCCD)=" + writeOk);
|
||||||
if (!writeOk) {
|
if (!writeOk) {
|
||||||
closeGattInternal();
|
closeGattInternal();
|
||||||
scheduleReconnect("CCCD write failed to start");
|
scheduleReconnect("CCCD write failed to start");
|
||||||
@@ -380,21 +401,56 @@ public final class BleCentralClient {
|
|||||||
if (descriptor == null) return;
|
if (descriptor == null) return;
|
||||||
if (!CCCD_UUID.equals(descriptor.getUuid())) return;
|
if (!CCCD_UUID.equals(descriptor.getUuid())) return;
|
||||||
|
|
||||||
Log.i(Constants.TAG_BLE, "onDescriptorWrite CCCD status=" + status);
|
BluetoothGattCharacteristic ch = descriptor.getCharacteristic();
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
UUID chUuid = ch != null ? ch.getUuid() : null;
|
||||||
|
Log.i(Constants.TAG_BLE, "onDescriptorWrite CCCD status=" + status + " char=" + chUuid);
|
||||||
|
|
||||||
|
if (status != BluetoothGatt.GATT_SUCCESS) {
|
||||||
|
if (Constants.FEED_TX_UUID.equals(chUuid)) {
|
||||||
|
closeGattInternal();
|
||||||
|
scheduleReconnect("CCCD write failed: " + status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Constants.WIFI_REQUEST_TX_UUID.equals(chUuid)) {
|
||||||
|
Log.w(Constants.TAG_BLE, "WIFI_REQUEST_TX CCCD write failed: " + status);
|
||||||
|
pendingWifiCccd = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeGattInternal();
|
||||||
|
scheduleReconnect("CCCD write failed: " + status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Constants.FEED_TX_UUID.equals(chUuid)) {
|
||||||
subscribed = true;
|
subscribed = true;
|
||||||
lastNotificationAtMs = System.currentTimeMillis();
|
lastNotificationAtMs = System.currentTimeMillis();
|
||||||
lastPingAtMs = 0L;
|
lastPingAtMs = 0L;
|
||||||
startLivenessCheck();
|
startLivenessCheck();
|
||||||
if (callback != null) callback.onStatus("Connected", null, true);
|
if (callback != null) callback.onStatus("Connected", null, true);
|
||||||
} else {
|
|
||||||
closeGattInternal();
|
if (pendingWifiCccd != null) {
|
||||||
scheduleReconnect("CCCD write failed: " + status);
|
boolean wifiWriteOk = gatt.writeDescriptor(pendingWifiCccd);
|
||||||
|
Log.i(Constants.TAG_BLE, "writeDescriptor(WIFI CCCD)=" + wifiWriteOk);
|
||||||
|
if (!wifiWriteOk) {
|
||||||
|
Log.w(Constants.TAG_BLE, "WIFI_REQUEST_TX CCCD write failed to start");
|
||||||
|
pendingWifiCccd = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Constants.WIFI_REQUEST_TX_UUID.equals(chUuid)) {
|
||||||
|
Log.i(Constants.TAG_BLE, "Subscribed to WIFI_REQUEST_TX");
|
||||||
|
pendingWifiCccd = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCharacteristicChanged(UUID uuid, byte[] value) {
|
private void handleCharacteristicChanged(UUID uuid, byte[] value) {
|
||||||
if (!Constants.FEED_TX_UUID.equals(uuid)) return;
|
if (Constants.WIFI_REQUEST_TX_UUID.equals(uuid)) {
|
||||||
|
boolean requested = value != null && value.length > 0 && (value[0] & 0xFF) != 0;
|
||||||
|
Log.i(Constants.TAG_BLE, "WIFI_REQUEST_TX notify=" + requested + " raw=" + hexPrefix(value, 1));
|
||||||
|
if (callback != null) callback.onWifiRequest(requested);
|
||||||
|
} else if (Constants.FEED_TX_UUID.equals(uuid)) {
|
||||||
lastNotificationAtMs = System.currentTimeMillis();
|
lastNotificationAtMs = System.currentTimeMillis();
|
||||||
|
|
||||||
FeedReassembler.Result result = reassembler.onNotification(value, lastNotificationAtMs);
|
FeedReassembler.Result result = reassembler.onNotification(value, lastNotificationAtMs);
|
||||||
@@ -415,16 +471,11 @@ public final class BleCentralClient {
|
|||||||
}
|
}
|
||||||
Log.d(Constants.TAG_FEED, "Unparsed notify len=" + (value != null ? value.length : 0) + hint + " hex=" + hexPrefix(value, 16));
|
Log.d(Constants.TAG_FEED, "Unparsed notify len=" + (value != null ? value.length : 0) + hint + " hex=" + hexPrefix(value, 16));
|
||||||
}
|
}
|
||||||
return;
|
} else if (result.isPing) {
|
||||||
}
|
|
||||||
|
|
||||||
if (result.isPing) {
|
|
||||||
Log.d(Constants.TAG_FEED, "PING");
|
Log.d(Constants.TAG_FEED, "PING");
|
||||||
lastPingAtMs = lastNotificationAtMs;
|
lastPingAtMs = lastNotificationAtMs;
|
||||||
if (callback != null) callback.onPing();
|
if (callback != null) callback.onPing();
|
||||||
return;
|
} else if (result.jsonOrNull != null) {
|
||||||
}
|
|
||||||
if (result.jsonOrNull != null) {
|
|
||||||
Log.i(Constants.TAG_FEED, "Reassembled JSON (" + result.jsonOrNull.length() + " bytes)");
|
Log.i(Constants.TAG_FEED, "Reassembled JSON (" + result.jsonOrNull.length() + " bytes)");
|
||||||
Log.i(Constants.TAG_FEED, "RAW_JSON_BEGIN");
|
Log.i(Constants.TAG_FEED, "RAW_JSON_BEGIN");
|
||||||
logLarge(Constants.TAG_FEED, result.jsonOrNull);
|
logLarge(Constants.TAG_FEED, result.jsonOrNull);
|
||||||
@@ -432,9 +483,11 @@ public final class BleCentralClient {
|
|||||||
if (callback != null) callback.onFeedJson(result.jsonOrNull);
|
if (callback != null) callback.onFeedJson(result.jsonOrNull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void closeGattInternal() {
|
private void closeGattInternal() {
|
||||||
subscribed = false;
|
subscribed = false;
|
||||||
|
pendingWifiCccd = null;
|
||||||
stopLivenessCheck();
|
stopLivenessCheck();
|
||||||
handler.removeCallbacks(connectTimeoutRunnable);
|
handler.removeCallbacks(connectTimeoutRunnable);
|
||||||
if (gatt != null) {
|
if (gatt != null) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package sh.nym.irisglass;
|
package sh.nym.irisglass;
|
||||||
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
@@ -92,6 +94,11 @@ public final class BleLinkService extends Service implements BleCentralClient.Ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWifiRequest(boolean requested) {
|
||||||
|
setWifiEnabled(requested);
|
||||||
|
}
|
||||||
|
|
||||||
private void maybeNudgeWinnerChanged(FeedEnvelope env) {
|
private void maybeNudgeWinnerChanged(FeedEnvelope env) {
|
||||||
if (env == null) return;
|
if (env == null) return;
|
||||||
|
|
||||||
@@ -122,4 +129,11 @@ public final class BleLinkService extends Service implements BleCentralClient.Ca
|
|||||||
i.putExtra(Constants.EXTRA_WINNER_ID, winnerId);
|
i.putExtra(Constants.EXTRA_WINNER_ID, winnerId);
|
||||||
startService(i);
|
startService(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setWifiEnabled(boolean enabled) {
|
||||||
|
WifiManager wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
if (wifiManager != null) {
|
||||||
|
wifiManager.setWifiEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ public final class Constants {
|
|||||||
public static final String SERVICE_UUID_STR = "A0B0C0D0-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
public static final String SERVICE_UUID_STR = "A0B0C0D0-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
||||||
public static final String FEED_TX_UUID_STR = "A0B0C0D1-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
public static final String FEED_TX_UUID_STR = "A0B0C0D1-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
||||||
public static final String CONTROL_RX_UUID_STR = "A0B0C0D2-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
public static final String CONTROL_RX_UUID_STR = "A0B0C0D2-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
||||||
|
public static final String WIFI_REQUEST_TX_UUID_STR = "A0B0C0D3-E0F0-4A0B-9C0D-0E0F1A2B3C4D";
|
||||||
|
|
||||||
public static final UUID SERVICE_UUID = UUID.fromString(SERVICE_UUID_STR);
|
public static final UUID SERVICE_UUID = UUID.fromString(SERVICE_UUID_STR);
|
||||||
public static final UUID FEED_TX_UUID = UUID.fromString(FEED_TX_UUID_STR);
|
public static final UUID FEED_TX_UUID = UUID.fromString(FEED_TX_UUID_STR);
|
||||||
public static final UUID CONTROL_RX_UUID = UUID.fromString(CONTROL_RX_UUID_STR);
|
public static final UUID CONTROL_RX_UUID = UUID.fromString(CONTROL_RX_UUID_STR);
|
||||||
|
public static final UUID WIFI_REQUEST_TX_UUID = UUID.fromString(WIFI_REQUEST_TX_UUID_STR);
|
||||||
|
|
||||||
public static final String PERIPHERAL_NAME_HINT = "Aris";
|
public static final String PERIPHERAL_NAME_HINT = "Aris";
|
||||||
public static final String LEGACY_PERIPHERAL_NAME_HINT = "GlassNow";
|
public static final String LEGACY_PERIPHERAL_NAME_HINT = "GlassNow";
|
||||||
|
|||||||
Reference in New Issue
Block a user