Add cal topo, wip firmware page

This commit is contained in:
Garth Vander Houwen 2023-12-30 09:21:42 -08:00
parent abe0dbb93d
commit a3ef868802
7 changed files with 218 additions and 158 deletions

View file

@ -29,6 +29,7 @@
DD2553592855B52700E55709 /* PositionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2553582855B52700E55709 /* PositionConfig.swift */; };
DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */; };
DD2DC2C029BCD8AB003B383C /* HardwareModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2DC2BF29BCD8AB003B383C /* HardwareModels.swift */; };
DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */; };
DD3501892852FC3B000FC853 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3501882852FC3B000FC853 /* Settings.swift */; };
DD3619152B1EF9F900C41C8C /* LocationsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */; };
DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6B428E33FD100FA9159 /* ShareChannels.swift */; };
@ -247,6 +248,8 @@
DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = "<group>"; };
DD2CC2E52ABFE04E00EDFDA7 /* MeshtasticDataModelV19.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV19.xcdatamodel; sourceTree = "<group>"; };
DD2DC2BF29BCD8AB003B383C /* HardwareModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardwareModels.swift; sourceTree = "<group>"; };
DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 23.xcdatamodel"; sourceTree = "<group>"; };
DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirmwareApi.swift; sourceTree = "<group>"; };
DD3501882852FC3B000FC853 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
DD3619132B1EE20700C41C8C /* MeshtasticDataModelV21.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV21.xcdatamodel; sourceTree = "<group>"; };
DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsHandler.swift; sourceTree = "<group>"; };
@ -550,6 +553,7 @@
DDE9659B2B1C3B6A00531070 /* RouteRecorder.swift */,
DDA0B6B1294CDC55001356EC /* Channels.swift */,
DDD6EEAE29BC024700383354 /* Firmware.swift */,
DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */,
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */,
DD86D40B287F401000BAEB7A /* SaveChannelQRCode.swift */,
DD3501882852FC3B000FC853 /* Settings.swift */,
@ -1190,6 +1194,7 @@
DDDB444A29F8AA3A00EE2349 /* CLLocationCoordinate2D.swift in Sources */,
DD41582628582E9B009B0E59 /* DeviceConfig.swift in Sources */,
DD007BAE2AA4E91200F5FA12 /* MyInfoEntityExtension.swift in Sources */,
DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */,
DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */,
DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */,
DD5E5207298EE33B00D21B61 /* connection_status.pb.swift in Sources */,
@ -1790,6 +1795,7 @@
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */,
DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */,
DD3619132B1EE20700C41C8C /* MeshtasticDataModelV21.xcdatamodel */,
DDAB580B2B0D913500147258 /* MeshtasticDataModelV20.xcdatamodel */,
@ -1813,7 +1819,7 @@
DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */,
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */,
);
currentVersion = DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */;
currentVersion = DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */;
name = Meshtastic.xcdatamodeld;
path = Meshtastic/Meshtastic.xcdatamodeld;
sourceTree = "<group>";

View file

@ -111,6 +111,7 @@ enum SerialModeTypes: Int, CaseIterable, Identifiable {
case proto = 2
case txtmsg = 3
case nmea = 4
case caltopo = 5
var id: Int { self.rawValue }
var description: String {
@ -125,6 +126,8 @@ enum SerialModeTypes: Int, CaseIterable, Identifiable {
return "serial.mode.txtmsg".localized
case .nmea:
return "serial.mode.nmea".localized
case .caltopo:
return "serial.mode.caltopo".localized
}
}
func protoEnumValue() -> ModuleConfig.SerialConfig.Serial_Mode {
@ -141,6 +144,8 @@ enum SerialModeTypes: Int, CaseIterable, Identifiable {
return ModuleConfig.SerialConfig.Serial_Mode.textmsg
case .nmea:
return ModuleConfig.SerialConfig.Serial_Mode.nmea
case .caltopo:
return ModuleConfig.SerialConfig.Serial_Mode.caltopo
}
}
}

View file

@ -759,16 +759,15 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
if UserDefaults.provideLocation {
let interval = UserDefaults.provideLocationInterval > 0 ? UserDefaults.provideLocationInterval : 30
if positionTimer != nil {
}
positionTimer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(positionTimerFired), userInfo: context, repeats: true)
if positionTimer != nil {
RunLoop.current.add(positionTimer!, forMode: .common)
positionTimer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(positionTimerFired), userInfo: context, repeats: true)
if positionTimer != nil {
RunLoop.current.add(positionTimer!, forMode: .common)
}
}
}
return
}
case FROMNUM_UUID:
print("🗞️ BLE (Notify) characteristic, value will be read next")

View file

@ -309,6 +309,7 @@
<attribute name="echo" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="overrideConsoleSerialPort" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="rxd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="timeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="txd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>

View file

@ -23,7 +23,10 @@ struct SerialConfig: View {
@State var txd = 0
@State var baudRate = 0
@State var timeout = 0
@State var overrideConsoleSerialPort = false
@State var mode = 0
var body: some View {
VStack {
@ -153,6 +156,7 @@ struct SerialConfig: View {
sc.txd = UInt32(txd)
sc.baud = SerialBaudRates(rawValue: baudRate)!.protoEnumValue()
sc.timeout = UInt32(timeout)
sc.overrideConsoleSerialPort = overrideConsoleSerialPort
sc.mode = SerialModeTypes(rawValue: mode)!.protoEnumValue()
let adminMessageId = bleManager.saveSerialModuleConfig(config: sc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
@ -231,6 +235,13 @@ struct SerialConfig: View {
if newTimeout != node!.serialConfig!.timeout { hasChanges = true }
}
}
.onChange(of: overrideConsoleSerialPort) { newOverrideConsoleSerialPort in
if node != nil && node!.serialConfig != nil {
if newOverrideConsoleSerialPort != node!.serialConfig!.overrideConsoleSerialPort { hasChanges = true }
}
}
.onChange(of: mode) { newMode in
if node != nil && node!.serialConfig != nil {
@ -248,6 +259,7 @@ struct SerialConfig: View {
self.baudRate = Int(node?.serialConfig?.baudRate ?? 0)
self.timeout = Int(node?.serialConfig?.timeout ?? 0)
self.mode = Int(node?.serialConfig?.mode ?? 0)
self.overrideConsoleSerialPort = false // node?.serialConfig?.overrideConsoleSerialPort ?? false
self.hasChanges = false
}
}

View file

@ -18,12 +18,13 @@ struct Firmware: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
var node: NodeInfoEntity?
@State var minimumVersion = "2.1.0"
@State var minimumVersion = "2.2.16"
@State var version = ""
@State private var firmwareReleaseData: FirmwareRelease = FirmwareRelease()
//var currentDevice: DeviceHardware
var body: some View {
// NavigationSplitView {
NavigationStack {
VStack {
let hwModel: HardwareModels = HardwareModels.allCases.first(where: { $0.rawValue == node?.user?.hwModel ?? "UNSET" }) ?? HardwareModels.UNSET
VStack(alignment: .leading) {
Text("Current Version: \(bleManager.connectedVersion)")
@ -91,166 +92,163 @@ struct Firmware: View {
Text(hwModel.platform().description)
.font(.title3)
}
}.padding()
}
Spacer()
VStack(alignment: .leading) {
Text("Firmware Releases")
.font(.title3)
.padding([.leading, .trailing])
List {
Section(header: Text("Stable")) {
ForEach(firmwareReleaseData.releases?.stable ?? [], id: \.id) { fr in
Link(destination: URL(string: fr.zipUrl ?? "")!) {
HStack {
Text(fr.title ?? "Unknown")
.font(.caption)
Spacer()
Image(systemName: "square.and.arrow.down")
.font(.title3)
}
}
}
}
Section("Alpha") {
ForEach(firmwareReleaseData.releases?.alpha ?? [], id: \.id) { fr in
Link(destination: URL(string: fr.zipUrl ?? "")!) {
HStack {
Text(fr.title ?? "Unknown")
.font(.caption)
Spacer()
Image(systemName: "square.and.arrow.down")
.font(.title3)
}
}
}
}
Section("Pull Requests") {
ForEach(firmwareReleaseData.pullRequests ?? [], id: \.id) { fr in
Link(destination: URL(string: fr.zipUrl ?? "")!) {
HStack {
Text(fr.title ?? "Unknown")
.font(.caption)
Spacer()
Image(systemName: "square.and.arrow.down")
.font(.title3)
}
}
// List {
// Section(header: Text("Stable")) {
// ForEach(firmwareReleaseData.releases?.stable ?? [], id: \.id) { fr in
// Link(destination: URL(string: fr.zipUrl ?? "")!) {
// HStack {
// Text(fr.title ?? "Unknown")
// .font(.caption)
// Spacer()
// Image(systemName: "square.and.arrow.down")
// .font(.title3)
// }
// }
// }
// }
// Section("Alpha") {
// ForEach(firmwareReleaseData.releases?.alpha ?? [], id: \.id) { fr in
// Link(destination: URL(string: fr.zipUrl ?? "")!) {
// HStack {
// Text(fr.title ?? "Unknown")
// .font(.caption)
// Spacer()
// Image(systemName: "square.and.arrow.down")
// .font(.title3)
// }
// }
// }
// }
// Section("Pull Requests") {
// ForEach(firmwareReleaseData.pullRequests ?? [], id: \.id) { fr in
// Link(destination: URL(string: fr.zipUrl ?? "")!) {
// HStack {
// Text(fr.title ?? "Unknown")
// .font(.caption)
// Spacer()
// Image(systemName: "square.and.arrow.down")
// .font(.title3)
// }
// }
// }
// }
// }
}
.padding(.bottom, 5)
.onAppear() {
Api().loadDeviceHardwareData { (hw) in
for device in hw {
if device.hwModelSlug == node?.user?.hwModel ?? "UNSET" {
print("Selected: \(device)")
}
}
}
// Api().loadFirmwareReleaseData { (bks) in
// //sel = bks
// }
}
.padding(.bottom, 5)
.onAppear(perform: loadData)
.navigationTitle("Firmware Updates")
.navigationBarTitleDisplayMode(.inline)
}
}
func loadData() {
guard let url = URL(string: "https://api.meshtastic.org/github/firmware/list") else {
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, _, _ in
if let data = data {
if let response_obj = try? JSONDecoder().decode(FirmwareRelease.self, from: data) {
DispatchQueue.main.async {
self.firmwareReleaseData = response_obj
}
}
}
}.resume()
}
}
struct FirmwareRelease: Codable {
var releases: Releases? = Releases()
var pullRequests: [PullRequests]? = []
enum CodingKeys: String, CodingKey {
case releases = "Releases"
case pullRequests = "Pull Requests"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
releases = try values.decodeIfPresent(Releases.self, forKey: .releases )
pullRequests = try values.decodeIfPresent([PullRequests].self, forKey: .pullRequests )
}
init() {
}
}
struct Releases: Codable {
var stable: [Stable]? = []
var alpha: [Alpha]? = []
enum CodingKeys: String, CodingKey {
case stable = "Stable"
case alpha = "Alpha"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
stable = try values.decodeIfPresent([Stable].self, forKey: .stable )
alpha = try values.decodeIfPresent([Alpha].self, forKey: .alpha )
}
init() {}
}
struct Alpha: Codable {
var id: String?
var title: String?
var pageUrl: String?
var zipUrl: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case title = "title"
case pageUrl = "page_url"
case zipUrl = "zip_url"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(String.self, forKey: .id )
title = try values.decodeIfPresent(String.self, forKey: .title )
pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
}
init() {}
}
struct Stable: Codable {
var id: String?
var title: String?
var pageUrl: String?
var zipUrl: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case title = "title"
case pageUrl = "page_url"
case zipUrl = "zip_url"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(String.self, forKey: .id )
title = try values.decodeIfPresent(String.self, forKey: .title )
pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
}
init() {}
}
struct PullRequests: Codable {
var id: String?
var title: String?
var pageUrl: String?
var zipUrl: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case title = "title"
case pageUrl = "page_url"
case zipUrl = "zip_url"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(String.self, forKey: .id )
title = try values.decodeIfPresent(String.self, forKey: .title )
pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
}
init() {}
}
//struct FirmwareRelease: Codable {
// var releases: Releases? = Releases()
// var pullRequests: [PullRequests]? = []
// enum CodingKeys: String, CodingKey {
// case releases = "Releases"
// case pullRequests = "Pull Requests"
// }
// init(from decoder: Decoder) throws {
// let values = try decoder.container(keyedBy: CodingKeys.self)
// releases = try values.decodeIfPresent(Releases.self, forKey: .releases )
// pullRequests = try values.decodeIfPresent([PullRequests].self, forKey: .pullRequests )
// }
// init() {
// }
//}
//
//struct Releases: Codable {
// var stable: [Stable]? = []
// var alpha: [Alpha]? = []
// enum CodingKeys: String, CodingKey {
// case stable = "Stable"
// case alpha = "Alpha"
// }
// init(from decoder: Decoder) throws {
// let values = try decoder.container(keyedBy: CodingKeys.self)
// stable = try values.decodeIfPresent([Stable].self, forKey: .stable )
// alpha = try values.decodeIfPresent([Alpha].self, forKey: .alpha )
// }
// init() {}
//}
//
//struct Alpha: Codable {
// var id: String?
// var title: String?
// var pageUrl: String?
// var zipUrl: String?
// enum CodingKeys: String, CodingKey {
// case id = "id"
// case title = "title"
// case pageUrl = "page_url"
// case zipUrl = "zip_url"
// }
// init(from decoder: Decoder) throws {
// let values = try decoder.container(keyedBy: CodingKeys.self)
// id = try values.decodeIfPresent(String.self, forKey: .id )
// title = try values.decodeIfPresent(String.self, forKey: .title )
// pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
// zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
// }
// init() {}
//}
//
//struct Stable: Codable {
// var id: String?
// var title: String?
// var pageUrl: String?
// var zipUrl: String?
// enum CodingKeys: String, CodingKey {
// case id = "id"
// case title = "title"
// case pageUrl = "page_url"
// case zipUrl = "zip_url"
// }
// init(from decoder: Decoder) throws {
// let values = try decoder.container(keyedBy: CodingKeys.self)
// id = try values.decodeIfPresent(String.self, forKey: .id )
// title = try values.decodeIfPresent(String.self, forKey: .title )
// pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
// zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
// }
// init() {}
//}
//
//struct PullRequests: Codable {
// var id: String?
// var title: String?
// var pageUrl: String?
// var zipUrl: String?
// enum CodingKeys: String, CodingKey {
// case id = "id"
// case title = "title"
// case pageUrl = "page_url"
// case zipUrl = "zip_url"
// }
// init(from decoder: Decoder) throws {
// let values = try decoder.container(keyedBy: CodingKeys.self)
// id = try values.decodeIfPresent(String.self, forKey: .id )
// title = try values.decodeIfPresent(String.self, forKey: .title )
// pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
// zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
// }
// init() {}
//}

View file

@ -6,3 +6,42 @@
//
import Foundation
struct DeviceHardware: Codable {
var hwModel: Int
var hwModelSlug: String
var platformioTarget: String
var activelySupported: Bool
var displayName: String
}
class Api : ObservableObject{
// @Published var devices = [DeviceHardware]()
func loadDeviceHardwareData(completion:@escaping ([DeviceHardware]) -> ()) {
guard let url = URL(string: "https://api.meshtastic.org/resource/deviceHardware") else {
print("Invalid url...")
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
let deviceHardware = try! JSONDecoder().decode([DeviceHardware].self, from: data!)
print(deviceHardware)
DispatchQueue.main.async {
completion(deviceHardware)
}
}.resume()
}
// func loadFirmwareReleaseData(completion:@escaping ([FirmwareRelease]) -> ()) {
// guard let url = URL(string: "https://api.meshtastic.org/github/firmware/list") else {
// print("Invalid url...")
// return
// }
// URLSession.shared.dataTask(with: url) { data, response, error in
// let deviceHardware = try! JSONDecoder().decode([FirmwareRelease].self, from: data!)
// print(deviceHardware)
// DispatchQueue.main.async {
// completion(deviceHardware)
// }
// }.resume()
// }
}