Dont ever save positions at apple park

implement display mode
This commit is contained in:
Garth Vander Houwen 2023-01-25 23:01:45 -08:00
parent 6b4240d7fb
commit 8141a36e06
6 changed files with 157 additions and 84 deletions

View file

@ -104,6 +104,7 @@ enum OledTypes: Int, CaseIterable, Identifiable {
case auto = 0
case ssd1306 = 1
case sh1106 = 2
case sh1107 = 3
var id: Int { self.rawValue }
var description: String {
@ -115,6 +116,8 @@ enum OledTypes: Int, CaseIterable, Identifiable {
return "SSD 1306"
case .sh1106:
return "SH 1106"
case .sh1107:
return "SH 1107"
}
}
}
@ -127,6 +130,46 @@ enum OledTypes: Int, CaseIterable, Identifiable {
return Config.DisplayConfig.OledType.oledSsd1306
case .sh1106:
return Config.DisplayConfig.OledType.oledSh1106
case .sh1107:
return Config.DisplayConfig.OledType.oledSh1106
}
}
}
// Default of 0 is auto
enum DisplayModes: Int, CaseIterable, Identifiable {
case defaultMode = 0
case twoColor = 1
case inverted = 2
case color = 3
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .defaultMode:
return "Default 128x64 screen layout"
case .twoColor:
return "Optimized for 2 color displays"
case .inverted:
return "Inverted top bar for 2 Color display"
case .color:
return "TFT Full Color Displays"
}
}
}
func protoEnumValue() -> Config.DisplayConfig.DisplayMode {
switch self {
case .defaultMode:
return Config.DisplayConfig.DisplayMode.default
case .twoColor:
return Config.DisplayConfig.DisplayMode.twocolor
case .inverted:
return Config.DisplayConfig.DisplayMode.inverted
case .color:
return Config.DisplayConfig.DisplayMode.color
}
}
}

View file

@ -505,7 +505,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
case .remoteHardwareApp:
MeshLogger.log("🕸️ MESH PACKET received for Remote Hardware App UNHANDLED \(try! decodedInfo.packet.jsonString())")
case .positionApp:
positionPacket(packet: decodedInfo.packet, context: context!)
upsertPositionPacket(packet: decodedInfo.packet, context: context!)
case .waypointApp:
waypointPacket(packet: decodedInfo.packet, context: context!)
case .nodeinfoApp:

View file

@ -589,7 +589,8 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
newNode.user = newUser
}
if nodeInfo.position.latitudeI > 0 || nodeInfo.position.longitudeI > 0 {
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000)
{
let position = PositionEntity(context: context)
position.seqNo = Int32(nodeInfo.position.seqNumber)
position.latitudeI = nodeInfo.position.latitudeI
@ -656,14 +657,19 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
if nodeInfo.hasPosition {
let position = PositionEntity(context: context)
position.latitudeI = nodeInfo.position.latitudeI
position.longitudeI = nodeInfo.position.longitudeI
position.altitude = nodeInfo.position.altitude
position.satsInView = Int32(nodeInfo.position.satsInView)
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
let position = PositionEntity(context: context)
position.latitudeI = nodeInfo.position.latitudeI
position.longitudeI = nodeInfo.position.longitudeI
position.altitude = nodeInfo.position.altitude
position.satsInView = Int32(nodeInfo.position.satsInView)
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
@ -753,6 +759,8 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
@ -819,62 +827,6 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
}
}
func positionPacket (packet: MeshPacket, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.position.received %@", comment: "Position Packet received from node: %@"), String(packet.from))
MeshLogger.log("📍 \(logString)")
let fetchNodePositionRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
do {
if let positionMessage = try? Position(serializedData: packet.decoded.payload) {
// Don't save empty position packets
if positionMessage.longitudeI > 0 || positionMessage.latitudeI > 0 {
let fetchedNode = try context.fetch(fetchNodePositionRequest) as! [NodeInfoEntity]
if fetchedNode.count == 1 {
let position = PositionEntity(context: context)
position.snr = packet.rxSnr
position.seqNo = Int32(positionMessage.seqNumber)
position.latitudeI = positionMessage.latitudeI
position.longitudeI = positionMessage.longitudeI
position.altitude = positionMessage.altitude
position.satsInView = Int32(positionMessage.satsInView)
position.speed = Int32(positionMessage.groundSpeed)
position.heading = Int32(positionMessage.groundTrack)
if positionMessage.timestamp != 0 {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.timestamp)))
} else {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
}
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
mutablePositions.add(position)
fetchedNode[0].id = Int64(packet.from)
fetchedNode[0].num = Int64(packet.from)
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
fetchedNode[0].snr = packet.rxSnr
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
do {
try context.save()
print("💾 Updated Node Position Coordinates, SNR and Time from Position App Packet For: \(fetchedNode[0].num)")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
}
}
} else {
print("💥 Empty POSITION_APP Packet")
print(try! packet.jsonString())
}
}
} catch {
print("💥 Error Deserializing POSITION_APP packet.")
}
}
func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
if let routingMessage = try? Routing(serializedData: packet.decoded.payload) {

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22C65" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22D49" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="BluetoothConfigEntity" representedClassName="BluetoothConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="fixedPin" optional="YES" attributeType="Integer 32" defaultValueString="123456" usesScalarValueType="YES"/>
@ -60,6 +60,7 @@
</entity>
<entity name="DisplayConfigEntity" representedClassName="DisplayConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="compassNorthTop" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="displayMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="flipScreen" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="gpsFormat" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="oledType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>

View file

@ -62,7 +62,7 @@ public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManage
public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObjectContext) {
do {
let objects = channel.allPrivateMessages// try context.fetch(fetchChannelMessagesRequest) as! [NSManagedObject]
let objects = channel.allPrivateMessages
for object in objects {
context.delete(object)
}
@ -75,7 +75,7 @@ public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObje
public func deleteUserMessages(user: UserEntity, context: NSManagedObjectContext) {
do {
let objects = user.messageList//try context.fetch(fetchUserMessagesRequest) as! [NSManagedObject]
let objects = user.messageList
for object in objects {
context.delete(object)
}
@ -101,6 +101,64 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext) {
}
}
func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.position.received %@", comment: "Position Packet received from node: %@"), String(packet.from))
MeshLogger.log("📍 \(logString)")
let fetchNodePositionRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
do {
if let positionMessage = try? Position(serializedData: packet.decoded.payload) {
// Don't save empty position packets
if positionMessage.longitudeI > 0 || positionMessage.latitudeI > 0 && (positionMessage.latitudeI != 373346000 && positionMessage.longitudeI != -1220090000)
{
let fetchedNode = try context.fetch(fetchNodePositionRequest) as! [NodeInfoEntity]
if fetchedNode.count == 1 {
let position = PositionEntity(context: context)
position.snr = packet.rxSnr
position.seqNo = Int32(positionMessage.seqNumber)
position.latitudeI = positionMessage.latitudeI
position.longitudeI = positionMessage.longitudeI
position.altitude = positionMessage.altitude
position.satsInView = Int32(positionMessage.satsInView)
position.speed = Int32(positionMessage.groundSpeed)
position.heading = Int32(positionMessage.groundTrack)
if positionMessage.timestamp != 0 {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.timestamp)))
} else {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
}
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
mutablePositions.add(position)
fetchedNode[0].id = Int64(packet.from)
fetchedNode[0].num = Int64(packet.from)
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
fetchedNode[0].snr = packet.rxSnr
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
do {
try context.save()
print("💾 Updated Node Position Coordinates, SNR and Time from Position App Packet For: \(fetchedNode[0].num)")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
}
}
} else {
print("💥 Empty POSITION_APP Packet")
print(try! packet.jsonString())
}
}
} catch {
print("💥 Error Deserializing POSITION_APP packet.")
}
}
func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.bluetooth.config %@", comment: "Bluetooth config received: %@"), String(nodeNum))
@ -208,6 +266,7 @@ func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManage
newDisplayConfig.compassNorthTop = config.display.compassNorthTop
newDisplayConfig.flipScreen = config.display.flipScreen
newDisplayConfig.oledType = Int32(config.display.oled.rawValue)
newDisplayConfig.displayMode = Int32(config.display.displaymode.rawValue)
fetchedNode[0].displayConfig = newDisplayConfig
} else {
@ -218,6 +277,7 @@ func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManage
fetchedNode[0].displayConfig?.compassNorthTop = config.display.compassNorthTop
fetchedNode[0].displayConfig?.flipScreen = config.display.flipScreen
fetchedNode[0].displayConfig?.oledType = Int32(config.display.oled.rawValue)
fetchedNode[0].displayConfig?.displayMode = Int32(config.display.displaymode.rawValue)
}
do {

View file

@ -24,29 +24,20 @@ struct DisplayConfig: View {
@State var compassNorthTop = false
@State var flipScreen = false
@State var oledType = 0
@State var displayMode = 0
var body: some View {
Form {
Section(header: Text("Device Screen")) {
Picker("Screen on for", selection: $screenOnSeconds ) {
ForEach(ScreenOnIntervals.allCases) { soi in
Text(soi.description)
Picker("Display Mode", selection: $displayMode ) {
ForEach(DisplayModes.allCases) { dm in
Text(dm.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("How long the screen remains on after the user button is pressed or messages are received.")
.font(.caption)
Picker("Carousel Interval", selection: $screenCarouselInterval ) {
ForEach(ScreenCarouselIntervals.allCases) { sci in
Text(sci.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("Automatically toggles to the next page on the screen like a carousel, based the specified interval.")
Text("Override automatic OLED screen detection.")
.font(.caption)
Toggle(isOn: $compassNorthTop) {
@ -64,6 +55,7 @@ struct DisplayConfig: View {
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Text("Flip screen vertically")
.font(.caption)
Picker("OLED Type", selection: $oledType ) {
ForEach(OledTypes.allCases) { ot in
Text(ot.description)
@ -74,7 +66,25 @@ struct DisplayConfig: View {
.font(.caption)
}
Section(header: Text("Format")) {
Section(header: Text("Timing & Format")) {
Picker("Screen on for", selection: $screenOnSeconds ) {
ForEach(ScreenOnIntervals.allCases) { soi in
Text(soi.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("How long the screen remains on after the user button is pressed or messages are received.")
.font(.caption)
Picker("Carousel Interval", selection: $screenCarouselInterval ) {
ForEach(ScreenCarouselIntervals.allCases) { sci in
Text(sci.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("Automatically toggles to the next page on the screen like a carousel, based the specified interval.")
.font(.caption)
Picker("GPS Format", selection: $gpsFormat ) {
ForEach(GpsFormats.allCases) { lu in
Text(lu.description)
@ -116,6 +126,7 @@ struct DisplayConfig: View {
dc.compassNorthTop = compassNorthTop
dc.flipScreen = flipScreen
dc.oled = OledTypes(rawValue: oledType)!.protoEnumValue()
dc.displaymode = DisplayModes(rawValue: displayMode)!.protoEnumValue()
let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: node!.user!, toUser: node!.user!)
if adminMessageId > 0 {
@ -143,6 +154,7 @@ struct DisplayConfig: View {
self.compassNorthTop = node?.displayConfig?.compassNorthTop ?? false
self.flipScreen = node?.displayConfig?.flipScreen ?? false
self.oledType = Int(node?.displayConfig?.oledType ?? 0)
self.displayMode = Int(node?.displayConfig?.displayMode ?? 0)
self.hasChanges = false
}
.onChange(of: screenOnSeconds) { newScreenSecs in
@ -175,5 +187,10 @@ struct DisplayConfig: View {
if newOledType != node!.displayConfig!.oledType { hasChanges = true }
}
}
.onChange(of: displayMode) { newDisplayMode in
if node != nil && node!.displayConfig != nil {
if newDisplayMode != node!.displayConfig!.displayMode { hasChanges = true }
}
}
}
}