mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Finish refactoring Packet handling out of the blue manager
Protobufs update
This commit is contained in:
parent
d3fd9ead54
commit
82adcbd8de
6 changed files with 399 additions and 685 deletions
|
|
@ -460,7 +460,7 @@
|
|||
TargetAttributes = {
|
||||
DDC2E15326CE248E0042C5E4 = {
|
||||
CreatedOnToolsVersion = 12.5.1;
|
||||
LastSwiftMigration = 1320;
|
||||
LastSwiftMigration = 1340;
|
||||
};
|
||||
DDC2E16926CE248F0042C5E4 = {
|
||||
CreatedOnToolsVersion = 12.5.1;
|
||||
|
|
@ -805,6 +805,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "MeshtasticClient/Compression/MeshtasticClient-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
|
||||
// MARK: Discover Characteristics Event
|
||||
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
||||
|
||||
if let e = error {
|
||||
|
||||
if meshLoggingEnabled { MeshLogger.log("🚫 BLE didDiscoverCharacteristicsFor error by \(peripheral.name ?? "Unknown") \(e)") }
|
||||
|
|
@ -333,8 +334,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
default:
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
|
@ -386,7 +386,41 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
switch decodedInfo.packet.decoded.portnum {
|
||||
|
||||
case .unknownApp:
|
||||
print("MyInfo or NodeInfo")
|
||||
if decodedInfo.myInfo.myNodeNum != 0 {
|
||||
|
||||
let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, meshLogging: meshLoggingEnabled, context: context!)
|
||||
|
||||
if myInfo != nil {
|
||||
|
||||
self.connectedPeripheral.bitrate = myInfo!.bitrate
|
||||
self.connectedPeripheral.num = myInfo!.myNodeNum
|
||||
lastConnnectionVersion = myInfo?.firmwareVersion ?? myInfo!.firmwareVersion ?? "Unknown"
|
||||
self.connectedPeripheral.firmwareVersion = myInfo!.firmwareVersion ?? "Unknown"
|
||||
self.connectedPeripheral.name = myInfo!.bleName ?? "Unknown"
|
||||
}
|
||||
|
||||
} else if decodedInfo.nodeInfo.num != 0 {
|
||||
|
||||
let nodeInfo = nodeInfoPacket(nodeInfo: decodedInfo.nodeInfo, meshLogging: meshLoggingEnabled, context: context!)
|
||||
|
||||
if nodeInfo != nil {
|
||||
|
||||
self.connectedPeripheral.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization
|
||||
self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
|
||||
|
||||
if self.connectedPeripheral != nil && self.connectedPeripheral.num == nodeInfo!.num {
|
||||
|
||||
if nodeInfo!.user != nil {
|
||||
|
||||
connectedPeripheral.name = nodeInfo!.user!.longName ?? "Unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Unknown App UNHANDLED \(try! decodedInfo.packet.jsonString())") }
|
||||
}
|
||||
case .textMessageApp:
|
||||
textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!)
|
||||
case .remoteHardwareApp:
|
||||
|
|
@ -394,7 +428,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
case .positionApp:
|
||||
positionPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!)
|
||||
case .nodeinfoApp:
|
||||
nodeInfoPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!)
|
||||
nodeInfoAppPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!)
|
||||
case .routingApp:
|
||||
routingPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!)
|
||||
case .adminApp:
|
||||
|
|
@ -425,288 +459,40 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
print("MAX PORT NUM OF 511")
|
||||
}
|
||||
|
||||
// MARK: Incoming MyInfo Packet
|
||||
if decodedInfo.myInfo.myNodeNum != 0 {
|
||||
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(decodedInfo.myInfo.myNodeNum))
|
||||
|
||||
do {
|
||||
let fetchedMyInfo = try context?.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
// Not Found Insert
|
||||
if fetchedMyInfo.isEmpty {
|
||||
let myInfo = MyInfoEntity(context: context!)
|
||||
myInfo.myNodeNum = Int64(decodedInfo.myInfo.myNodeNum)
|
||||
myInfo.hasGps = decodedInfo.myInfo.hasGps_p
|
||||
myInfo.bitrate = decodedInfo.myInfo.bitrate
|
||||
self.connectedPeripheral.bitrate = myInfo.bitrate
|
||||
|
||||
// Swift does strings weird, this does work to get the version without the github hash
|
||||
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")
|
||||
var version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.myInfo.firmwareVersion))]
|
||||
version = version.dropLast()
|
||||
myInfo.firmwareVersion = String(version)
|
||||
lastConnnectionVersion = String(version)
|
||||
// MARK: Check for an All / Broadcast User
|
||||
let fetchBCUserRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
|
||||
fetchBCUserRequest.predicate = NSPredicate(format: "num == %lld", Int64(broadcastNodeNum))
|
||||
|
||||
do {
|
||||
let fetchedUser = try context?.fetch(fetchBCUserRequest) as! [UserEntity]
|
||||
|
||||
myInfo.messageTimeoutMsec = Int32(bitPattern: decodedInfo.myInfo.messageTimeoutMsec)
|
||||
myInfo.minAppVersion = Int32(bitPattern: decodedInfo.myInfo.minAppVersion)
|
||||
myInfo.maxChannels = Int32(bitPattern: decodedInfo.myInfo.maxChannels)
|
||||
self.connectedPeripheral.num = myInfo.myNodeNum
|
||||
self.connectedPeripheral.firmwareVersion = myInfo.firmwareVersion ?? "Unknown"
|
||||
self.connectedPeripheral.name = myInfo.bleName ?? "Unknown"
|
||||
|
||||
let fetchBCUserRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
|
||||
fetchBCUserRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.myInfo.myNodeNum))
|
||||
|
||||
do {
|
||||
let fetchedUser = try context?.fetch(fetchBCUserRequest) as! [UserEntity]
|
||||
|
||||
if fetchedUser.isEmpty {
|
||||
// Save the broadcast user if it does not exist
|
||||
let bcu: UserEntity = UserEntity(context: context!)
|
||||
bcu.shortName = "ALL"
|
||||
bcu.longName = "All - Broadcast"
|
||||
bcu.hwModel = "UNSET"
|
||||
bcu.num = Int64(broadcastNodeNum)
|
||||
bcu.userId = "BROADCASTNODE"
|
||||
print("💾 Saved the All - Broadcast User")
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
print("💥 Error Saving the All - Broadcast User")
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fetchedMyInfo[0].myNodeNum = Int64(decodedInfo.myInfo.myNodeNum)
|
||||
fetchedMyInfo[0].hasGps = decodedInfo.myInfo.hasGps_p
|
||||
fetchedMyInfo[0].bitrate = decodedInfo.myInfo.bitrate
|
||||
|
||||
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")//.lastIndex(of: ".", offsetBy: -1)
|
||||
var version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset:6, in: decodedInfo.myInfo.firmwareVersion))]
|
||||
version = version.dropLast()
|
||||
fetchedMyInfo[0].firmwareVersion = String(version)
|
||||
lastConnnectionVersion = String(version)
|
||||
fetchedMyInfo[0].messageTimeoutMsec = Int32(bitPattern: decodedInfo.myInfo.messageTimeoutMsec)
|
||||
fetchedMyInfo[0].minAppVersion = Int32(bitPattern: decodedInfo.myInfo.minAppVersion)
|
||||
fetchedMyInfo[0].maxChannels = Int32(bitPattern: decodedInfo.myInfo.maxChannels)
|
||||
|
||||
self.connectedPeripheral.num = fetchedMyInfo[0].myNodeNum
|
||||
self.connectedPeripheral.firmwareVersion = fetchedMyInfo[0].firmwareVersion ?? "Unknown"
|
||||
self.connectedPeripheral.name = fetchedMyInfo[0].bleName ?? "Unknown"
|
||||
self.connectedPeripheral.bitrate = fetchedMyInfo[0].bitrate
|
||||
|
||||
}
|
||||
do {
|
||||
|
||||
try context!.save()
|
||||
if meshLoggingEnabled { MeshLogger.log("💾 Saved a myInfo for \(peripheral.name ?? String(decodedInfo.myInfo.myNodeNum))") }
|
||||
|
||||
} catch {
|
||||
|
||||
context!.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving Core Data MyInfoEntity: \(nsError)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
print("💥 Fetch MyInfo Error")
|
||||
if fetchedUser.isEmpty {
|
||||
// Save the broadcast user if it does not exist
|
||||
let bcu: UserEntity = UserEntity(context: context!)
|
||||
bcu.shortName = "ALL"
|
||||
bcu.longName = "All - Broadcast"
|
||||
bcu.hwModel = "UNSET"
|
||||
bcu.num = Int64(broadcastNodeNum)
|
||||
bcu.userId = "BROADCASTNODE"
|
||||
print("💾 Saved the All - Broadcast User")
|
||||
}
|
||||
|
||||
// MARK: Share Location Position Update Timer
|
||||
// Use context to pass the radio name with the timer
|
||||
// Use a RunLoop to prevent the timer from running on the main UI thread
|
||||
if userSettings?.provideLocation ?? false {
|
||||
|
||||
if self.positionTimer != nil {
|
||||
self.positionTimer!.invalidate()
|
||||
}
|
||||
let context = ["name": "@\(peripheral.name ?? "Unknown")"]
|
||||
self.positionTimer = Timer.scheduledTimer(timeInterval: TimeInterval((userSettings?.provideLocationInterval ?? 900)), target: self, selector: #selector(positionTimerFired), userInfo: context, repeats: true)
|
||||
RunLoop.current.add(self.positionTimer!, forMode: .common)
|
||||
}
|
||||
} catch {
|
||||
|
||||
print("💥 Error Saving the All - Broadcast User")
|
||||
}
|
||||
|
||||
// MARK: Incoming Node Info Packet
|
||||
if decodedInfo.nodeInfo.num != 0 {
|
||||
|
||||
let fetchNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.nodeInfo.num))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedNode = try context?.fetch(fetchNodeRequest) as! [NodeInfoEntity]
|
||||
// Not Found Insert
|
||||
if fetchedNode.isEmpty && decodedInfo.nodeInfo.hasUser {
|
||||
|
||||
let newNode = NodeInfoEntity(context: context!)
|
||||
newNode.id = Int64(decodedInfo.nodeInfo.num)
|
||||
newNode.num = Int64(decodedInfo.nodeInfo.num)
|
||||
|
||||
if decodedInfo.nodeInfo.hasDeviceMetrics {
|
||||
|
||||
let telemetry = TelemetryEntity(context: context!)
|
||||
|
||||
telemetry.batteryLevel = Int32(decodedInfo.nodeInfo.deviceMetrics.batteryLevel)
|
||||
telemetry.voltage = decodedInfo.nodeInfo.deviceMetrics.voltage
|
||||
telemetry.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization
|
||||
self.connectedPeripheral.channelUtilization = telemetry.channelUtilization
|
||||
telemetry.airUtilTx = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
|
||||
self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
|
||||
|
||||
var newTelemetries = [TelemetryEntity]()
|
||||
newTelemetries.append(telemetry)
|
||||
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
|
||||
}
|
||||
|
||||
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.lastHeard)))
|
||||
newNode.snr = decodedInfo.nodeInfo.snr
|
||||
|
||||
if self.connectedPeripheral != nil && self.connectedPeripheral.num == newNode.num {
|
||||
|
||||
if decodedInfo.nodeInfo.hasUser {
|
||||
|
||||
connectedPeripheral.name = decodedInfo.nodeInfo.user.longName
|
||||
}
|
||||
}
|
||||
|
||||
if decodedInfo.nodeInfo.hasUser {
|
||||
|
||||
let newUser = UserEntity(context: context!)
|
||||
newUser.userId = decodedInfo.nodeInfo.user.id
|
||||
newUser.num = Int64(decodedInfo.nodeInfo.num)
|
||||
newUser.longName = decodedInfo.nodeInfo.user.longName
|
||||
newUser.shortName = decodedInfo.nodeInfo.user.shortName
|
||||
newUser.macaddr = decodedInfo.nodeInfo.user.macaddr
|
||||
newUser.hwModel = String(describing: decodedInfo.nodeInfo.user.hwModel).uppercased()
|
||||
newNode.user = newUser
|
||||
}
|
||||
|
||||
let position = PositionEntity(context: context!)
|
||||
position.latitudeI = decodedInfo.nodeInfo.position.latitudeI
|
||||
position.longitudeI = decodedInfo.nodeInfo.position.longitudeI
|
||||
position.altitude = decodedInfo.nodeInfo.position.altitude
|
||||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.position.time)))
|
||||
|
||||
var newPostions = [PositionEntity]()
|
||||
newPostions.append(position)
|
||||
newNode.positions? = NSOrderedSet(array: newPostions)
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(decodedInfo.nodeInfo.num))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedMyInfo = try context?.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count > 0 {
|
||||
newNode.myInfo = fetchedMyInfo[0]
|
||||
|
||||
}
|
||||
|
||||
} catch {
|
||||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
|
||||
} else if decodedInfo.nodeInfo.hasUser && decodedInfo.nodeInfo.num > 0 {
|
||||
|
||||
fetchedNode[0].id = Int64(decodedInfo.nodeInfo.num)
|
||||
fetchedNode[0].num = Int64(decodedInfo.nodeInfo.num)
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.lastHeard)))
|
||||
fetchedNode[0].snr = decodedInfo.nodeInfo.snr
|
||||
|
||||
if self.connectedPeripheral != nil && self.connectedPeripheral.num == fetchedNode[0].num {
|
||||
|
||||
if decodedInfo.nodeInfo.hasUser {
|
||||
|
||||
self.connectedPeripheral.name = fetchedNode[0].user!.longName ?? "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
if decodedInfo.nodeInfo.hasUser {
|
||||
|
||||
fetchedNode[0].user!.userId = decodedInfo.nodeInfo.user.id
|
||||
fetchedNode[0].user!.num = Int64(decodedInfo.nodeInfo.num)
|
||||
fetchedNode[0].user!.longName = decodedInfo.nodeInfo.user.longName
|
||||
fetchedNode[0].user!.shortName = decodedInfo.nodeInfo.user.shortName
|
||||
fetchedNode[0].user!.macaddr = decodedInfo.nodeInfo.user.macaddr
|
||||
fetchedNode[0].user!.hwModel = String(describing: decodedInfo.nodeInfo.user.hwModel).uppercased()
|
||||
}
|
||||
|
||||
if decodedInfo.nodeInfo.hasDeviceMetrics {
|
||||
|
||||
let newTelemetry = TelemetryEntity(context: context!)
|
||||
|
||||
newTelemetry.batteryLevel = Int32(decodedInfo.nodeInfo.deviceMetrics.batteryLevel)
|
||||
newTelemetry.voltage = decodedInfo.nodeInfo.deviceMetrics.voltage
|
||||
newTelemetry.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization
|
||||
self.connectedPeripheral.channelUtilization = newTelemetry.channelUtilization
|
||||
newTelemetry.airUtilTx = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
|
||||
self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
|
||||
|
||||
let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as! NSMutableOrderedSet
|
||||
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
||||
}
|
||||
|
||||
if decodedInfo.nodeInfo.hasPosition {
|
||||
|
||||
let position = PositionEntity(context: context!)
|
||||
position.latitudeI = decodedInfo.nodeInfo.position.latitudeI
|
||||
position.longitudeI = decodedInfo.nodeInfo.position.longitudeI
|
||||
position.altitude = decodedInfo.nodeInfo.position.altitude
|
||||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.position.time)))
|
||||
|
||||
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
|
||||
|
||||
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
||||
|
||||
}
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(decodedInfo.nodeInfo.num))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedMyInfo = try context?.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count > 0 {
|
||||
|
||||
fetchedNode[0].myInfo = fetchedMyInfo[0]
|
||||
}
|
||||
|
||||
} catch {
|
||||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
try context!.save()
|
||||
print("💾 Saved a nodeInfo for \(decodedInfo.nodeInfo.num)")
|
||||
|
||||
} catch {
|
||||
|
||||
context!.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
print("💥 Fetch NodeInfoEntity Error")
|
||||
}
|
||||
|
||||
if decodedInfo.nodeInfo.hasUser {
|
||||
|
||||
if meshLoggingEnabled { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.user.longName)") }
|
||||
|
||||
} else {
|
||||
|
||||
if meshLoggingEnabled { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.num)") }
|
||||
// MARK: Share Location Position Update Timer
|
||||
// Use context to pass the radio name with the timer
|
||||
// Use a RunLoop to prevent the timer from running on the main UI thread
|
||||
if userSettings?.provideLocation ?? false {
|
||||
|
||||
if self.positionTimer != nil {
|
||||
self.positionTimer!.invalidate()
|
||||
}
|
||||
let context = ["name": "@\(peripheral.name ?? "Unknown")"]
|
||||
self.positionTimer = Timer.scheduledTimer(timeInterval: TimeInterval((userSettings?.provideLocationInterval ?? 900)), target: self, selector: #selector(positionTimerFired), userInfo: context, repeats: true)
|
||||
RunLoop.current.add(self.positionTimer!, forMode: .common)
|
||||
}
|
||||
|
||||
if decodedInfo.configCompleteID != 0 {
|
||||
|
|
@ -720,7 +506,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
|
||||
case FROMNUM_UUID :
|
||||
|
||||
print("🗞️ FROMNUM Notification, value will be read below")
|
||||
print("🗞️ BLE FROMNUM (Notify) characteristic, value will be read next")
|
||||
|
||||
default:
|
||||
|
||||
|
|
@ -731,7 +517,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
peripheral.readValue(for: FROMRADIO_characteristic)
|
||||
}
|
||||
|
||||
// Send Message
|
||||
public func sendMessage(message: String, toUserNum: Int64, isEmoji: Bool, replyID: Int64) -> Bool {
|
||||
|
||||
var success = false
|
||||
|
|
@ -854,7 +639,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
return success
|
||||
}
|
||||
|
||||
// Send Position
|
||||
public func sendPosition(destNum: Int64, wantResponse: Bool) -> Bool {
|
||||
|
||||
var success = false
|
||||
|
|
@ -1002,4 +786,5 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,267 @@
|
|||
import Foundation
|
||||
import CoreData
|
||||
|
||||
func nodeInfoPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObjectContext) {
|
||||
func myInfoPacket (myInfo: MyNodeInfo, meshLogging: Bool, context: NSManagedObjectContext) -> MyInfoEntity? {
|
||||
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(myInfo.myNodeNum))
|
||||
|
||||
do {
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
// Not Found Insert
|
||||
if fetchedMyInfo.isEmpty {
|
||||
|
||||
let myInfoEntity = MyInfoEntity(context: context)
|
||||
myInfoEntity.myNodeNum = Int64(myInfo.myNodeNum)
|
||||
myInfoEntity.hasGps = myInfo.hasGps_p
|
||||
myInfoEntity.hasWifi = myInfo.hasWifi_p
|
||||
myInfoEntity.bitrate = myInfo.bitrate
|
||||
|
||||
// Swift does strings weird, this does work to get the version without the github hash
|
||||
let lastDotIndex = myInfo.firmwareVersion.lastIndex(of: ".")
|
||||
var version = myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: myInfo.firmwareVersion))]
|
||||
version = version.dropLast()
|
||||
myInfoEntity.firmwareVersion = String(version)
|
||||
myInfoEntity.messageTimeoutMsec = Int32(bitPattern: myInfo.messageTimeoutMsec)
|
||||
myInfoEntity.minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
|
||||
myInfoEntity.maxChannels = Int32(bitPattern: myInfo.maxChannels)
|
||||
|
||||
do {
|
||||
|
||||
try context.save()
|
||||
if meshLogging { MeshLogger.log("💾 Saved a new myInfo for node number: \(String(myInfo.myNodeNum))") }
|
||||
return myInfoEntity
|
||||
|
||||
} catch {
|
||||
|
||||
context.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Inserting New Core Data MyInfoEntity: \(nsError)")
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
fetchedMyInfo[0].myNodeNum = Int64(myInfo.myNodeNum)
|
||||
fetchedMyInfo[0].hasGps = myInfo.hasGps_p
|
||||
fetchedMyInfo[0].bitrate = myInfo.bitrate
|
||||
|
||||
let lastDotIndex = myInfo.firmwareVersion.lastIndex(of: ".")//.lastIndex(of: ".", offsetBy: -1)
|
||||
var version = myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset:6, in: myInfo.firmwareVersion))]
|
||||
version = version.dropLast()
|
||||
fetchedMyInfo[0].firmwareVersion = String(version)
|
||||
fetchedMyInfo[0].messageTimeoutMsec = Int32(bitPattern: myInfo.messageTimeoutMsec)
|
||||
fetchedMyInfo[0].minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
|
||||
fetchedMyInfo[0].maxChannels = Int32(bitPattern: myInfo.maxChannels)
|
||||
|
||||
do {
|
||||
|
||||
try context.save()
|
||||
if meshLogging { MeshLogger.log("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))") }
|
||||
return fetchedMyInfo[0]
|
||||
|
||||
} catch {
|
||||
|
||||
context.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Updating Core Data MyInfoEntity: \(nsError)")
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func nodeInfoPacket (nodeInfo: NodeInfo, meshLogging: Bool, context: NSManagedObjectContext) -> NodeInfoEntity? {
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeInfo.num))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Not Found Insert
|
||||
if fetchedNode.isEmpty && nodeInfo.hasUser {
|
||||
|
||||
let newNode = NodeInfoEntity(context: context)
|
||||
newNode.id = Int64(nodeInfo.num)
|
||||
newNode.num = Int64(nodeInfo.num)
|
||||
|
||||
if nodeInfo.hasDeviceMetrics {
|
||||
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
|
||||
telemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
||||
telemetry.voltage = nodeInfo.deviceMetrics.voltage
|
||||
telemetry.channelUtilization = nodeInfo.deviceMetrics.channelUtilization
|
||||
telemetry.airUtilTx = nodeInfo.deviceMetrics.airUtilTx
|
||||
|
||||
var newTelemetries = [TelemetryEntity]()
|
||||
newTelemetries.append(telemetry)
|
||||
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
|
||||
}
|
||||
|
||||
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
||||
newNode.snr = nodeInfo.snr
|
||||
|
||||
if nodeInfo.hasUser {
|
||||
|
||||
let newUser = UserEntity(context: context)
|
||||
newUser.userId = nodeInfo.user.id
|
||||
newUser.num = Int64(nodeInfo.num)
|
||||
newUser.longName = nodeInfo.user.longName
|
||||
newUser.shortName = nodeInfo.user.shortName
|
||||
newUser.macaddr = nodeInfo.user.macaddr
|
||||
newUser.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
||||
newNode.user = newUser
|
||||
}
|
||||
|
||||
let position = PositionEntity(context: context)
|
||||
position.latitudeI = nodeInfo.position.latitudeI
|
||||
position.longitudeI = nodeInfo.position.longitudeI
|
||||
position.altitude = nodeInfo.position.altitude
|
||||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
|
||||
|
||||
var newPostions = [PositionEntity]()
|
||||
newPostions.append(position)
|
||||
newNode.positions? = NSOrderedSet(array: newPostions)
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count > 0 {
|
||||
newNode.myInfo = fetchedMyInfo[0]
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
try context.save()
|
||||
|
||||
if nodeInfo.hasUser {
|
||||
|
||||
if meshLogging { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo inserted for \(nodeInfo.user.longName)") }
|
||||
|
||||
} else {
|
||||
|
||||
if meshLogging { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo inserted for \(nodeInfo.num)") }
|
||||
}
|
||||
return newNode
|
||||
|
||||
} catch {
|
||||
|
||||
context.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
|
||||
} else if nodeInfo.hasUser && nodeInfo.num > 0 {
|
||||
|
||||
fetchedNode[0].id = Int64(nodeInfo.num)
|
||||
fetchedNode[0].num = Int64(nodeInfo.num)
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
||||
fetchedNode[0].snr = nodeInfo.snr
|
||||
|
||||
|
||||
if nodeInfo.hasUser {
|
||||
|
||||
fetchedNode[0].user!.userId = nodeInfo.user.id
|
||||
fetchedNode[0].user!.num = Int64(nodeInfo.num)
|
||||
fetchedNode[0].user!.longName = nodeInfo.user.longName
|
||||
fetchedNode[0].user!.shortName = nodeInfo.user.shortName
|
||||
fetchedNode[0].user!.macaddr = nodeInfo.user.macaddr
|
||||
fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
||||
}
|
||||
|
||||
if nodeInfo.hasDeviceMetrics {
|
||||
|
||||
let newTelemetry = TelemetryEntity(context: context)
|
||||
|
||||
newTelemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
||||
newTelemetry.voltage = nodeInfo.deviceMetrics.voltage
|
||||
newTelemetry.channelUtilization = nodeInfo.deviceMetrics.channelUtilization
|
||||
newTelemetry.airUtilTx = nodeInfo.deviceMetrics.airUtilTx
|
||||
|
||||
let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as! NSMutableOrderedSet
|
||||
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
||||
}
|
||||
|
||||
if nodeInfo.hasPosition {
|
||||
|
||||
let position = PositionEntity(context: context)
|
||||
position.latitudeI = nodeInfo.position.latitudeI
|
||||
position.longitudeI = nodeInfo.position.longitudeI
|
||||
position.altitude = nodeInfo.position.altitude
|
||||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
|
||||
|
||||
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
|
||||
|
||||
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
||||
|
||||
}
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count > 0 {
|
||||
|
||||
fetchedNode[0].myInfo = fetchedMyInfo[0]
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
try context.save()
|
||||
|
||||
if nodeInfo.hasUser {
|
||||
|
||||
if meshLogging { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo inserted for \(nodeInfo.user.longName)") }
|
||||
|
||||
} else {
|
||||
|
||||
if meshLogging { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo inserted for \(nodeInfo.num)") }
|
||||
}
|
||||
|
||||
return fetchedNode[0]
|
||||
|
||||
} catch {
|
||||
|
||||
context.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
print("💥 Fetch NodeInfoEntity Error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func nodeInfoAppPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObjectContext) {
|
||||
|
||||
let fetchNodeInfoAppRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
|
@ -144,8 +404,6 @@ func routingPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObj
|
|||
|
||||
if routingMessage.errorReason == Routing.Error.none {
|
||||
|
||||
print("Priority ACK no Error")
|
||||
|
||||
let fetchMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
||||
fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID))
|
||||
|
||||
|
|
@ -184,9 +442,48 @@ func telemetryPacket(packet: MeshPacket, meshLogging: Bool, context: NSManagedOb
|
|||
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
|
||||
|
||||
|
||||
if meshLogging { MeshLogger.log("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(telemetryMessage)") }
|
||||
let fetchNodeTelemetryRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeTelemetryRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeTelemetryRequest) as! [NodeInfoEntity]
|
||||
|
||||
if fetchedNode.count == 1 {
|
||||
|
||||
// Device Metrics
|
||||
telemetry.airUtilTx = telemetryMessage.deviceMetrics.airUtilTx
|
||||
telemetry.channelUtilization = telemetryMessage.deviceMetrics.channelUtilization
|
||||
telemetry.batteryLevel = Int32(telemetryMessage.deviceMetrics.batteryLevel)
|
||||
telemetry.voltage = telemetryMessage.deviceMetrics.voltage
|
||||
|
||||
// Environment Metrics
|
||||
telemetry.barometricPressure = telemetryMessage.environmentMetrics.barometricPressure
|
||||
telemetry.current = telemetryMessage.environmentMetrics.current
|
||||
telemetry.gasResistance = telemetryMessage.environmentMetrics.gasResistance
|
||||
telemetry.relativeHumidity = telemetryMessage.environmentMetrics.relativeHumidity
|
||||
telemetry.temperature = telemetryMessage.environmentMetrics.temperature
|
||||
let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as! NSMutableOrderedSet
|
||||
mutableTelemetries.add(telemetry)
|
||||
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(telemetryMessage.time)))
|
||||
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
||||
fetchedNode[0].objectWillChange.send()
|
||||
}
|
||||
|
||||
try context.save()
|
||||
|
||||
if meshLogging {
|
||||
MeshLogger.log("💾 Telemetry Saved for Node: \(packet.from)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
context.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving Telemetry for Node \(packet.from) Error: \(nsError)")
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
|
|||
|
|
@ -32,12 +32,25 @@ struct ChannelSet {
|
|||
// methods supported on all messages.
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
/// Channel list with settings
|
||||
var settings: [ChannelSettings] = []
|
||||
|
||||
///
|
||||
/// LoRa config
|
||||
var loraConfig: Config.LoRaConfig {
|
||||
get {return _loraConfig ?? Config.LoRaConfig()}
|
||||
set {_loraConfig = newValue}
|
||||
}
|
||||
/// Returns true if `loraConfig` has been explicitly set.
|
||||
var hasLoraConfig: Bool {return self._loraConfig != nil}
|
||||
/// Clears the value of `loraConfig`. Subsequent reads from it will return its default value.
|
||||
mutating func clearLoraConfig() {self._loraConfig = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _loraConfig: Config.LoRaConfig? = nil
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
|
|
@ -50,6 +63,7 @@ extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
static let protoMessageName: String = "ChannelSet"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "settings"),
|
||||
2: .standard(proto: "lora_config"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -59,20 +73,29 @@ extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeRepeatedMessageField(value: &self.settings) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &self._loraConfig) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if !self.settings.isEmpty {
|
||||
try visitor.visitRepeatedMessageField(value: self.settings, fieldNumber: 1)
|
||||
}
|
||||
try { if let v = self._loraConfig {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: ChannelSet, rhs: ChannelSet) -> Bool {
|
||||
if lhs.settings != rhs.settings {return false}
|
||||
if lhs._loraConfig != rhs._loraConfig {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,180 +215,11 @@ struct OEMStore {
|
|||
init() {}
|
||||
}
|
||||
|
||||
struct LocalConfig {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var device: Config.DeviceConfig {
|
||||
get {return _storage._device ?? Config.DeviceConfig()}
|
||||
set {_uniqueStorage()._device = newValue}
|
||||
}
|
||||
/// Returns true if `device` has been explicitly set.
|
||||
var hasDevice: Bool {return _storage._device != nil}
|
||||
/// Clears the value of `device`. Subsequent reads from it will return its default value.
|
||||
mutating func clearDevice() {_uniqueStorage()._device = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var position: Config.PositionConfig {
|
||||
get {return _storage._position ?? Config.PositionConfig()}
|
||||
set {_uniqueStorage()._position = newValue}
|
||||
}
|
||||
/// Returns true if `position` has been explicitly set.
|
||||
var hasPosition: Bool {return _storage._position != nil}
|
||||
/// Clears the value of `position`. Subsequent reads from it will return its default value.
|
||||
mutating func clearPosition() {_uniqueStorage()._position = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var power: Config.PowerConfig {
|
||||
get {return _storage._power ?? Config.PowerConfig()}
|
||||
set {_uniqueStorage()._power = newValue}
|
||||
}
|
||||
/// Returns true if `power` has been explicitly set.
|
||||
var hasPower: Bool {return _storage._power != nil}
|
||||
/// Clears the value of `power`. Subsequent reads from it will return its default value.
|
||||
mutating func clearPower() {_uniqueStorage()._power = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var wifi: Config.WiFiConfig {
|
||||
get {return _storage._wifi ?? Config.WiFiConfig()}
|
||||
set {_uniqueStorage()._wifi = newValue}
|
||||
}
|
||||
/// Returns true if `wifi` has been explicitly set.
|
||||
var hasWifi: Bool {return _storage._wifi != nil}
|
||||
/// Clears the value of `wifi`. Subsequent reads from it will return its default value.
|
||||
mutating func clearWifi() {_uniqueStorage()._wifi = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var display: Config.DisplayConfig {
|
||||
get {return _storage._display ?? Config.DisplayConfig()}
|
||||
set {_uniqueStorage()._display = newValue}
|
||||
}
|
||||
/// Returns true if `display` has been explicitly set.
|
||||
var hasDisplay: Bool {return _storage._display != nil}
|
||||
/// Clears the value of `display`. Subsequent reads from it will return its default value.
|
||||
mutating func clearDisplay() {_uniqueStorage()._display = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var lora: Config.LoRaConfig {
|
||||
get {return _storage._lora ?? Config.LoRaConfig()}
|
||||
set {_uniqueStorage()._lora = newValue}
|
||||
}
|
||||
/// Returns true if `lora` has been explicitly set.
|
||||
var hasLora: Bool {return _storage._lora != nil}
|
||||
/// Clears the value of `lora`. Subsequent reads from it will return its default value.
|
||||
mutating func clearLora() {_uniqueStorage()._lora = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
}
|
||||
|
||||
struct LocalModuleConfig {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var mqtt: ModuleConfig.MQTTConfig {
|
||||
get {return _storage._mqtt ?? ModuleConfig.MQTTConfig()}
|
||||
set {_uniqueStorage()._mqtt = newValue}
|
||||
}
|
||||
/// Returns true if `mqtt` has been explicitly set.
|
||||
var hasMqtt: Bool {return _storage._mqtt != nil}
|
||||
/// Clears the value of `mqtt`. Subsequent reads from it will return its default value.
|
||||
mutating func clearMqtt() {_uniqueStorage()._mqtt = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var serial: ModuleConfig.SerialConfig {
|
||||
get {return _storage._serial ?? ModuleConfig.SerialConfig()}
|
||||
set {_uniqueStorage()._serial = newValue}
|
||||
}
|
||||
/// Returns true if `serial` has been explicitly set.
|
||||
var hasSerial: Bool {return _storage._serial != nil}
|
||||
/// Clears the value of `serial`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSerial() {_uniqueStorage()._serial = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var externalNotification: ModuleConfig.ExternalNotificationConfig {
|
||||
get {return _storage._externalNotification ?? ModuleConfig.ExternalNotificationConfig()}
|
||||
set {_uniqueStorage()._externalNotification = newValue}
|
||||
}
|
||||
/// Returns true if `externalNotification` has been explicitly set.
|
||||
var hasExternalNotification: Bool {return _storage._externalNotification != nil}
|
||||
/// Clears the value of `externalNotification`. Subsequent reads from it will return its default value.
|
||||
mutating func clearExternalNotification() {_uniqueStorage()._externalNotification = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var storeForward: ModuleConfig.StoreForwardConfig {
|
||||
get {return _storage._storeForward ?? ModuleConfig.StoreForwardConfig()}
|
||||
set {_uniqueStorage()._storeForward = newValue}
|
||||
}
|
||||
/// Returns true if `storeForward` has been explicitly set.
|
||||
var hasStoreForward: Bool {return _storage._storeForward != nil}
|
||||
/// Clears the value of `storeForward`. Subsequent reads from it will return its default value.
|
||||
mutating func clearStoreForward() {_uniqueStorage()._storeForward = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var rangeTest: ModuleConfig.RangeTestConfig {
|
||||
get {return _storage._rangeTest ?? ModuleConfig.RangeTestConfig()}
|
||||
set {_uniqueStorage()._rangeTest = newValue}
|
||||
}
|
||||
/// Returns true if `rangeTest` has been explicitly set.
|
||||
var hasRangeTest: Bool {return _storage._rangeTest != nil}
|
||||
/// Clears the value of `rangeTest`. Subsequent reads from it will return its default value.
|
||||
mutating func clearRangeTest() {_uniqueStorage()._rangeTest = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var telemetry: ModuleConfig.TelemetryConfig {
|
||||
get {return _storage._telemetry ?? ModuleConfig.TelemetryConfig()}
|
||||
set {_uniqueStorage()._telemetry = newValue}
|
||||
}
|
||||
/// Returns true if `telemetry` has been explicitly set.
|
||||
var hasTelemetry: Bool {return _storage._telemetry != nil}
|
||||
/// Clears the value of `telemetry`. Subsequent reads from it will return its default value.
|
||||
mutating func clearTelemetry() {_uniqueStorage()._telemetry = nil}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var cannedMessage: ModuleConfig.CannedMessageConfig {
|
||||
get {return _storage._cannedMessage ?? ModuleConfig.CannedMessageConfig()}
|
||||
set {_uniqueStorage()._cannedMessage = newValue}
|
||||
}
|
||||
/// Returns true if `cannedMessage` has been explicitly set.
|
||||
var hasCannedMessage: Bool {return _storage._cannedMessage != nil}
|
||||
/// Clears the value of `cannedMessage`. Subsequent reads from it will return its default value.
|
||||
mutating func clearCannedMessage() {_uniqueStorage()._cannedMessage = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
extension ScreenFonts: @unchecked Sendable {}
|
||||
extension DeviceState: @unchecked Sendable {}
|
||||
extension ChannelFile: @unchecked Sendable {}
|
||||
extension OEMStore: @unchecked Sendable {}
|
||||
extension LocalConfig: @unchecked Sendable {}
|
||||
extension LocalModuleConfig: @unchecked Sendable {}
|
||||
#endif // swift(>=5.5) && canImport(_Concurrency)
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
|
@ -612,227 +443,3 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "LocalConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "device"),
|
||||
2: .same(proto: "position"),
|
||||
3: .same(proto: "power"),
|
||||
4: .same(proto: "wifi"),
|
||||
5: .same(proto: "display"),
|
||||
6: .same(proto: "lora"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _device: Config.DeviceConfig? = nil
|
||||
var _position: Config.PositionConfig? = nil
|
||||
var _power: Config.PowerConfig? = nil
|
||||
var _wifi: Config.WiFiConfig? = nil
|
||||
var _display: Config.DisplayConfig? = nil
|
||||
var _lora: Config.LoRaConfig? = nil
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_device = source._device
|
||||
_position = source._position
|
||||
_power = source._power
|
||||
_wifi = source._wifi
|
||||
_display = source._display
|
||||
_lora = source._lora
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularMessageField(value: &_storage._device) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &_storage._position) }()
|
||||
case 3: try { try decoder.decodeSingularMessageField(value: &_storage._power) }()
|
||||
case 4: try { try decoder.decodeSingularMessageField(value: &_storage._wifi) }()
|
||||
case 5: try { try decoder.decodeSingularMessageField(value: &_storage._display) }()
|
||||
case 6: try { try decoder.decodeSingularMessageField(value: &_storage._lora) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = _storage._device {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
} }()
|
||||
try { if let v = _storage._position {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try { if let v = _storage._power {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
|
||||
} }()
|
||||
try { if let v = _storage._wifi {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
|
||||
} }()
|
||||
try { if let v = _storage._display {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
|
||||
} }()
|
||||
try { if let v = _storage._lora {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
|
||||
} }()
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: LocalConfig, rhs: LocalConfig) -> Bool {
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._device != rhs_storage._device {return false}
|
||||
if _storage._position != rhs_storage._position {return false}
|
||||
if _storage._power != rhs_storage._power {return false}
|
||||
if _storage._wifi != rhs_storage._wifi {return false}
|
||||
if _storage._display != rhs_storage._display {return false}
|
||||
if _storage._lora != rhs_storage._lora {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "LocalModuleConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "mqtt"),
|
||||
2: .same(proto: "serial"),
|
||||
3: .standard(proto: "external_notification"),
|
||||
4: .standard(proto: "store_forward"),
|
||||
5: .standard(proto: "range_test"),
|
||||
6: .same(proto: "telemetry"),
|
||||
7: .standard(proto: "canned_message"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _mqtt: ModuleConfig.MQTTConfig? = nil
|
||||
var _serial: ModuleConfig.SerialConfig? = nil
|
||||
var _externalNotification: ModuleConfig.ExternalNotificationConfig? = nil
|
||||
var _storeForward: ModuleConfig.StoreForwardConfig? = nil
|
||||
var _rangeTest: ModuleConfig.RangeTestConfig? = nil
|
||||
var _telemetry: ModuleConfig.TelemetryConfig? = nil
|
||||
var _cannedMessage: ModuleConfig.CannedMessageConfig? = nil
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_mqtt = source._mqtt
|
||||
_serial = source._serial
|
||||
_externalNotification = source._externalNotification
|
||||
_storeForward = source._storeForward
|
||||
_rangeTest = source._rangeTest
|
||||
_telemetry = source._telemetry
|
||||
_cannedMessage = source._cannedMessage
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularMessageField(value: &_storage._mqtt) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &_storage._serial) }()
|
||||
case 3: try { try decoder.decodeSingularMessageField(value: &_storage._externalNotification) }()
|
||||
case 4: try { try decoder.decodeSingularMessageField(value: &_storage._storeForward) }()
|
||||
case 5: try { try decoder.decodeSingularMessageField(value: &_storage._rangeTest) }()
|
||||
case 6: try { try decoder.decodeSingularMessageField(value: &_storage._telemetry) }()
|
||||
case 7: try { try decoder.decodeSingularMessageField(value: &_storage._cannedMessage) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = _storage._mqtt {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
} }()
|
||||
try { if let v = _storage._serial {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try { if let v = _storage._externalNotification {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
|
||||
} }()
|
||||
try { if let v = _storage._storeForward {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
|
||||
} }()
|
||||
try { if let v = _storage._rangeTest {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
|
||||
} }()
|
||||
try { if let v = _storage._telemetry {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
|
||||
} }()
|
||||
try { if let v = _storage._cannedMessage {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 7)
|
||||
} }()
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: LocalModuleConfig, rhs: LocalModuleConfig) -> Bool {
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._mqtt != rhs_storage._mqtt {return false}
|
||||
if _storage._serial != rhs_storage._serial {return false}
|
||||
if _storage._externalNotification != rhs_storage._externalNotification {return false}
|
||||
if _storage._storeForward != rhs_storage._storeForward {return false}
|
||||
if _storage._rangeTest != rhs_storage._rangeTest {return false}
|
||||
if _storage._telemetry != rhs_storage._telemetry {return false}
|
||||
if _storage._cannedMessage != rhs_storage._cannedMessage {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ struct ShareChannel: View {
|
|||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
let channelSet = ChannelSet()
|
||||
|
||||
@State private var text = "meshtastic.org"
|
||||
@State private var text = "https://www.meshtastic.org/e/#"
|
||||
var qrCodeImage = QrCodeImage()
|
||||
|
||||
var body: some View {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue