From dccefee3383c553aabbb90e00b6c7e7d701380b9 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 5 Aug 2022 15:58:12 -0700 Subject: [PATCH] ACK errors --- Meshtastic.xcodeproj/project.pbxproj | 12 ++ Meshtastic/Enums/RoutingError.swift | 109 ++++++++++++++++++ Meshtastic/Helpers/MeshPackets.swift | 2 + .../Views/Messages/UserMessageList.swift | 57 +++++---- 4 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 Meshtastic/Enums/RoutingError.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 279a0636..d1afffe5 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD882F5C2772E4640005BF05 /* Contacts.swift */; }; DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8EBF42285058FA00426DCA /* DisplayConfig.swift */; }; DD8ED9C52898D51F00B3B0AB /* WiFiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */; }; + DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */; }; DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860B26F684AF00DC5189 /* BatteryIcon.swift */; }; DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; }; DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */; }; @@ -148,6 +149,7 @@ DD8EBF42285058FA00426DCA /* DisplayConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayConfig.swift; sourceTree = ""; }; DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 5.xcdatamodel"; sourceTree = ""; }; DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WiFiConfig.swift; sourceTree = ""; }; + DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutingError.swift; sourceTree = ""; }; DD90860A26F645B700DC5189 /* Meshtastic.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Meshtastic.entitlements; sourceTree = ""; }; DD90860B26F684AF00DC5189 /* BatteryIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIcon.swift; sourceTree = ""; }; DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = ""; }; @@ -305,6 +307,14 @@ path = Export; sourceTree = ""; }; + DD8ED9C6289CE4A100B3B0AB /* Enums */ = { + isa = PBXGroup; + children = ( + DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */, + ); + path = Enums; + sourceTree = ""; + }; DD8EDE9226F97A2B00A5A10B /* Frameworks */ = { isa = PBXGroup; children = ( @@ -359,6 +369,7 @@ DDC2E15626CE248E0042C5E4 /* Meshtastic */ = { isa = PBXGroup; children = ( + DD8ED9C6289CE4A100B3B0AB /* Enums */, DD90860A26F645B700DC5189 /* Meshtastic.entitlements */, DDC4D5662754996200A4208E /* Persistence */, DDAF8C5626ED07740058C060 /* Protobufs */, @@ -680,6 +691,7 @@ DD2553592855B52700E55709 /* PositionConfig.swift in Sources */, DDAF8C6326ED0A230058C060 /* admin.pb.swift in Sources */, DD86D40C287F401000BAEB7A /* SaveChannelQRCode.swift in Sources */, + DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */, C9483F6D2773017500998F6B /* MapView.swift in Sources */, DDAF8C5826ED07FD0058C060 /* mesh.pb.swift in Sources */, DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */, diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift new file mode 100644 index 00000000..b242f45f --- /dev/null +++ b/Meshtastic/Enums/RoutingError.swift @@ -0,0 +1,109 @@ +// +// RoutingError.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/4/22. +// + +enum RoutingError: Int, CaseIterable, Identifiable { + + case none = 0 + case noRoute = 1 + case gotNak = 2 + case timeout = 3 + case noInterface = 4 + case maxRetransmit = 5 + case noChannel = 6 + case tooLarge = 7 + case noResponse = 8 + case badRequest = 32 + case notAuthorized = 33 + + var id: Int { self.rawValue } + var display: String { + get { + switch self { + + case .none: + return "No Error." + case .noRoute: + return "No Route" + case .gotNak: + return "Received a nak" + case .timeout: + return "Timeout" + case .noInterface: + return "No Interface" + case .maxRetransmit: + return "Max Retransmission Reached" + case .noChannel: + return "No Channel" + case .tooLarge: + return "The packet is too large" + case .noResponse: + return "No Response" + case .badRequest: + return "Bad Request" + case .notAuthorized: + return "Not Authorized" + } + } + } + var description: String { + get { + switch self { + + case .none: + return "This message is not a failure." + case .noRoute: + return "Our node doesn't have a route to the requested destination anymore." + case .gotNak: + return "We received a nak while trying to forward on your behalf." + case .timeout: + return "We timed out while attempting to route this packet." + case .noInterface: + return "No suitable interface could be found for delivering this packet." + case .maxRetransmit: + return "We reached the max retransmission count (Hop Limit) and have received no responses." + case .noChannel: + return "No suitable channel was found for sending this packet (i.e. was requested channel index disabled?)." + case .tooLarge: + return "The packet was too big for sending (exceeds interface MTU after encoding)." + case .noResponse: + return "The request had want_response set, the request reached the destination node, but no service on that node wants to send a response (possibly due to bad channel permissions)." + case .badRequest: + return "The application layer service on the remote node received your request, but considered your request somehow invalid." + case .notAuthorized: + return "The application layer service on the remote node received your request, but considered your request not authorized (i.e you did not send the request on the required bound channel)." + } + } + } + func protoEnumValue() -> Routing.Error { + + switch self { + + case .none: + return Routing.Error.none + case .noRoute: + return Routing.Error.noRoute + case .gotNak: + return Routing.Error.gotNak + case .timeout: + return Routing.Error.timeout + case .noInterface: + return Routing.Error.noInterface + case .maxRetransmit: + return Routing.Error.maxRetransmit + case .noChannel: + return Routing.Error.noChannel + case .tooLarge: + return Routing.Error.tooLarge + case .noResponse: + return Routing.Error.noResponse + case .badRequest: + return Routing.Error.badRequest + case .notAuthorized: + return Routing.Error.notAuthorized + } + } +} diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 6d5bb1f1..8157d990 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -1337,6 +1337,8 @@ func routingPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObj fetchedMessage![0].ackSNR = packet.rxSnr fetchedMessage![0].ackTimestamp = Int32(packet.rxTime) fetchedMessage![0].objectWillChange.send() + fetchedMessage![0].fromUser?.objectWillChange.send() + fetchedMessage![0].toUser?.objectWillChange.send() } else { diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index ed4366ef..846a05ca 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -213,37 +213,41 @@ struct UserMessageList: View { let messageDate = Date(timeIntervalSince1970: TimeInterval(message.messageTimestamp)) - Text("Sent \(messageDate, style: .date) \(messageDate, style: .time)").font(.caption2).foregroundColor(.gray) + Text("Sent \(messageDate, style: .date) \(messageDate.formattedDate(format: "h:mm:ss a"))").font(.caption2).foregroundColor(.gray) } - VStack { - - Text("Received ACK: \(message.receivedACK ? "✔️" : "")") - - } + if message.receivedACK { - VStack { - - let ackDate = Date(timeIntervalSince1970: TimeInterval(message.ackTimestamp)) - - let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date()) - if ackDate >= sixMonthsAgo! { - - Text("ACK \(ackDate, style: .date) \(ackDate, style: .time)").font(.caption2).foregroundColor(.gray) - - } else { - - Text("Unknown Age").font(.caption2).foregroundColor(.gray) - } - } - } else if message.ackError > 0 { - Text("Ack Failure") + VStack { + + Text("Received Ack \(message.receivedACK ? "✔️" : "")") + } } + if message.ackError > 0 { + + let ackErrorVal = RoutingError(rawValue: Int(message.ackError)) + Text("\(ackErrorVal?.display ?? "No Error" )").fixedSize(horizontal: false, vertical: true) + } + VStack { + + let ackDate = Date(timeIntervalSince1970: TimeInterval(message.ackTimestamp)) + + let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date()) + if ackDate >= sixMonthsAgo! { + + Text((ackDate.formattedDate(format: "h:mm:ss a"))).font(.caption2).foregroundColor(.gray) + + } else { + + Text("Unknown Age").font(.caption2).foregroundColor(.gray) + } + } + if message.ackSNR != 0 { VStack { - Text("ACK SNR \(String(message.ackSNR))") + Text("Ack SNR \(String(message.ackSNR))") .font(.caption2) .foregroundColor(.gray) } @@ -296,6 +300,13 @@ struct UserMessageList: View { Text("Acknowledged").font(.caption2).foregroundColor(.gray) } + + if message.ackError > 0 { + + let ackErrorVal = RoutingError(rawValue: Int(message.ackError)) + Text("\(ackErrorVal?.display ?? "No Error" )").fixedSize(horizontal: false, vertical: true) + .font(.caption2).foregroundColor(.red) + } } } .padding(.bottom)