From 1a3efc248db75528685d0e07bc58a51251af943d Mon Sep 17 00:00:00 2001 From: Paul de Jong Date: Mon, 11 May 2026 20:44:35 +0200 Subject: [PATCH 1/2] Fix GPS telemetry for video metadata on Osmo Action cameras by setting sattelites to non-zero value. Also set pushing GPS at 10Hz as documented by DJI --- DJIOsmoKit/Location/OsmoLocationManager.swift | 2 +- DJIOsmoKit/Protocol/Commands/GPSPushCommand.swift | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/DJIOsmoKit/Location/OsmoLocationManager.swift b/DJIOsmoKit/Location/OsmoLocationManager.swift index bfb59df..6242a62 100644 --- a/DJIOsmoKit/Location/OsmoLocationManager.swift +++ b/DJIOsmoKit/Location/OsmoLocationManager.swift @@ -60,7 +60,7 @@ public final class OsmoLocationManager: NSObject { isActive = true // 1 Hz push timer on the main run loop - pushTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in + pushTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in Task { @MainActor in self?.pushGPSToAllCameras() } diff --git a/DJIOsmoKit/Protocol/Commands/GPSPushCommand.swift b/DJIOsmoKit/Protocol/Commands/GPSPushCommand.swift index 7bb13ba..4d1300e 100644 --- a/DJIOsmoKit/Protocol/Commands/GPSPushCommand.swift +++ b/DJIOsmoKit/Protocol/Commands/GPSPushCommand.swift @@ -27,7 +27,7 @@ enum GPSPushCommand { // DJI protocol requires timestamps in UTC+8 (China Standard Time). // This matches the reference implementation in dji-sdk/Osmo-GPS-Controller-Demo. // The camera interprets all GPS timestamps as CST regardless of the user's locale. - cal.timeZone = TimeZone(secondsFromGMT: 8 * 3600)! + cal.timeZone = TimeZone(secondsFromGMT: 0 * 3600)! let comps = cal.dateComponents( [.year, .month, .day, .hour, .minute, .second], from: location.timestamp @@ -68,8 +68,15 @@ enum GPSPushCommand { payload.writeLE(vAcc, at: 32) payload.writeLE(hAcc, at: 36) payload.writeLE(sAcc, at: 40) - payload.writeLE(UInt32(0), at: 44) // satellite_number (unavailable from CLLocation) - + payload.writeLE(UInt32(8), at: 44) // fake satellite_number; CLLocation does not provide this + + OsmoLog.location.debug(""" + GPS accuracy: + verticalAccuracy=\(location.verticalAccuracy)m -> vAcc=\(vAcc)mm + horizontalAccuracy=\(location.horizontalAccuracy)m -> hAcc=\(hAcc)mm + speedAccuracy=\(location.speedAccuracy)m/s -> sAcc=\(sAcc)cm/s + """) + return FrameBuilder.build(OutgoingFrame( cmdType: 0x00, // fire-and-forget, no response expected seq: seq, From 09d559604782730f4f705ac2725b9dd128ed93c0 Mon Sep 17 00:00:00 2001 From: Paul de Jong Date: Mon, 11 May 2026 22:21:11 +0200 Subject: [PATCH 2/2] Corrected comments regarnding GPS push rate, and added logic to not send GPS data is no camera is connected --- DJIOsmoKit/Location/OsmoLocationManager.swift | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/DJIOsmoKit/Location/OsmoLocationManager.swift b/DJIOsmoKit/Location/OsmoLocationManager.swift index 6242a62..3872efb 100644 --- a/DJIOsmoKit/Location/OsmoLocationManager.swift +++ b/DJIOsmoKit/Location/OsmoLocationManager.swift @@ -3,7 +3,7 @@ import Foundation import Observation import OSLog -/// Manages Core Location updates and pushes GPS data to all connected cameras at 1 Hz. +/// Manages Core Location updates and pushes GPS data to all connected cameras at 10 Hz. /// /// `OsmoLocationManager` is `@Observable` so SwiftUI views can react to /// `isActive` and `lastLocation` changes. It is `@MainActor` to match @@ -12,7 +12,7 @@ import OSLog /// Usage: /// ```swift /// let locationManager = OsmoLocationManager(cameraManager: .shared) -/// locationManager.start() // begins CL updates + 1 Hz GPS push +/// locationManager.start() // begins CL updates + 10 Hz GPS push /// locationManager.stop() // stops everything /// ``` @Observable @@ -27,6 +27,9 @@ public final class OsmoLocationManager: NSObject { /// The most recent location received from Core Location. public private(set) var lastLocation: CLLocation? + /// Time of the most recent GPS frame pushed to connected cameras. + public private(set) var lastPushAt: Date? + /// Current Core Location authorization status. public var authorizationStatus: CLAuthorizationStatus { locationManager.authorizationStatus @@ -59,7 +62,7 @@ public final class OsmoLocationManager: NSObject { locationManager.startUpdatingLocation() isActive = true - // 1 Hz push timer on the main run loop + // 10 Hz push timer on the main run loop pushTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in Task { @MainActor in self?.pushGPSToAllCameras() @@ -90,8 +93,13 @@ public final class OsmoLocationManager: NSObject { return } let targets = manager.enabledConnectedCameras.count + guard targets > 0 else { + OsmoLog.location.debug("GPS push skipped: no connected cameras") + return + } OsmoLog.location.debug("GPS push → \(targets) camera(s) @ \(String(format: "%.6f", location.coordinate.latitude), privacy: .private),\(String(format: "%.6f", location.coordinate.longitude), privacy: .private)") manager.pushGPS(location) + lastPushAt = Date() } }