feat: Merge SaltyTag BLE — GPS/IMU streaming to UWB tag, anchor display, UWB position authority #5
@ -68,14 +68,21 @@ final class BLEManager: NSObject, ObservableObject {
|
|||||||
func sendGPS(_ data: Data) {
|
func sendGPS(_ data: Data) {
|
||||||
guard gpsStreamEnabled, isConnected,
|
guard gpsStreamEnabled, isConnected,
|
||||||
let p = peripheral, let c = gpsChar else { return }
|
let p = peripheral, let c = gpsChar else { return }
|
||||||
p.writeValue(data, for: c, type: .withoutResponse)
|
// Use writeWithoutResponse if the characteristic supports it (lower latency,
|
||||||
|
// no ACK overhead). Fall back to write-with-response if the firmware only
|
||||||
|
// advertises PROPERTY_WRITE (0x08) — e.g. NimBLE default without WRITE_NR.
|
||||||
|
let writeType: CBCharacteristicWriteType =
|
||||||
|
c.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
|
||||||
|
p.writeValue(data, for: c, type: writeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a pre-built IMU packet to the tag. Call at 10 Hz.
|
/// Write a pre-built IMU packet to the tag. Call at 10 Hz.
|
||||||
func sendIMU(_ data: Data) {
|
func sendIMU(_ data: Data) {
|
||||||
guard imuStreamEnabled, isConnected,
|
guard imuStreamEnabled, isConnected,
|
||||||
let p = peripheral, let c = imuChar else { return }
|
let p = peripheral, let c = imuChar else { return }
|
||||||
p.writeValue(data, for: c, type: .withoutResponse)
|
let writeType: CBCharacteristicWriteType =
|
||||||
|
c.properties.contains(.writeWithoutResponse) ? .withoutResponse : .withResponse
|
||||||
|
p.writeValue(data, for: c, type: writeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Internal helpers
|
// MARK: - Internal helpers
|
||||||
|
|||||||
@ -164,25 +164,3 @@ private extension Data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Safe integer clamping
|
|
||||||
|
|
||||||
private extension Int16 {
|
|
||||||
init(clamping value: Int64) {
|
|
||||||
self = Int16(max(Int64(Int16.min), min(Int64(Int16.max), value)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private extension Int32 {
|
|
||||||
init(clamping value: Int64) {
|
|
||||||
self = Int32(max(Int64(Int32.min), min(Int64(Int32.max), value)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private extension UInt16 {
|
|
||||||
init(clamping value: Int64) {
|
|
||||||
self = UInt16(max(Int64(0), min(Int64(UInt16.max), value)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private extension UInt8 {
|
|
||||||
init(clamping value: Int64) {
|
|
||||||
self = UInt8(max(Int64(0), min(Int64(UInt8.max), value)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -70,7 +70,7 @@ struct BLEStatusView: View {
|
|||||||
|
|
||||||
private var streamingSection: some View {
|
private var streamingSection: some View {
|
||||||
Section("Data Streaming") {
|
Section("Data Streaming") {
|
||||||
Toggle(isOn: $sensor.ble.gpsStreamEnabled) {
|
Toggle(isOn: Binding(get: { ble.gpsStreamEnabled }, set: { ble.gpsStreamEnabled = $0 })) {
|
||||||
Label {
|
Label {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
Text("GPS → Tag")
|
Text("GPS → Tag")
|
||||||
@ -82,7 +82,7 @@ struct BLEStatusView: View {
|
|||||||
.foregroundStyle(.blue)
|
.foregroundStyle(.blue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Toggle(isOn: $sensor.ble.imuStreamEnabled) {
|
Toggle(isOn: Binding(get: { ble.imuStreamEnabled }, set: { ble.imuStreamEnabled = $0 })) {
|
||||||
Label {
|
Label {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
Text("IMU → Tag")
|
Text("IMU → Tag")
|
||||||
|
|||||||
@ -229,7 +229,7 @@ final class SensorManager: NSObject, ObservableObject {
|
|||||||
locationManager.startUpdatingLocation()
|
locationManager.startUpdatingLocation()
|
||||||
locationManager.startUpdatingHeading()
|
locationManager.startUpdatingHeading()
|
||||||
if !motionManager.isDeviceMotionActive { startIMU() }
|
if !motionManager.isDeviceMotionActive { startIMU() }
|
||||||
if !altimeter.isRelativeAltitudeAvailable() == false { startBarometer() }
|
if CMAltimeter.isRelativeAltitudeAvailable() { startBarometer() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private func stopSensors() {
|
private func stopSensors() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user