diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index eb367e16..b8ee6a03 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -966,7 +966,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.3; + MARKETING_VERSION = 2.0.5; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -999,7 +999,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.3; + MARKETING_VERSION = 2.0.5; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 2051809c..71a55c23 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -212,14 +212,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } else { if newPeripheral.peripheral.state != CBPeripheralState.connected { - peripherals.append(newPeripheral) - print("ℹ️ Adding peripheral: \(peripheralName)") } } let today = Date() - let visibleDuration = Calendar.current.date(byAdding: .second, value: -3, to: today)! + let visibleDuration = Calendar.current.date(byAdding: .second, value: -5, to: today)! peripherals.removeAll(where: { $0.lastUpdate < visibleDuration}) } diff --git a/Meshtastic/Protobufs/admin.pb.swift b/Meshtastic/Protobufs/admin.pb.swift index a8dbfaae..21b5f2a0 100644 --- a/Meshtastic/Protobufs/admin.pb.swift +++ b/Meshtastic/Protobufs/admin.pb.swift @@ -209,23 +209,24 @@ struct AdminMessage { } /// - /// Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins - var confirmSetConfig: Bool { + /// Begins an edit transaction for config, module config, owner, and channel settings changes + /// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) + var beginEditSettings: Bool { get { - if case .confirmSetConfig(let v)? = payloadVariant {return v} + if case .beginEditSettings(let v)? = payloadVariant {return v} return false } - set {payloadVariant = .confirmSetConfig(newValue)} + set {payloadVariant = .beginEditSettings(newValue)} } /// - /// Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins - var confirmSetModuleConfig: Bool { + /// Commits an open transaction for any edits made to config, module config, owner, and channel settings + var commitEditSettings: Bool { get { - if case .confirmSetModuleConfig(let v)? = payloadVariant {return v} + if case .commitEditSettings(let v)? = payloadVariant {return v} return false } - set {payloadVariant = .confirmSetModuleConfig(newValue)} + set {payloadVariant = .commitEditSettings(newValue)} } /// @@ -375,11 +376,12 @@ struct AdminMessage { /// Set the Canned Message Module messages text. case setCannedMessageModuleMessages(String) /// - /// Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins - case confirmSetConfig(Bool) + /// Begins an edit transaction for config, module config, owner, and channel settings changes + /// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) + case beginEditSettings(Bool) /// - /// Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins - case confirmSetModuleConfig(Bool) + /// Commits an open transaction for any edits made to config, module config, owner, and channel settings + case commitEditSettings(Bool) /// /// Setting channels/radio config remotely carries the risk that you might send an invalid config and the radio never talks to your mesh again. /// Therefore if setting either of these properties remotely, you must send a confirm_xxx message within 10 minutes. @@ -484,12 +486,12 @@ struct AdminMessage { guard case .setCannedMessageModuleMessages(let l) = lhs, case .setCannedMessageModuleMessages(let r) = rhs else { preconditionFailure() } return l == r }() - case (.confirmSetConfig, .confirmSetConfig): return { - guard case .confirmSetConfig(let l) = lhs, case .confirmSetConfig(let r) = rhs else { preconditionFailure() } + case (.beginEditSettings, .beginEditSettings): return { + guard case .beginEditSettings(let l) = lhs, case .beginEditSettings(let r) = rhs else { preconditionFailure() } return l == r }() - case (.confirmSetModuleConfig, .confirmSetModuleConfig): return { - guard case .confirmSetModuleConfig(let l) = lhs, case .confirmSetModuleConfig(let r) = rhs else { preconditionFailure() } + case (.commitEditSettings, .commitEditSettings): return { + guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } return l == r }() case (.confirmSetChannel, .confirmSetChannel): return { @@ -731,8 +733,8 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat 34: .standard(proto: "set_config"), 35: .standard(proto: "set_module_config"), 36: .standard(proto: "set_canned_message_module_messages"), - 64: .standard(proto: "confirm_set_config"), - 65: .standard(proto: "confirm_set_module_config"), + 64: .standard(proto: "begin_edit_settings"), + 65: .standard(proto: "commit_edit_settings"), 66: .standard(proto: "confirm_set_channel"), 67: .standard(proto: "confirm_set_radio"), 95: .standard(proto: "reboot_ota_seconds"), @@ -935,7 +937,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try decoder.decodeSingularBoolField(value: &v) if let v = v { if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} - self.payloadVariant = .confirmSetConfig(v) + self.payloadVariant = .beginEditSettings(v) } }() case 65: try { @@ -943,7 +945,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try decoder.decodeSingularBoolField(value: &v) if let v = v { if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} - self.payloadVariant = .confirmSetModuleConfig(v) + self.payloadVariant = .commitEditSettings(v) } }() case 66: try { @@ -1089,12 +1091,12 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat guard case .setCannedMessageModuleMessages(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularStringField(value: v, fieldNumber: 36) }() - case .confirmSetConfig?: try { - guard case .confirmSetConfig(let v)? = self.payloadVariant else { preconditionFailure() } + case .beginEditSettings?: try { + guard case .beginEditSettings(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularBoolField(value: v, fieldNumber: 64) }() - case .confirmSetModuleConfig?: try { - guard case .confirmSetModuleConfig(let v)? = self.payloadVariant else { preconditionFailure() } + case .commitEditSettings?: try { + guard case .commitEditSettings(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularBoolField(value: v, fieldNumber: 65) }() case .confirmSetChannel?: try { diff --git a/Meshtastic/Protobufs/config.pb.swift b/Meshtastic/Protobufs/config.pb.swift index 1bdbd1eb..ebd95f47 100644 --- a/Meshtastic/Protobufs/config.pb.swift +++ b/Meshtastic/Protobufs/config.pb.swift @@ -158,6 +158,16 @@ struct Config { /// Set this to true to leave the debug log outputting even when API is active. var debugLogEnabled: Bool = false + /// + /// For boards without a hard wired button, this is the pin number that will be used + /// Boards that have more than one button can swap the function with this one. defaults to BUTTON_PIN if defined. + var buttonGpio: UInt32 = 0 + + /// + /// For boards without a PWM buzzer, this is the pin number that will be used + /// Defaults to PIN_BUZZER if defined. + var buzzerGpio: UInt32 = 0 + var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -259,6 +269,14 @@ struct Config { /// (bitwise OR of PositionFlags) var positionFlags: UInt32 = 0 + /// + /// (Re)define GPS_RX_PIN for your board. + var rxGpio: UInt32 = 0 + + /// + /// (Re)define GPS_TX_PIN for your board. + var txGpio: UInt32 = 0 + var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -1346,6 +1364,8 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl 1: .same(proto: "role"), 2: .standard(proto: "serial_enabled"), 3: .standard(proto: "debug_log_enabled"), + 4: .standard(proto: "button_gpio"), + 5: .standard(proto: "buzzer_gpio"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1357,6 +1377,8 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl case 1: try { try decoder.decodeSingularEnumField(value: &self.role) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }() + case 4: try { try decoder.decodeSingularUInt32Field(value: &self.buttonGpio) }() + case 5: try { try decoder.decodeSingularUInt32Field(value: &self.buzzerGpio) }() default: break } } @@ -1372,6 +1394,12 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl if self.debugLogEnabled != false { try visitor.visitSingularBoolField(value: self.debugLogEnabled, fieldNumber: 3) } + if self.buttonGpio != 0 { + try visitor.visitSingularUInt32Field(value: self.buttonGpio, fieldNumber: 4) + } + if self.buzzerGpio != 0 { + try visitor.visitSingularUInt32Field(value: self.buzzerGpio, fieldNumber: 5) + } try unknownFields.traverse(visitor: &visitor) } @@ -1379,6 +1407,8 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl if lhs.role != rhs.role {return false} if lhs.serialEnabled != rhs.serialEnabled {return false} if lhs.debugLogEnabled != rhs.debugLogEnabled {return false} + if lhs.buttonGpio != rhs.buttonGpio {return false} + if lhs.buzzerGpio != rhs.buzzerGpio {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -1403,6 +1433,8 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 5: .standard(proto: "gps_update_interval"), 6: .standard(proto: "gps_attempt_time"), 7: .standard(proto: "position_flags"), + 8: .standard(proto: "rx_gpio"), + 9: .standard(proto: "tx_gpio"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1418,6 +1450,8 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm case 5: try { try decoder.decodeSingularUInt32Field(value: &self.gpsUpdateInterval) }() case 6: try { try decoder.decodeSingularUInt32Field(value: &self.gpsAttemptTime) }() case 7: try { try decoder.decodeSingularUInt32Field(value: &self.positionFlags) }() + case 8: try { try decoder.decodeSingularUInt32Field(value: &self.rxGpio) }() + case 9: try { try decoder.decodeSingularUInt32Field(value: &self.txGpio) }() default: break } } @@ -1445,6 +1479,12 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if self.positionFlags != 0 { try visitor.visitSingularUInt32Field(value: self.positionFlags, fieldNumber: 7) } + if self.rxGpio != 0 { + try visitor.visitSingularUInt32Field(value: self.rxGpio, fieldNumber: 8) + } + if self.txGpio != 0 { + try visitor.visitSingularUInt32Field(value: self.txGpio, fieldNumber: 9) + } try unknownFields.traverse(visitor: &visitor) } @@ -1456,6 +1496,8 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if lhs.gpsUpdateInterval != rhs.gpsUpdateInterval {return false} if lhs.gpsAttemptTime != rhs.gpsAttemptTime {return false} if lhs.positionFlags != rhs.positionFlags {return false} + if lhs.rxGpio != rhs.rxGpio {return false} + if lhs.txGpio != rhs.txGpio {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Meshtastic/Protobufs/module_config.pb.swift b/Meshtastic/Protobufs/module_config.pb.swift index 4911431e..9de93522 100644 --- a/Meshtastic/Protobufs/module_config.pb.swift +++ b/Meshtastic/Protobufs/module_config.pb.swift @@ -474,7 +474,6 @@ struct ModuleConfig { /// /// Preferences for the ExternalNotificationModule - /// FIXME - Move this out of UserPreferences and into a section for module configuration. var enabled: Bool = false /// @@ -497,6 +496,10 @@ struct ModuleConfig { /// TODO: REPLACE var alertBell: Bool = false + /// + /// TODO: REPLACE + var usePwm: Bool = false + var unknownFields = SwiftProtobuf.UnknownStorage() init() {} @@ -1228,6 +1231,7 @@ extension ModuleConfig.ExternalNotificationConfig: SwiftProtobuf.Message, SwiftP 4: .same(proto: "active"), 5: .standard(proto: "alert_message"), 6: .standard(proto: "alert_bell"), + 7: .standard(proto: "use_pwm"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1242,6 +1246,7 @@ extension ModuleConfig.ExternalNotificationConfig: SwiftProtobuf.Message, SwiftP case 4: try { try decoder.decodeSingularBoolField(value: &self.active) }() case 5: try { try decoder.decodeSingularBoolField(value: &self.alertMessage) }() case 6: try { try decoder.decodeSingularBoolField(value: &self.alertBell) }() + case 7: try { try decoder.decodeSingularBoolField(value: &self.usePwm) }() default: break } } @@ -1266,6 +1271,9 @@ extension ModuleConfig.ExternalNotificationConfig: SwiftProtobuf.Message, SwiftP if self.alertBell != false { try visitor.visitSingularBoolField(value: self.alertBell, fieldNumber: 6) } + if self.usePwm != false { + try visitor.visitSingularBoolField(value: self.usePwm, fieldNumber: 7) + } try unknownFields.traverse(visitor: &visitor) } @@ -1276,6 +1284,7 @@ extension ModuleConfig.ExternalNotificationConfig: SwiftProtobuf.Message, SwiftP if lhs.active != rhs.active {return false} if lhs.alertMessage != rhs.alertMessage {return false} if lhs.alertBell != rhs.alertBell {return false} + if lhs.usePwm != rhs.usePwm {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index bae08710..738989d2 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -91,9 +91,9 @@ struct MQTTConfig: View { let totalBytes = username.utf8.count // Only mess with the value if it is too big - if totalBytes > 30 { + if totalBytes > 62 { - let firstNBytes = Data(username.utf8.prefix(30)) + let firstNBytes = Data(username.utf8.prefix(62)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { @@ -120,9 +120,9 @@ struct MQTTConfig: View { let totalBytes = password.utf8.count // Only mess with the value if it is too big - if totalBytes > 30 { + if totalBytes > 62 { - let firstNBytes = Data(password.utf8.prefix(30)) + let firstNBytes = Data(password.utf8.prefix(62)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { diff --git a/MeshtasticTests/MeshtasticAppleTests.swift b/MeshtasticTests/MeshtasticAppleTests.swift deleted file mode 100644 index 08bed2c3..00000000 --- a/MeshtasticTests/MeshtasticAppleTests.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// MeshtasticAppleTests.swift -// MeshtasticAppleTests -// -// Created by Garth Vander Houwen on 8/18/21. -// - -import XCTest - -@testable import MeshtasticApple - -class MeshtasticAppleTests: XCTestCase { - - override func setUpWithError() throws { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/MeshtasticUITests/MeshtasticAppleUITests.swift b/MeshtasticUITests/MeshtasticAppleUITests.swift deleted file mode 100644 index 1d6dbac7..00000000 --- a/MeshtasticUITests/MeshtasticAppleUITests.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// MeshtasticAppleUITests.swift -// MeshtasticAppleUITests -// -// Created by Garth Vander Houwen on 8/18/21. -// - -import XCTest - -class MeshtasticAppleUITests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // UI tests must launch the application that they test. - let app = XCUIApplication() - app.launch() - - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTApplicationLaunchMetric()]) { - XCUIApplication().launch() - } - } - } -} diff --git a/MeshtasticUITests/MeshtasticUITests.swift b/MeshtasticUITests/MeshtasticUITests.swift index 1a1ed582..ae140de9 100644 --- a/MeshtasticUITests/MeshtasticUITests.swift +++ b/MeshtasticUITests/MeshtasticUITests.swift @@ -2,7 +2,7 @@ // MeshtasticUITests.swift // MeshtasticUITests // -// Created by Garth Vander Houwen on 8/18/21. +// Copyright(c) Garth Vander Houwen 8/18/21. // import XCTest @@ -32,7 +32,7 @@ class MeshtasticUITests: XCTestCase { } func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { + if #available(macOS 13, iOS 16.0, watchOS 8.0, *) { // This measures how long it takes to launch your application. measure(metrics: [XCTApplicationLaunchMetric()]) { XCUIApplication().launch()