2021-09-10 07:41:26 -07:00
import Foundation
2021-09-12 17:51:10 -07:00
import CoreData
2021-09-10 07:41:26 -07:00
import CoreBluetooth
2021-09-14 21:38:12 -07:00
import SwiftUI
2022-01-04 22:57:33 -08:00
import MapKit
2021-09-10 07:41:26 -07:00
2021-11-29 15:59:06 -08:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-09-10 21:50:54 -07:00
// M e s h t a s t i c B L E D e v i c e M a n a g e r
2021-11-29 15:59:06 -08:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-09-10 21:50:54 -07:00
class BLEManager : NSObject , ObservableObject , CBCentralManagerDelegate , CBPeripheralDelegate {
2021-11-29 15:59:06 -08:00
2021-12-12 17:17:46 -08:00
static let shared = BLEManager ( )
2021-12-25 23:48:12 -08:00
2021-10-20 00:31:22 -07:00
private static var documentsFolder : URL {
do {
2021-12-12 17:17:46 -08:00
return try FileManager . default . url ( for : . documentDirectory , in : . userDomainMask , appropriateFor : nil , create : true )
2021-10-20 00:31:22 -07:00
} catch {
fatalError ( " Can't find documents directory. " )
}
}
2021-12-25 23:48:12 -08:00
2021-12-12 17:17:46 -08:00
var context : NSManagedObjectContext ?
2022-02-22 09:08:06 -10:00
var userSettings : UserSettings ?
2021-12-25 23:48:12 -08:00
2021-12-12 17:17:46 -08:00
private var centralManager : CBCentralManager !
2021-12-25 23:48:12 -08:00
2022-10-22 07:35:55 -07:00
@ Published var peripherals : [ Peripheral ]
2022-09-28 15:50:35 -07:00
@ Published var connectedPeripheral : Peripheral !
@ Published var lastConnectionError : String
2022-10-26 09:08:03 -07:00
@ Published var minimumVersion = " 1.3.48 "
2022-08-06 08:07:16 -07:00
@ Published var connectedVersion : String
2022-09-27 06:33:00 -07:00
@ Published var invalidVersion = false
@ Published var preferredPeripheral = false
2021-11-29 15:59:06 -08:00
2021-11-21 13:48:28 -08:00
@ Published var isSwitchedOn : Bool = false
@ Published var isScanning : Bool = false
2022-10-12 15:26:25 -07:00
@ Published var isConnecting : Bool = false
2021-11-21 13:48:28 -08:00
@ Published var isConnected : Bool = false
2022-10-18 13:53:50 -07:00
@ Published var isSubscribed : Bool = false
2022-06-11 09:50:25 -07:00
// / U s e d t o m a k e s u r e w e n e v e r g e t f o o l d b y o l d B L E p a c k e t s
private var configNonce : UInt32 = 1
2021-11-29 15:59:06 -08:00
2021-10-22 10:03:50 -07:00
var timeoutTimer : Timer ?
2021-10-27 20:31:20 -07:00
var timeoutTimerCount = 0
2022-02-22 09:08:06 -10:00
var positionTimer : Timer ?
2022-10-15 01:00:13 -07:00
let broadcastNodeNum : UInt32 = 4294967295
2021-10-12 17:54:10 -07:00
2022-09-28 15:50:35 -07:00
/* M e s h t a s t i c S e r v i c e D e t a i l s */
var TORADIO_characteristic : CBCharacteristic !
var FROMRADIO_characteristic : CBCharacteristic !
var FROMNUM_characteristic : CBCharacteristic !
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
let meshtasticServiceCBUUID = CBUUID ( string : " 0x6BA1B218-15A8-461F-9FA8-5DCAE273EAFD " )
let TORADIO_UUID = CBUUID ( string : " 0xF75C76D2-129E-4DAD-A1DD-7866124401E7 " )
2022-10-13 14:08:36 -07:00
let FROMRADIO_UUID = CBUUID ( string : " 0x2C55E69E-4993-11ED-B878-0242AC120002 " )
2022-10-11 14:25:59 -07:00
let EOL_FROMRADIO_UUID = CBUUID ( string : " 0x8BA2BCC2-EE02-4A55-A531-C525C5E454D5 " )
2022-09-28 15:50:35 -07:00
let FROMNUM_UUID = CBUUID ( string : " 0xED9DA18C-A800-4F66-A670-AA7547E34453 " )
2022-07-01 19:44:25 -07:00
// M e s h t a s t i c D F U d e t a i l s
let DFUSERVICE_UUID = CBUUID ( string : " cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30 " )
let DFUSIZE_UUID = CBUUID ( string : " e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e " )
let DFUDATA_UUID = CBUUID ( string : " e272ebac-d463-4b98-bc84-5cc1a39ee517 " )
let DFUCRC32_UUID = CBUUID ( string : " 4826129c-c22a-43a3-b066-ce8f0d5bacc6 " )
let DFURESULT_UUID = CBUUID ( string : " 5e134862-7411-4424-ac4a-210937432c77 " )
let DFUREGION_UUID = CBUUID ( string : " 5e134862-7411-4424-ac4a-210937432c67 " )
var DFUSIZE_characteristic : CBCharacteristic ?
var DFUDATA_characteristic : CBCharacteristic ?
var DFUCRC32_characteristic : CBCharacteristic ?
var DFURESULT_characteristic : CBCharacteristic ?
var DFUREGION_characteristic : CBCharacteristic ?
2021-12-25 23:48:12 -08:00
2022-10-15 10:14:08 -07:00
// p r i v a t e v a r m e s h L o g g i n g E n a b l e d : B o o l = t r u e
2021-10-20 00:31:22 -07:00
let meshLog = documentsFolder . appendingPathComponent ( " meshlog.txt " )
2021-12-25 23:48:12 -08:00
2022-09-28 15:50:35 -07:00
// MARK: i n i t B L E M a n a g e r
override init ( ) {
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
self . lastConnectionError = " "
2022-08-06 08:07:16 -07:00
self . connectedVersion = " 0.0.0 "
2022-10-22 07:35:55 -07:00
self . peripherals = [ Peripheral ] ( )
2022-09-28 15:50:35 -07:00
super . init ( )
2021-12-25 23:48:12 -08:00
// l e t b l e Q u e u e : D i s p a t c h Q u e u e = D i s p a t c h Q u e u e ( l a b e l : " C e n t r a l M a n a g e r " )
2022-09-28 15:50:35 -07:00
centralManager = CBCentralManager ( delegate : self , queue : nil )
}
2021-09-10 07:41:26 -07:00
2021-12-12 17:17:46 -08:00
// MARK: B l u e t o o t h e n a b l e d / d i s a b l e d f o r t h e a p p
2022-09-28 15:50:35 -07:00
func centralManagerDidUpdateState ( _ central : CBCentralManager ) {
if central . state = = . poweredOn {
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
isSwitchedOn = true
2021-11-21 13:48:28 -08:00
startScanning ( )
2022-09-28 15:50:35 -07:00
} else {
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
isSwitchedOn = false
}
}
2021-11-29 15:59:06 -08:00
2021-12-12 17:17:46 -08:00
// MARK: S c a n n i n g f o r B L E D e v i c e s
2022-09-28 15:50:35 -07:00
// S c a n f o r n e a r b y B L E d e v i c e s u s i n g t h e M e s h t a s t i c B L E s e r v i c e I D
func startScanning ( ) {
if isSwitchedOn {
centralManager . scanForPeripherals ( withServices : [ meshtasticServiceCBUUID ] , options : nil )
2022-10-22 07:35:55 -07:00
DispatchQueue . main . async {
self . isScanning = self . centralManager . isScanning
}
2022-09-28 15:50:35 -07:00
print ( " ✅ Scanning Started " )
}
}
2021-11-29 15:59:06 -08:00
2021-12-12 17:17:46 -08:00
// S t o p S c a n n i n g F o r B L E D e v i c e s
2022-09-28 15:50:35 -07:00
func stopScanning ( ) {
if centralManager . isScanning {
centralManager . stopScan ( )
2022-10-22 07:35:55 -07:00
DispatchQueue . main . async {
self . isScanning = self . centralManager . isScanning
}
2022-09-28 15:50:35 -07:00
print ( " 🛑 Stopped Scanning " )
}
}
2021-11-29 15:59:06 -08:00
2021-12-12 17:17:46 -08:00
// MARK: B L E C o n n e c t f u n c t i o n s
2021-10-22 10:03:50 -07:00
// / T h e a c t i o n a f t e r t h e t i m e o u t - t i m e r h a s f i r e d
// /
// / - P a r a m e t e r s :
// / - t i m e r : T h e t i m e t h a t f i r e d t h e e v e n t
// /
2021-11-29 15:59:06 -08:00
@objc func timeoutTimerFired ( timer : Timer ) {
2021-12-15 23:53:45 -08:00
guard let timerContext = timer . userInfo as ? [ String : String ] else { return }
let name : String = timerContext [ " name " , default : " Unknown " ]
2021-11-29 15:59:06 -08:00
2021-10-28 00:15:47 -07:00
self . timeoutTimerCount += 1
2022-10-12 15:26:25 -07:00
self . lastConnectionError = " "
2021-10-22 20:58:20 -07:00
2022-08-23 07:59:15 -07:00
if timeoutTimerCount = = 10 {
2021-11-04 08:36:55 -07:00
if connectedPeripheral != nil {
2021-10-22 20:58:20 -07:00
self . centralManager ? . cancelPeripheralConnection ( connectedPeripheral . peripheral )
}
2021-11-04 08:36:55 -07:00
connectedPeripheral = nil
2022-08-11 23:34:09 -07:00
if self . timeoutTimer != nil {
self . timeoutTimer ! . invalidate ( )
}
2022-10-12 15:26:25 -07:00
self . isConnected = false
self . isConnecting = false
2022-10-12 15:46:53 -07:00
self . lastConnectionError = " 🚨 Connection failed after \( timeoutTimerCount ) attempts to connect to \( name ) . You may need to forget your device under Settings > Bluetooth. "
2022-10-15 10:14:08 -07:00
MeshLogger . log ( lastConnectionError )
2022-10-12 15:26:25 -07:00
self . timeoutTimerCount = 0
self . startScanning ( )
2021-11-29 15:59:06 -08:00
} else {
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🚨 BLE Connecting 2 Second Timeout Timer Fired \( timeoutTimerCount ) Time(s): \( name ) " )
2021-10-22 10:03:50 -07:00
}
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// C o n n e c t t o a s p e c i f i c p e r i p h e r a l
func connectTo ( peripheral : CBPeripheral ) {
stopScanning ( )
2022-10-22 07:35:55 -07:00
DispatchQueue . main . async {
self . isConnecting = true
self . lastConnectionError = " "
}
2022-10-12 16:09:55 -07:00
if connectedPeripheral != nil {
MeshLogger . log ( " ℹ ️ BLE Disconnecting from: \( connectedPeripheral . name ) to connect to \( peripheral . name ? ? " Unknown " ) " )
disconnectPeripheral ( )
2022-09-28 15:50:35 -07:00
}
2022-10-12 16:09:55 -07:00
centralManager ? . connect ( peripheral )
2022-08-04 23:03:46 -06:00
// I n v a l i d a t e a n y e x i s t i n g t i m e r
2022-10-12 16:09:55 -07:00
if timeoutTimer != nil {
timeoutTimer ! . invalidate ( )
2022-08-11 23:34:09 -07:00
}
2021-10-23 10:27:10 -07:00
// U s e a t i m e r t o k e e p t r a c k o f c o n n e c t i n g p e r i p h e r a l s , c o n t e x t t o p a s s t h e r a d i o n a m e w i t h t h e t i m e r a n d t h e R u n L o o p t o p r e v e n t
// t h e t i m e r f r o m r u n n i n g o n t h e m a i n U I t h r e a d
2022-10-12 15:46:53 -07:00
let context = [ " name " : " \( peripheral . name ? ? " Unknown " ) " ]
2022-10-12 16:09:55 -07:00
timeoutTimer = Timer . scheduledTimer ( timeInterval : 1.5 , target : self , selector : #selector ( timeoutTimerFired ) , userInfo : context , repeats : true )
RunLoop . current . add ( timeoutTimer ! , forMode : . common )
MeshLogger . log ( " ℹ ️ BLE Connecting: \( peripheral . name ? ? " Unknown " ) " )
2022-09-28 15:50:35 -07:00
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// D i s c o n n e c t C o n n e c t e d P e r i p h e r a l
func disconnectPeripheral ( ) {
2021-11-29 15:59:06 -08:00
2021-11-21 13:48:28 -08:00
guard let connectedPeripheral = connectedPeripheral else { return }
2022-09-28 15:50:35 -07:00
centralManager ? . cancelPeripheralConnection ( connectedPeripheral . peripheral )
2022-10-11 14:25:59 -07:00
FROMRADIO_characteristic = nil
2022-09-28 15:50:35 -07:00
isConnected = false
2022-10-18 13:53:50 -07:00
isSubscribed = false
2022-09-28 15:50:35 -07:00
invalidVersion = false
connectedVersion = " 0.0.0 "
2022-10-12 16:09:55 -07:00
startScanning ( )
2022-09-28 15:50:35 -07:00
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// C a l l e d e a c h t i m e a p e r i p h e r a l i s d i s c o v e r e d
func centralManager ( _ central : CBCentralManager , didDiscover peripheral : CBPeripheral , advertisementData : [ String : Any ] , rssi RSSI : NSNumber ) {
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
var peripheralName : String = peripheral . name ? ? " Unknown "
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
if let name = advertisementData [ CBAdvertisementDataLocalNameKey ] as ? String {
peripheralName = name
}
2021-11-29 15:59:06 -08:00
2022-10-18 20:25:11 -07:00
let newPeripheral = Peripheral ( id : peripheral . identifier . uuidString , num : 0 , name : peripheralName , shortName : " ???? " , longName : peripheralName , firmwareVersion : " Unknown " , rssi : RSSI . intValue , lastUpdate : Date ( ) , peripheral : peripheral )
2021-10-22 10:03:50 -07:00
let peripheralIndex = peripherals . firstIndex ( where : { $0 . id = = newPeripheral . id } )
2021-10-27 21:15:36 -07:00
2021-11-20 11:02:15 -08:00
if peripheralIndex != nil && newPeripheral . peripheral . state != CBPeripheralState . connected {
2021-10-28 00:15:47 -07:00
2021-11-07 12:59:03 -08:00
peripherals [ peripheralIndex ! ] = newPeripheral
2021-11-20 11:02:15 -08:00
peripherals . remove ( at : peripheralIndex ! )
peripherals . append ( newPeripheral )
2021-12-25 23:48:12 -08:00
2021-11-29 15:59:06 -08:00
} else {
2022-03-04 04:16:45 -08:00
2021-11-21 13:48:28 -08:00
if newPeripheral . peripheral . state != CBPeripheralState . connected {
2021-11-29 15:59:06 -08:00
2021-11-21 13:48:28 -08:00
peripherals . append ( newPeripheral )
2021-12-21 00:33:22 -08:00
print ( " ℹ ️ Adding peripheral: \( peripheralName ) " )
2021-11-21 13:48:28 -08:00
}
2021-10-22 10:03:50 -07:00
}
2022-03-04 04:16:45 -08:00
2022-06-15 22:11:37 -07:00
let today = Date ( )
2022-09-28 15:50:35 -07:00
let visibleDuration = Calendar . current . date ( byAdding : . second , value : - 3 , to : today ) !
peripherals . removeAll ( where : { $0 . lastUpdate < visibleDuration } )
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// C a l l e d w h e n a p e r i p h e r a l i s c o n n e c t e d
func centralManager ( _ central : CBCentralManager , didConnect peripheral : CBPeripheral ) {
2022-10-22 07:41:40 -07:00
isConnecting = false
isConnected = true
2022-10-01 09:37:10 -07:00
if userSettings ? . preferredPeripheralId . count ? ? 0 < 1 {
2022-10-22 07:41:40 -07:00
userSettings ? . preferredPeripheralId = peripheral . identifier . uuidString
preferredPeripheral = true
2022-10-01 09:37:10 -07:00
} else if userSettings ! . preferredPeripheralId = = peripheral . identifier . uuidString {
2022-10-22 07:41:40 -07:00
preferredPeripheral = true
2022-10-01 09:37:10 -07:00
} else {
2022-10-22 07:49:39 -07:00
preferredPeripheral = false
2022-10-01 09:37:10 -07:00
print ( " Trying to connect a non prefered peripheral " )
}
2022-10-22 07:35:55 -07:00
// I n v a l i d a t e a n d r e s e t c o n n e c t i o n t i m e r c o u n t
2022-10-22 07:49:39 -07:00
timeoutTimerCount = 0
if timeoutTimer != nil {
timeoutTimer ! . invalidate ( )
2022-08-11 23:34:09 -07:00
}
2022-10-22 07:41:40 -07:00
2022-10-22 07:35:55 -07:00
// r e m o v e a n y c o n n e c t i o n e r r o r s
self . lastConnectionError = " "
2022-09-09 08:25:52 -07:00
// M a p t h e p e r i p h e r a l t o t h e c o n n e c t e d P e r i p h e r a l O b s e r v e d O b j e c t s
2022-09-28 15:50:35 -07:00
connectedPeripheral = peripherals . filter ( { $0 . peripheral . identifier = = peripheral . identifier } ) . first
2022-09-09 08:25:52 -07:00
if connectedPeripheral != nil {
connectedPeripheral . peripheral . delegate = self
}
else {
// w e a r e n u l l j u s t d i s c o n n e c t a n d s t a r t o v e r
2022-10-22 07:41:40 -07:00
lastConnectionError = " Bluetooth connection error, please try again. "
disconnectPeripheral ( )
2022-09-09 08:25:52 -07:00
return
}
2021-10-23 10:27:10 -07:00
// D i s c o v e r S e r v i c e s
2022-07-01 19:44:25 -07:00
peripheral . discoverServices ( [ meshtasticServiceCBUUID , DFUSERVICE_UUID ] )
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ✅ BLE Connected: \( peripheral . name ? ? " Unknown " ) " )
2022-09-28 15:50:35 -07:00
}
2021-11-29 15:59:06 -08:00
2021-12-12 17:17:46 -08:00
// C a l l e d w h e n a P e r i p h e r a l f a i l s t o c o n n e c t
2021-11-21 13:48:28 -08:00
func centralManager ( _ central : CBCentralManager , didFailToConnect peripheral : CBPeripheral , error : Error ? ) {
disconnectPeripheral ( )
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " 🚫 BLE Failed to Connect: \( peripheral . name ? ? " Unknown " ) " )
2021-11-21 13:48:28 -08:00
}
2021-09-10 21:50:54 -07:00
2022-09-28 15:50:35 -07:00
// D i s c o n n e c t P e r i p h e r a l E v e n t
func centralManager ( _ central : CBCentralManager , didDisconnectPeripheral peripheral : CBPeripheral , error : Error ? ) {
// S t a r t a s c a n s o t h e d i s c o n n e c t e d p e r i p h e r a l i s m o v e d t o t h e p e r i p h e r a l s [ ] i f i t i s a w a k e
self . startScanning ( )
2021-10-23 00:19:23 -07:00
self . connectedPeripheral = nil
2022-10-12 15:26:25 -07:00
self . isConnecting = false
2022-10-18 13:53:50 -07:00
self . isSubscribed = false
2022-09-28 15:50:35 -07:00
if let e = error {
2021-10-23 10:27:10 -07:00
// h t t p s : / / d e v e l o p e r . a p p l e . c o m / d o c u m e n t a t i o n / c o r e b l u e t o o t h / c b e r r o r / c o d e
2022-09-28 15:50:35 -07:00
let errorCode = ( e as NSError ) . code
if errorCode = = 6 { // C B E r r o r . C o d e . c o n n e c t i o n T i m e o u t T h e c o n n e c t i o n h a s t i m e d o u t u n e x p e c t e d l y .
2021-10-22 10:03:50 -07:00
// H a p p e n s w h e n d e v i c e i s m a n u a l l y r e s e t / p o w e r e d o f f
2021-10-23 00:19:23 -07:00
// W e w i l l t r y a n d r e - c o n n e c t t o t h i s d e v i c e
2022-08-23 07:59:15 -07:00
lastConnectionError = " 🚨 \( e . localizedDescription ) The app will automatically reconnect to the preferred radio if it reappears within one minute. "
2021-10-23 01:00:42 -07:00
if peripheral . identifier . uuidString = = UserDefaults . standard . object ( forKey : " preferredPeripheralId " ) as ? String ? ? " " {
self . connectTo ( peripheral : peripheral )
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ℹ ️ BLE Reconnecting: \( peripheral . name ? ? " Unknown " ) " )
2021-10-23 01:00:42 -07:00
}
2022-09-28 15:50:35 -07:00
} else if errorCode = = 7 { // C B E r r o r . C o d e . p e r i p h e r a l D i s c o n n e c t e d T h e s p e c i f i e d d e v i c e h a s d i s c o n n e c t e d f r o m u s .
// S e e m s t o b e w h a t i s r e c e i v e d w h e n a t b e a m s l e e p s , i m m e d i a t e l y r e c c o n n e c t i n g d o e s n o t w o r k .
2021-10-22 10:03:50 -07:00
lastConnectionError = e . localizedDescription
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " 🚨 BLE Disconnected: \( peripheral . name ? ? " Unknown " ) Error Code: \( errorCode ) Error: \( e . localizedDescription ) " )
2022-05-27 22:14:57 -07:00
2022-09-28 15:50:35 -07:00
} else if errorCode = = 14 { // P e e r r e m o v e d p a i r i n g i n f o r m a t i o n
// F o r g e t t i n g a n d r e c o n n e c t i n g s e e m s t o b e n e c e s s a r y s o w e n e e d t o s h o w t h e u s e r a n e r r o r t e l l i n g t h e m t o d o t h a t
2022-01-10 07:02:12 -08:00
lastConnectionError = " 🚨 \( e . localizedDescription ) This error usually cannot be fixed without forgetting the device unders Settings > Bluetooth and re-connecting to the radio. "
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " 🚨 BLE Disconnected: \( peripheral . name ? ? " Unknown " ) Error Code: \( errorCode ) Error: \( lastConnectionError ) " )
2022-09-28 15:50:35 -07:00
} else {
2021-10-23 00:19:23 -07:00
lastConnectionError = e . localizedDescription
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " 🚨 BLE Disconnected: \( peripheral . name ? ? " Unknown " ) Error Code: \( errorCode ) Error: \( e . localizedDescription ) " )
2021-10-23 00:19:23 -07:00
}
2022-09-28 15:50:35 -07:00
} else {
// D i s c o n n e c t e d w i t h o u t e r r o r w h i c h i n d i c a t e s u s e r i n t e n t t o d i s c o n n e c t
2021-10-23 00:19:23 -07:00
// H a p p e n s w h e n s w i p i n g t o d i s c o n n e c t
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ℹ ️ BLE Disconnected: \( peripheral . name ? ? " Unknown " ) : User Initiated Disconnect " )
2022-09-28 15:50:35 -07:00
}
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// MARK: P e r i p h e r a l S e r v i c e s f u n c t i o n s
func peripheral ( _ peripheral : CBPeripheral , didDiscoverServices error : Error ? ) {
if let e = error {
print ( " 🚫 Discover Services error \( e ) " )
}
guard let services = peripheral . services else { return }
for service in services {
if service . uuid = = meshtasticServiceCBUUID {
peripheral . discoverCharacteristics ( [ TORADIO_UUID , FROMRADIO_UUID , FROMNUM_UUID ] , for : service )
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ✅ BLE Service for Meshtastic discovered by \( peripheral . name ? ? " Unknown " ) " )
2022-09-28 15:50:35 -07:00
} else if ( service . uuid = = DFUSERVICE_UUID ) {
2022-10-12 22:15:15 -07:00
peripheral . discoverCharacteristics ( [ DFUDATA_UUID , DFUSIZE_UUID , DFUREGION_UUID , DFURESULT_UUID , DFUCRC32_UUID ] , for : service )
MeshLogger . log ( " ✅ BLE Service for Meshtastic DFU discovered by \( peripheral . name ? ? " Unknown " ) " )
2022-07-01 19:44:25 -07:00
}
2022-09-28 15:50:35 -07:00
}
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// MARK: D i s c o v e r C h a r a c t e r i s t i c s E v e n t
func peripheral ( _ peripheral : CBPeripheral , didDiscoverCharacteristicsFor service : CBService , error : Error ? ) {
2022-06-01 23:23:02 -07:00
2022-11-02 06:02:58 -07:00
2022-09-28 15:50:35 -07:00
if let e = error {
2022-11-02 06:02:58 -07:00
MeshLogger . log ( " 🚫 BLE Discover Characteristics error for \( peripheral . name ? ? " Unknown " ) \( e ) disconnecting device " )
// T r y a n d s t o p c r a s h e s w h e n t h i s e r r o r o c c u r s
disconnectPeripheral ( )
return
2022-09-28 15:50:35 -07:00
}
2022-10-19 07:33:46 -07:00
2022-09-28 15:50:35 -07:00
guard let characteristics = service . characteristics else { return }
2021-09-10 21:50:54 -07:00
2022-09-28 15:50:35 -07:00
for characteristic in characteristics {
2021-11-29 16:51:59 -08:00
switch characteristic . uuid {
2022-10-11 14:25:59 -07:00
2021-11-29 16:51:59 -08:00
case TORADIO_UUID :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✅ BLE did discover TORADIO characteristic for Meshtastic by \( peripheral . name ? ? " Unknown " ) " )
2021-11-29 16:51:59 -08:00
TORADIO_characteristic = characteristic
case FROMRADIO_UUID :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✅ BLE did discover FROMRADIO characteristic for Meshtastic by \( peripheral . name ? ? " Unknown " ) " )
2021-11-29 16:51:59 -08:00
FROMRADIO_characteristic = characteristic
peripheral . readValue ( for : FROMRADIO_characteristic )
2021-11-29 15:59:06 -08:00
2021-11-29 16:51:59 -08:00
case FROMNUM_UUID :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✅ BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \( peripheral . name ? ? " Unknown " ) " )
2021-11-29 16:51:59 -08:00
FROMNUM_characteristic = characteristic
peripheral . setNotifyValue ( true , for : characteristic )
2022-07-01 19:44:25 -07:00
case DFUSIZE_UUID :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✅ BLE did discover DFU Size characteristic for Meshtastic DFU by \( peripheral . name ? ? " Unknown " ) " )
2022-07-01 19:44:25 -07:00
DFUSIZE_characteristic = characteristic
case DFUDATA_UUID :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✅ BLE did discover DFU Data characteristic for Meshtastic DFU by \( peripheral . name ? ? " Unknown " ) " )
2022-07-01 19:44:25 -07:00
DFUDATA_characteristic = characteristic
case DFUCRC32_UUID :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✅ BLE did discover DFU CRC32 characteristic for Meshtastic DFU by \( peripheral . name ? ? " Unknown " ) " )
2022-07-01 19:44:25 -07:00
DFUCRC32_characteristic = characteristic
2022-10-15 10:14:08 -07:00
case DFURESULT_UUID :
MeshLogger . log ( " ✅ BLE did discover DFU Result characteristic for Meshtastic DFU by \( peripheral . name ? ? " Unknown " ) " )
2022-07-01 19:44:25 -07:00
DFURESULT_characteristic = characteristic
2022-10-15 10:14:08 -07:00
case DFUREGION_UUID :
MeshLogger . log ( " ✅ BLE did discover DFU Region characteristic for Meshtastic DFU by \( peripheral . name ? ? " Unknown " ) " )
2022-07-01 19:44:25 -07:00
DFUREGION_characteristic = characteristic
2021-11-29 15:59:06 -08:00
2021-11-29 16:51:59 -08:00
default :
break
}
2022-06-01 23:23:02 -07:00
}
2022-10-11 14:25:59 -07:00
if ( ! [ FROMNUM_characteristic , TORADIO_characteristic ] . contains ( nil ) ) {
2022-08-30 07:46:46 -05:00
sendWantConfig ( )
}
2022-09-28 15:50:35 -07:00
}
2022-08-30 07:46:46 -05:00
2022-09-27 06:33:00 -07:00
func requestDeviceMetadata ( ) {
guard ( connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected ) else { return }
MeshLogger . log ( " ℹ ️ Requesting Device Metadata for \( connectedPeripheral ! . peripheral . name ? ? " Unknown " ) " )
var adminPacket = AdminMessage ( )
2022-10-09 18:32:21 -07:00
adminPacket . getDeviceMetadataRequest = true
2022-09-27 06:33:00 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
meshPacket . wantAck = true
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
dataMessage . wantResponse = true
meshPacket . decoded = dataMessage
var toRadio : ToRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
connectedPeripheral ! . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
// E i t h e r R e a d t h e c o n f i g c o m p l e t e v a l u e o r f r o m n u m n o t i f y v a l u e
connectedPeripheral ! . peripheral . readValue ( for : FROMRADIO_characteristic )
}
2022-08-30 07:57:15 -05:00
func sendWantConfig ( ) {
2022-08-30 07:46:46 -05:00
guard ( connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected ) else { return }
2022-10-11 14:25:59 -07:00
if FROMRADIO_characteristic = = nil {
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🚨 Unsupported Firmware Version Detected, unable to connect to device. " )
2022-10-11 14:25:59 -07:00
invalidVersion = true
return
} else {
2022-08-30 07:46:46 -05:00
MeshLogger . log ( " ℹ ️ Issuing wantConfig to \( connectedPeripheral ! . peripheral . name ? ? " Unknown " ) " )
// B L E C h a r a c t e r i s t i c s d i s c o v e r e d , i s s u e w a n t C o n f i g
var toRadio : ToRadio = ToRadio ( )
configNonce += 1
toRadio . wantConfigID = configNonce
let binaryData : Data = try ! toRadio . serializedData ( )
connectedPeripheral ! . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
2022-10-11 14:25:59 -07:00
// E i t h e r R e a d t h e c o n f i g c o m p l e t e v a l u e o r f r o m n u m n o t i f y v a l u e
connectedPeripheral ! . peripheral . readValue ( for : FROMRADIO_characteristic )
}
2022-08-30 07:46:46 -05:00
}
2021-11-29 15:59:06 -08:00
2021-10-27 20:31:20 -07:00
func peripheral ( _ peripheral : CBPeripheral , didUpdateNotificationStateFor characteristic : CBCharacteristic , error : Error ? ) {
2021-11-29 15:59:06 -08:00
if let errorText = error ? . localizedDescription {
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🚫 didUpdateNotificationStateFor error: \( errorText ) " )
2021-12-12 17:17:46 -08:00
}
2021-10-27 20:31:20 -07:00
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
// MARK: D a t a R e a d / U p d a t e C h a r a c t e r i s t i c E v e n t
func peripheral ( _ peripheral : CBPeripheral , didUpdateValueFor characteristic : CBCharacteristic , error : Error ? ) {
2021-12-31 09:43:37 -08:00
if let e = error {
print ( " 🚫 didUpdateValueFor Characteristic error \( e ) " )
let errorCode = ( e as NSError ) . code
if errorCode = = 5 { // C B A T T E r r o r D o m a i n C o d e = 5 " A u t h e n t i c a t i o n i s i n s u f f i c i e n t . "
// B L E P i n c o n n e c t i o n e r r o r
lastConnectionError = " 🚫 BLE \( e . localizedDescription ) Please try connecting again and check the PIN carefully. "
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🚫 BLE \( e . localizedDescription ) Please try connecting again and check the PIN carefully. " )
2021-12-31 09:43:37 -08:00
self . centralManager ? . cancelPeripheralConnection ( peripheral )
}
2022-01-13 18:18:24 -08:00
if errorCode = = 15 { // C B A T T E r r o r D o m a i n C o d e = 1 5 " E n c r y p t i o n i s i n s u f f i c i e n t . "
// B L E P i n c o n n e c t i o n e r r o r
2022-09-24 11:28:36 -07:00
lastConnectionError = " 🚫 BLE \( e . localizedDescription ) Please try connecting again and check the PIN carefully. "
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🚫 BLE \( e . localizedDescription ) Please try connecting again. You may need to forget the device under Settings > General > Bluetooth. " )
2022-01-13 18:18:24 -08:00
self . centralManager ? . cancelPeripheralConnection ( peripheral )
}
2022-09-28 15:50:35 -07:00
}
2021-11-29 15:59:06 -08:00
2022-09-28 15:50:35 -07:00
switch characteristic . uuid {
2021-11-29 17:09:27 -08:00
case FROMRADIO_UUID :
2022-04-11 15:58:11 -07:00
2021-11-29 17:09:27 -08:00
if characteristic . value = = nil || characteristic . value ! . isEmpty {
return
}
2022-03-04 03:54:25 -08:00
2021-11-29 17:09:27 -08:00
var decodedInfo = FromRadio ( )
2022-06-24 07:48:25 -07:00
do {
decodedInfo = try FromRadio ( serializedData : characteristic . value ! )
} catch {
print ( characteristic . value ! )
}
2022-07-31 19:05:47 -04:00
2022-05-27 19:18:33 -07:00
switch decodedInfo . packet . decoded . portnum {
2022-06-15 22:11:37 -07:00
// H a n d l e A n y l o c a l o n l y p a c k e t s w e g e t o v e r B L E
2022-05-27 19:18:33 -07:00
case . unknownApp :
2022-06-15 22:11:37 -07:00
2022-07-02 10:06:50 -07:00
var nowKnown = false
// M y I n f o
if decodedInfo . myInfo . isInitialized && decodedInfo . myInfo . myNodeNum > 0 {
2022-08-06 08:07:16 -07:00
let lastDotIndex = decodedInfo . myInfo . firmwareVersion . lastIndex ( of : " . " )
2022-08-11 23:34:09 -07:00
let version = decodedInfo . myInfo . firmwareVersion [ . . . ( lastDotIndex ? ? String . Index ( utf16Offset : 6 , in : decodedInfo . myInfo . firmwareVersion ) ) ]
2022-07-02 10:06:50 -07:00
nowKnown = true
2022-10-22 07:49:39 -07:00
connectedVersion = String ( version )
2022-09-27 06:33:00 -07:00
let supportedVersion = connectedVersion = = " 0.0.0 " || self . minimumVersion . compare ( connectedVersion , options : . numeric ) = = . orderedAscending || minimumVersion . compare ( connectedVersion , options : . numeric ) = = . orderedSame
if ! supportedVersion {
invalidVersion = true
2022-10-22 07:35:55 -07:00
lastConnectionError = " 🚨 Update your firmware "
2022-09-27 06:33:00 -07:00
return
} else {
2022-10-15 10:14:08 -07:00
let myInfo = myInfoPacket ( myInfo : decodedInfo . myInfo , peripheralId : self . connectedPeripheral . id , context : context ! )
2022-10-14 22:18:28 -07:00
2022-10-22 07:35:55 -07:00
userSettings ? . preferredNodeNum = myInfo ? . myNodeNum ? ? 0
2022-09-27 06:33:00 -07:00
if myInfo != nil {
2022-10-22 07:49:39 -07:00
connectedPeripheral . num = myInfo ! . myNodeNum
connectedPeripheral . firmwareVersion = myInfo ! . firmwareVersion ? ? " Unknown "
connectedPeripheral . name = myInfo ! . bleName ? ? " Unknown "
connectedPeripheral . longName = myInfo ! . bleName ? ? " Unknown "
2022-09-27 06:33:00 -07:00
}
2022-07-02 10:06:50 -07:00
}
}
// N o d e I n f o
2022-09-27 06:33:00 -07:00
if decodedInfo . nodeInfo . num != 0 && ! invalidVersion {
2022-06-01 23:23:02 -07:00
2022-07-02 10:06:50 -07:00
nowKnown = true
2022-10-30 19:27:15 -07:00
let nodeInfo = nodeInfoPacket ( nodeInfo : decodedInfo . nodeInfo , channel : decodedInfo . packet . channel , context : context ! )
2022-07-02 10:06:50 -07:00
if nodeInfo != nil {
if self . connectedPeripheral != nil && self . connectedPeripheral . num = = nodeInfo ! . num {
if nodeInfo ! . user != nil {
connectedPeripheral . shortName = nodeInfo ! . user ! . shortName ? ? " ???? "
connectedPeripheral . longName = nodeInfo ! . user ! . longName ? ? " Unknown "
2022-06-01 23:23:02 -07:00
}
}
}
2022-07-02 10:06:50 -07:00
}
2022-10-09 18:32:21 -07:00
// C h a n n e l s
if decodedInfo . channel . isInitialized {
nowKnown = true
2022-10-15 10:14:08 -07:00
channelPacket ( channel : decodedInfo . channel , fromNum : connectedPeripheral . num , context : context ! )
2022-10-09 18:32:21 -07:00
}
2022-07-02 10:06:50 -07:00
// C o n f i g
2022-09-27 06:33:00 -07:00
if decodedInfo . config . isInitialized && ! invalidVersion {
2022-07-02 10:06:50 -07:00
nowKnown = true
2022-10-15 10:14:08 -07:00
localConfig ( config : decodedInfo . config , context : context ! , nodeNum : self . connectedPeripheral . num , nodeLongName : self . connectedPeripheral . longName )
2022-07-02 10:06:50 -07:00
}
// M o d u l e C o n f i g
2022-09-27 06:33:00 -07:00
if decodedInfo . moduleConfig . isInitialized && ! invalidVersion {
2022-07-02 10:06:50 -07:00
nowKnown = true
2022-10-15 10:14:08 -07:00
moduleConfig ( config : decodedInfo . moduleConfig , context : context ! , nodeNum : self . connectedPeripheral . num , nodeLongName : self . connectedPeripheral . longName )
2022-10-03 16:52:00 -07:00
if decodedInfo . moduleConfig . payloadVariant = = ModuleConfig . OneOf_PayloadVariant . cannedMessage ( decodedInfo . moduleConfig . cannedMessage ) {
self . getCannedMessageModuleMessages ( destNum : self . connectedPeripheral . num , wantResponse : true )
}
2022-07-02 10:06:50 -07:00
}
// L o g a n y o t h e r u n k n o w n A p p c a l l s
2022-10-15 10:14:08 -07:00
if ! nowKnown { MeshLogger . log ( " ℹ ️ MESH PACKET received for Unknown App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " ) }
2022-07-02 10:06:50 -07:00
2022-05-27 19:18:33 -07:00
case . textMessageApp :
2022-10-15 10:14:08 -07:00
textMessageAppPacket ( packet : decodedInfo . packet , connectedNode : ( self . connectedPeripheral != nil ? connectedPeripheral . num : 0 ) , context : context ! )
2022-05-27 19:18:33 -07:00
case . remoteHardwareApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Remote Hardware App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . positionApp :
2022-10-15 10:14:08 -07:00
positionPacket ( packet : decodedInfo . packet , context : context ! )
2022-09-28 15:50:35 -07:00
case . waypointApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Waypoint App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . nodeinfoApp :
2022-10-15 10:14:08 -07:00
if ! invalidVersion { nodeInfoAppPacket ( packet : decodedInfo . packet , context : context ! ) }
2022-05-27 19:18:33 -07:00
case . routingApp :
2022-11-10 22:17:38 -08:00
if ! invalidVersion { routingPacket ( packet : decodedInfo . packet , connectedNodeNum : self . connectedPeripheral . num , context : context ! ) }
2022-05-27 19:18:33 -07:00
case . adminApp :
2022-10-15 10:14:08 -07:00
adminAppPacket ( packet : decodedInfo . packet , context : context ! )
2022-05-27 19:18:33 -07:00
case . replyApp :
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Reply App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . ipTunnelApp :
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for IP Tunnel App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . serialApp :
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Serial App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . storeForwardApp :
2022-10-12 22:15:15 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Store Forward App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . rangeTestApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Range Test App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . telemetryApp :
2022-10-15 10:14:08 -07:00
if ! invalidVersion { telemetryPacket ( packet : decodedInfo . packet , context : context ! ) }
2022-05-27 19:18:33 -07:00
case . textMessageCompressedApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Text Message Compressed App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . zpsApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for ZPS App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . privateApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Private App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . atakForwarder :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for ATAK Forwarder App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-10-03 16:52:00 -07:00
case . simulatorApp :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Simulator App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-11-11 09:07:14 -08:00
case . audioApp :
MeshLogger . log ( " ℹ ️ MESH PACKET received for Audio App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . UNRECOGNIZED ( _ ) :
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ℹ ️ MESH PACKET received for Other App UNHANDLED \( try ! decodedInfo . packet . jsonString ( ) ) " )
2022-05-27 19:18:33 -07:00
case . max :
print ( " MAX PORT NUM OF 511 " )
2022-11-11 09:07:14 -08:00
2022-05-27 19:18:33 -07:00
}
2022-11-08 13:01:43 -08:00
// MARK: C h e c k f o r a n A l l / B r o a d c a s t U s e r a n d d e l e t e i t a s a t r a n s i t i o n t o m u l t i c h a n n e l
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 ]
if fetchedUser . count > 0 {
context ? . delete ( fetchedUser [ 0 ] )
print ( " 🗑️ Deleted the All - Broadcast User " )
}
} catch {
MeshLogger . log ( " 💥 Error Deleting the All - Broadcast User " )
}
2021-11-29 17:09:27 -08:00
2022-06-01 23:23:02 -07:00
// MARK: S h a r e L o c a t i o n P o s i t i o n U p d a t e T i m e r
// U s e c o n t e x t t o p a s s t h e r a d i o n a m e w i t h t h e t i m e r
// U s e a R u n L o o p t o p r e v e n t t h e t i m e r f r o m r u n n i n g o n t h e m a i n U I t h r e a d
if userSettings ? . provideLocation ? ? false {
2022-10-22 07:45:07 -07:00
if positionTimer != nil {
2022-10-14 22:18:28 -07:00
2022-10-22 07:45:07 -07:00
positionTimer ! . invalidate ( )
2021-12-12 17:17:46 -08:00
}
2022-10-14 22:18:28 -07:00
positionTimer = Timer . scheduledTimer ( timeInterval : TimeInterval ( ( userSettings ? . provideLocationInterval ? ? 900 ) ) , target : self , selector : #selector ( positionTimerFired ) , userInfo : context , repeats : true )
2022-10-22 07:45:07 -07:00
RunLoop . current . add ( positionTimer ! , forMode : . common )
2021-11-29 17:09:27 -08:00
}
2022-01-02 23:28:51 -08:00
2022-06-11 09:50:25 -07:00
if decodedInfo . configCompleteID != 0 && decodedInfo . configCompleteID = = configNonce {
2022-10-22 07:45:07 -07:00
invalidVersion = false
lastConnectionError = " "
isSubscribed = true
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🤜 BLE Config Complete Packet Id: \( decodedInfo . configCompleteID ) " )
2021-12-18 01:01:56 -08:00
peripherals . removeAll ( where : { $0 . peripheral . state = = CBPeripheralState . disconnected } )
2022-05-27 19:34:42 -07:00
// C o n f i g c o n p l e t e r e t u r n s s o w e d o n ' t r e a d t h e c h a r a c t e r i s t i c a g a i n
return
2021-11-29 17:09:27 -08:00
}
2021-11-29 15:59:06 -08:00
2022-05-12 19:31:58 -07:00
case FROMNUM_UUID :
2022-10-12 22:15:15 -07:00
print ( " 🗞️ BLE (Notify) characteristic, value will be read next " )
2021-11-29 17:09:27 -08:00
default :
2021-12-21 22:50:37 -08:00
print ( " 🚨 Unhandled Characteristic UUID: \( characteristic . uuid ) " )
2022-09-28 15:50:35 -07:00
}
2022-11-02 06:02:58 -07:00
if FROMRADIO_characteristic != nil {
// E i t h e r R e a d t h e c o n f i g c o m p l e t e v a l u e o r f r o m n u m n o t i f y v a l u e
peripheral . readValue ( for : FROMRADIO_characteristic )
}
2022-05-27 19:18:33 -07:00
}
2021-11-29 15:59:06 -08:00
2022-11-07 18:51:17 -08:00
public func sendMessage ( message : String , toUserNum : Int64 , channel : Int32 , isEmoji : Bool , replyID : Int64 ) -> Bool {
2021-12-26 21:38:14 -08:00
2021-10-20 00:31:22 -07:00
var success = false
2021-11-29 15:59:06 -08:00
2021-10-20 00:31:22 -07:00
// R e t u r n f a l s e i f w e a r e n o t p r o p e r l y c o n n e c t e d t o a d e v i c e , h a n d l e r e t r y l o g i c i n t h e v i e w f o r n o w
if connectedPeripheral = = nil || connectedPeripheral ! . peripheral . state != CBPeripheralState . connected {
2021-11-29 15:59:06 -08:00
2021-11-21 13:48:28 -08:00
self . disconnectPeripheral ( )
2021-10-20 00:31:22 -07:00
self . startScanning ( )
2021-11-29 15:59:06 -08:00
2021-10-20 00:31:22 -07:00
// T r y a n d c o n n e c t t o t h e p r e f e r r e d P e r i p h e r i a l f i r s t
let preferredPeripheral = peripherals . filter ( { $0 . peripheral . identifier . uuidString = = UserDefaults . standard . object ( forKey : " preferredPeripheralId " ) as ? String ? ? " " } ) . first
if preferredPeripheral != nil && preferredPeripheral ? . peripheral != nil {
connectTo ( peripheral : preferredPeripheral ! . peripheral )
}
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 🚫 Message Send Failed, not properly connected to \( preferredPeripheral ? . name ? ? " Unknown " ) " )
2021-10-20 00:31:22 -07:00
success = false
2022-01-04 22:57:33 -08:00
2021-11-29 15:59:06 -08:00
} else if message . count < 1 {
2021-12-25 23:48:12 -08:00
2021-12-24 21:50:10 -08:00
// D o n ' t s e n d a n e m p t y m e s s a g e
print ( " 🚫 Don't Send an Empty Message " )
2021-10-20 00:31:22 -07:00
success = false
2021-12-25 23:48:12 -08:00
2021-11-29 15:59:06 -08:00
} else {
2021-12-25 23:48:12 -08:00
let fromUserNum : Int64 = self . connectedPeripheral . num
let messageUsers : NSFetchRequest < NSFetchRequestResult > = NSFetchRequest . init ( entityName : " UserEntity " )
messageUsers . predicate = NSPredicate ( format : " num IN %@ " , [ fromUserNum , Int64 ( toUserNum ) ] )
2021-12-18 20:49:50 -08:00
do {
2021-12-25 23:48:12 -08:00
2021-12-19 19:40:16 -08:00
let fetchedUsers = try context ? . fetch ( messageUsers ) as ! [ UserEntity ]
2021-12-25 23:48:12 -08:00
2021-12-19 19:40:16 -08:00
if fetchedUsers . isEmpty {
2021-12-25 23:48:12 -08:00
2021-12-24 21:50:10 -08:00
print ( " 🚫 Message Users Not Found, Fail " )
2021-12-18 20:49:50 -08:00
success = false
2022-01-10 07:29:48 -08:00
2021-12-25 23:48:12 -08:00
} else if fetchedUsers . count >= 1 {
2021-12-18 20:49:50 -08:00
let newMessage = MessageEntity ( context : context ! )
2022-02-22 18:06:50 -10:00
newMessage . messageId = Int64 ( UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max ) )
2021-12-18 20:49:50 -08:00
newMessage . messageTimestamp = Int32 ( Date ( ) . timeIntervalSince1970 )
newMessage . receivedACK = false
2022-11-08 11:30:08 -08:00
if toUserNum > 0 {
newMessage . toUser = fetchedUsers . first ( where : { $0 . num = = toUserNum } )
}
2022-11-07 18:51:17 -08:00
newMessage . fromUser = fetchedUsers . first ( where : { $0 . num = = fromUserNum } )
2022-03-29 21:16:15 -07:00
newMessage . isEmoji = isEmoji
2022-07-02 10:06:50 -07:00
newMessage . admin = false
2022-11-07 18:51:17 -08:00
newMessage . channel = channel
2022-01-04 22:57:33 -08:00
if replyID > 0 {
newMessage . replyID = replyID
2022-01-01 22:55:25 -08:00
}
2021-12-18 20:49:50 -08:00
newMessage . messagePayload = message
2021-12-25 23:48:12 -08:00
2021-12-18 20:49:50 -08:00
let dataType = PortNum . textMessageApp
let payloadData : Data = message . data ( using : String . Encoding . utf8 ) !
var dataMessage = DataMessage ( )
dataMessage . payload = payloadData
dataMessage . portnum = dataType
var meshPacket = MeshPacket ( )
2022-02-22 18:06:50 -10:00
meshPacket . id = UInt32 ( newMessage . messageId )
2022-11-08 11:30:08 -08:00
if toUserNum > 0 {
meshPacket . to = UInt32 ( toUserNum )
} else {
meshPacket . to = 4294967295
}
2022-11-08 12:48:16 -08:00
meshPacket . channel = UInt32 ( channel )
2021-12-19 19:40:16 -08:00
meshPacket . from = UInt32 ( fromUserNum )
2022-01-15 17:16:00 -08:00
meshPacket . decoded = dataMessage
2022-03-29 21:16:15 -07:00
meshPacket . decoded . emoji = isEmoji ? 1 : 0
2022-01-04 22:57:33 -08:00
if replyID > 0 {
2022-02-04 02:26:58 -08:00
meshPacket . decoded . replyID = UInt32 ( replyID )
2022-01-01 22:55:25 -08:00
}
2021-12-18 20:49:50 -08:00
meshPacket . wantAck = true
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 📲 New messageId \( newMessage . messageId ) sent to \( newMessage . toUser ? . longName ! ? ? " Unknown " ) " )
2021-12-18 20:49:50 -08:00
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
do {
2021-12-25 23:48:12 -08:00
2021-12-18 20:49:50 -08:00
try context ! . save ( )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💾 Saved a new sent message from \( connectedPeripheral . num ) to \( toUserNum ) " )
2021-12-18 20:49:50 -08:00
success = true
2021-12-25 23:48:12 -08:00
2021-12-18 20:49:50 -08:00
} catch {
2021-12-25 23:48:12 -08:00
2021-12-18 20:49:50 -08:00
context ! . rollback ( )
2021-12-25 23:48:12 -08:00
2021-12-18 20:49:50 -08:00
let nsError = error as NSError
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💥 Unresolved Core Data error in Send Message Function your database is corrupted running a node db reset should clean up the data. Error: \( nsError ) " )
2021-12-18 20:49:50 -08:00
}
}
2021-12-15 23:53:45 -08:00
}
2021-12-25 23:48:12 -08:00
2021-12-18 20:49:50 -08:00
} catch {
2021-12-25 23:48:12 -08:00
2021-10-20 00:31:22 -07:00
}
}
return success
}
2022-02-17 18:07:41 -08:00
2022-08-12 08:58:10 -07:00
public func sendLocation ( destNum : Int64 , wantAck : Bool ) -> Bool {
2022-02-17 18:07:41 -08:00
var success = false
let fromNodeNum = connectedPeripheral . num
2022-02-24 07:57:08 -10:00
if fromNodeNum <= 0 || ( LocationHelper . currentLocation . latitude = = LocationHelper . DefaultLocation . latitude && LocationHelper . currentLocation . longitude = = LocationHelper . DefaultLocation . longitude ) {
2022-02-17 18:07:41 -08:00
return false
}
2022-10-06 08:56:15 -07:00
var positionPacket = Position ( )
positionPacket . latitudeI = Int32 ( LocationHelper . currentLocation . latitude * 1e7 )
positionPacket . longitudeI = Int32 ( LocationHelper . currentLocation . longitude * 1e7 )
positionPacket . satsInView = UInt32 ( LocationHelper . satsInView )
positionPacket . altitude = Int32 ( LocationHelper . currentAltitude )
positionPacket . timestamp = UInt32 ( LocationHelper . currentTimestamp . timeIntervalSince1970 )
positionPacket . groundSpeed = UInt32 ( LocationHelper . currentSpeed )
// p o s i t i o n P a c k e t . g r o u n d T r a c k = U I n t 3 2 ( L o c a t i o n H e l p e r . c u r r e n t H e a d i n g )
2022-08-21 19:06:10 -07:00
var waypointPacket = Waypoint ( )
2022-08-12 08:58:10 -07:00
waypointPacket . latitudeI = Int32 ( LocationHelper . currentLocation . latitude * 1e7 )
waypointPacket . longitudeI = Int32 ( LocationHelper . currentLocation . longitude * 1e7 )
2022-02-17 18:07:41 -08:00
2022-08-12 08:58:10 -07:00
let oneWeekFromNow = Calendar . current . date ( byAdding : . day , value : 7 , to : Date ( ) )
waypointPacket . expire = UInt32 ( oneWeekFromNow ! . timeIntervalSince1970 )
waypointPacket . name = " Test Waypoint "
var meshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( destNum )
meshPacket . from = 0 // S e n d 0 a s f r o m f r o m p h o n e t o d e v i c e t o a v o i d w a r n i n g a b o u t c l i e n t t r y i n g t o s e t n o d e n u m
meshPacket . wantAck = true // w a n t A c k
var dataMessage = DataMessage ( )
2022-10-06 08:56:15 -07:00
dataMessage . payload = try ! positionPacket . serializedData ( )
dataMessage . portnum = PortNum . positionApp
2022-08-12 08:58:10 -07:00
meshPacket . decoded = dataMessage
2022-02-17 18:07:41 -08:00
2022-08-12 08:58:10 -07:00
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 📍 Sent a Location Packet from the Apple device GPS to node: \( fromNodeNum ) " )
2022-08-12 08:58:10 -07:00
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
success = true
}
2022-08-11 23:34:09 -07:00
return success
}
2022-08-12 08:58:10 -07:00
public func sendPosition ( destNum : Int64 , wantAck : Bool ) -> Bool {
2022-02-17 18:07:41 -08:00
var success = false
let fromNodeNum = connectedPeripheral . num
2022-02-24 07:57:08 -10:00
if fromNodeNum <= 0 || ( LocationHelper . currentLocation . latitude = = LocationHelper . DefaultLocation . latitude && LocationHelper . currentLocation . longitude = = LocationHelper . DefaultLocation . longitude ) {
2022-02-17 18:07:41 -08:00
return false
}
2022-08-12 08:58:10 -07:00
var positionPacket = Position ( )
positionPacket . latitudeI = Int32 ( LocationHelper . currentLocation . latitude * 1e7 )
positionPacket . longitudeI = Int32 ( LocationHelper . currentLocation . longitude * 1e7 )
positionPacket . time = UInt32 ( LocationHelper . currentTimestamp . timeIntervalSince1970 )
2022-10-04 16:48:49 -07:00
positionPacket . timestamp = UInt32 ( LocationHelper . currentTimestamp . timeIntervalSince1970 )
2022-08-12 08:58:10 -07:00
positionPacket . altitude = Int32 ( LocationHelper . currentAltitude )
2022-10-04 18:10:40 -07:00
positionPacket . satsInView = UInt32 ( LocationHelper . satsInView )
2022-08-12 08:58:10 -07:00
// G e t E r r o r s w i t h o u t s o m e s p e e d
if LocationHelper . currentSpeed >= 5 {
positionPacket . groundSpeed = UInt32 ( LocationHelper . currentSpeed )
positionPacket . groundTrack = UInt32 ( LocationHelper . currentHeading )
}
2022-02-17 18:07:41 -08:00
2022-08-12 08:58:10 -07:00
var meshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( destNum )
meshPacket . from = 0 // S e n d 0 a s f r o m f r o m p h o n e t o d e v i c e t o a v o i d w a r n i n g a b o u t c l i e n t t r y i n g t o s e t n o d e n u m
meshPacket . wantAck = wantAck
var dataMessage = DataMessage ( )
dataMessage . payload = try ! positionPacket . serializedData ( )
dataMessage . portnum = PortNum . positionApp
meshPacket . decoded = dataMessage
2022-05-27 19:18:33 -07:00
2022-08-12 08:58:10 -07:00
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-02-17 18:07:41 -08:00
2022-08-12 08:58:10 -07:00
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
success = true
2022-10-14 22:18:28 -07:00
MeshLogger . log ( " 📍 Sent a Share Location Position Packet from the Apple device GPS to node: \( fromNodeNum ) " )
2022-02-17 18:07:41 -08:00
}
return success
}
2022-02-22 09:08:06 -10:00
@objc func positionTimerFired ( timer : Timer ) {
// C h e c k f o r c o n n e c t e d n o d e
if connectedPeripheral != nil {
// S e n d a p o s i t i o n o u t t o t h e m e s h i f " s h a r e l o c a t i o n w i t h t h e m e s h " i s e n a b l e d i n s e t t i n g s
if userSettings ! . provideLocation {
2022-02-24 07:57:08 -10:00
2022-08-12 08:58:10 -07:00
let success = sendPosition ( destNum : connectedPeripheral . num , wantAck : false )
2022-02-22 09:08:06 -10:00
if ! success {
print ( " Failed to send positon to device " )
}
}
}
}
2022-04-11 15:58:11 -07:00
2022-08-12 08:58:10 -07:00
public func sendShutdown ( destNum : Int64 ) -> Bool {
2022-05-27 19:18:33 -07:00
var adminPacket = AdminMessage ( )
2022-05-29 22:02:25 -07:00
adminPacket . shutdownSeconds = 10
2022-05-27 19:18:33 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
2022-05-29 22:02:25 -07:00
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-05-29 22:02:25 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-07-07 00:29:52 -07:00
do {
try context ! . save ( )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💾 Saved a Shutdown Admin Message for node: \( String ( destNum ) ) " )
2022-07-07 00:29:52 -07:00
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
return true
} catch {
context ! . rollback ( )
let nsError = error as NSError
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💥 Error Inserting New Core Data MessageEntity: \( nsError ) " )
2022-07-07 00:29:52 -07:00
}
2022-05-29 22:02:25 -07:00
}
return false
}
2022-08-12 08:58:10 -07:00
public func sendReboot ( destNum : Int64 ) -> Bool {
2022-05-29 22:02:25 -07:00
var adminPacket = AdminMessage ( )
adminPacket . rebootSeconds = 10
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
2022-06-27 08:30:49 -07:00
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-06-27 08:30:49 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-07-07 00:29:52 -07:00
do {
try context ! . save ( )
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💾 Saved a Reboot Admin Message for node: \( String ( destNum ) ) " )
2022-07-07 00:29:52 -07:00
return true
} catch {
context ! . rollback ( )
let nsError = error as NSError
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💥 Error Inserting New Core Data MessageEntity: \( nsError ) " )
2022-07-07 00:29:52 -07:00
}
2022-06-27 08:30:49 -07:00
}
return false
}
2022-08-12 08:58:10 -07:00
public func sendFactoryReset ( destNum : Int64 ) -> Bool {
2022-07-02 10:06:50 -07:00
2022-06-27 08:30:49 -07:00
var adminPacket = AdminMessage ( )
2022-09-09 15:07:39 -07:00
adminPacket . factoryReset = 1
2022-06-27 08:30:49 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
2022-10-09 07:38:19 -07:00
meshPacket . to = UInt32 ( destNum )
2022-06-27 08:30:49 -07:00
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
2022-05-27 19:18:33 -07:00
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-05-27 19:18:33 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-10-09 07:38:19 -07:00
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💾 Sent a Factory Reset for node: \( String ( destNum ) ) " )
2022-10-09 07:38:19 -07:00
return true
2022-05-27 19:18:33 -07:00
}
2022-07-02 19:50:08 -07:00
return false
2022-05-27 19:18:33 -07:00
}
2022-06-01 23:23:02 -07:00
2022-10-02 09:19:03 -07:00
public func sendNodeDBReset ( destNum : Int64 ) -> Bool {
var adminPacket = AdminMessage ( )
adminPacket . nodedbReset = 1
var meshPacket : MeshPacket = MeshPacket ( )
2022-10-06 08:56:15 -07:00
meshPacket . to = UInt32 ( destNum )
2022-10-02 09:19:03 -07:00
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
meshPacket . wantAck = true
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-10-15 10:14:08 -07:00
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
MeshLogger . log ( " 💾 Sent a NodeDB Reset for node: \( String ( destNum ) ) " )
return true
2022-10-02 09:19:03 -07:00
}
return false
}
2022-10-18 19:50:42 -07:00
public func connectToPreferredPeripheral ( ) -> Bool {
var success = false
// R e t u r n f a l s e i f w e a r e n o t p r o p e r l y c o n n e c t e d t o a d e v i c e , h a n d l e r e t r y l o g i c i n t h e v i e w f o r n o w
if connectedPeripheral = = nil || connectedPeripheral ! . peripheral . state != CBPeripheralState . connected {
self . disconnectPeripheral ( )
self . startScanning ( )
// T r y a n d c o n n e c t t o t h e p r e f e r r e d P e r i p h e r i a l f i r s t
let preferredPeripheral = peripherals . filter ( { $0 . peripheral . identifier . uuidString = = UserDefaults . standard . object ( forKey : " preferredPeripheralId " ) as ? String ? ? " " } ) . first
if preferredPeripheral != nil && preferredPeripheral ? . peripheral != nil {
connectTo ( peripheral : preferredPeripheral ! . peripheral )
success = true
}
} else if connectedPeripheral != nil && isSubscribed {
success = true
}
return success
}
2022-10-18 20:25:11 -07:00
public func saveChannelSet ( base64UrlString : String ) -> Bool {
2022-10-18 19:50:42 -07:00
if isConnected {
2022-10-28 09:02:37 -07:00
// B e f o r e w e g e t s t a r t e d d e l e t e t h e e x i s t i n g c h a n n e l s f r o m t h e m y N o d e I n f o
let fetchMyInfoRequest : NSFetchRequest < NSFetchRequestResult > = NSFetchRequest . init ( entityName : " MyInfoEntity " )
fetchMyInfoRequest . predicate = NSPredicate ( format : " myNodeNum == %lld " , Int64 ( connectedPeripheral . num ) )
do {
let fetchedMyInfo = try context ! . fetch ( fetchMyInfoRequest ) as ! [ MyInfoEntity ]
if fetchedMyInfo . count = = 1 {
let mutableChannels = fetchedMyInfo [ 0 ] . channels ! . mutableCopy ( ) as ! NSMutableOrderedSet
mutableChannels . removeAllObjects ( )
fetchedMyInfo [ 0 ] . channels = mutableChannels
do {
try context ! . save ( )
} catch {
print ( " Failed to clear existing channels from local app database " )
}
}
} catch {
2022-10-29 07:44:43 -07:00
print ( " Failed to find a node MyInfo to save these channels to " )
2022-10-28 09:02:37 -07:00
}
let decodedString = base64UrlString . base64urlToBase64 ( )
2022-10-18 19:50:42 -07:00
if let decodedData = Data ( base64Encoded : decodedString ) {
do {
2022-10-29 07:31:50 -07:00
let channelSet : ChannelSet = try ChannelSet ( serializedData : decodedData )
2022-10-22 07:35:55 -07:00
print ( channelSet )
2022-10-19 16:58:49 -07:00
var i : Int32 = 0
for cs in channelSet . settings {
var chan = Channel ( )
2022-10-29 07:31:50 -07:00
if i = = 0 {
2022-10-28 18:53:10 -07:00
chan . role = Channel . Role . primary
2022-10-29 07:31:50 -07:00
} else {
2022-10-28 18:53:10 -07:00
chan . role = Channel . Role . secondary
}
2022-10-29 07:31:50 -07:00
chan . settings = cs
chan . index = i
i += 1
2022-10-19 16:58:49 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setChannel = chan
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-10-29 07:31:50 -07:00
meshPacket . wantAck = true
meshPacket . channel = 0
2022-10-19 16:58:49 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-10-22 07:35:55 -07:00
self . connectedPeripheral . peripheral . writeValue ( binaryData , for : self . TORADIO_characteristic , type : . withResponse )
2022-10-28 18:53:10 -07:00
MeshLogger . log ( " ✈️ Sent a Channel for: \( String ( self . connectedPeripheral . num ) ) Channel Index \( chan . index ) " )
2022-10-19 16:58:49 -07:00
}
}
// S a v e t h e L o R a C o n f i g a n d t h e d e v i c e w i l l r e b o o t
var adminPacket = AdminMessage ( )
adminPacket . setConfig . lora = channelSet . loraConfig
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-10-28 18:53:10 -07:00
meshPacket . wantAck = true
2022-10-29 07:44:43 -07:00
meshPacket . channel = 0
2022-10-19 16:58:49 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-10-28 09:02:37 -07:00
self . connectedPeripheral . peripheral . writeValue ( binaryData , for : self . TORADIO_characteristic , type : . withResponse )
2022-10-28 18:53:10 -07:00
MeshLogger . log ( " ✈️ Sent a LoRaConfig for: \( String ( self . connectedPeripheral . num ) ) " )
2022-10-19 16:58:49 -07:00
}
return true
2022-10-18 19:50:42 -07:00
} catch {
2022-10-19 16:58:49 -07:00
return false
2022-10-18 19:50:42 -07:00
}
}
}
return false
}
2022-08-12 08:58:10 -07:00
public func saveUser ( config : User , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-06-11 09:50:25 -07:00
2022-06-12 01:25:42 -07:00
var adminPacket = AdminMessage ( )
2022-07-02 19:50:08 -07:00
adminPacket . setOwner = config
2022-06-18 00:08:01 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-06-18 00:08:01 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
2022-08-11 23:34:09 -07:00
2022-06-18 00:08:01 -07:00
meshPacket . decoded = dataMessage
2022-08-11 23:34:09 -07:00
let messageDescription = " Saved User Config for \( toUser . longName ? ? " Unknown " ) "
2022-07-11 15:43:25 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-18 00:08:01 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-06-18 00:08:01 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-06-18 00:08:01 -07:00
}
2022-08-20 12:31:52 -07:00
public func saveBluetoothConfig ( config : Config . BluetoothConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
var adminPacket = AdminMessage ( )
adminPacket . setConfig . bluetooth = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
meshPacket . wantAck = true
2022-06-18 00:08:01 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-08-20 12:31:52 -07:00
let messageDescription = " Saved Bluetooth Config for \( toUser . longName ? ? " Unknown " ) "
2022-07-11 15:43:25 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-18 00:08:01 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-06-18 00:08:01 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-06-18 00:08:01 -07:00
}
2022-08-12 08:58:10 -07:00
public func saveDeviceConfig ( config : Config . DeviceConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-02 19:50:08 -07:00
2022-06-21 02:43:37 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setConfig . device = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-06-21 02:43:37 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-11 15:43:25 -07:00
let messageDescription = " Saved Device Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-21 02:43:37 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-06-21 02:43:37 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-06-21 02:43:37 -07:00
}
2022-08-12 08:58:10 -07:00
public func saveDisplayConfig ( config : Config . DisplayConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-02 19:50:08 -07:00
2022-06-21 10:02:05 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setConfig . display = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-06-21 10:02:05 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-11 15:43:25 -07:00
let messageDescription = " Saved Display Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-21 10:02:05 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-06-21 10:02:05 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-06-21 10:02:05 -07:00
}
2022-08-12 08:58:10 -07:00
public func saveLoRaConfig ( config : Config . LoRaConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-11 15:43:25 -07:00
2022-06-18 00:08:01 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setConfig . lora = config
2022-06-12 01:25:42 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
2022-06-18 00:08:01 -07:00
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
2022-06-12 01:25:42 -07:00
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
2022-07-02 22:16:19 -07:00
2022-06-12 01:25:42 -07:00
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-06-12 01:25:42 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-11 15:43:25 -07:00
let messageDescription = " Saved LoRa Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-12 01:25:42 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-06-12 01:25:42 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-06-11 09:50:25 -07:00
}
2022-06-21 10:15:47 -07:00
2022-08-12 08:58:10 -07:00
public func savePositionConfig ( config : Config . PositionConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-02 19:50:08 -07:00
2022-06-21 10:15:47 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setConfig . position = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-06-21 10:15:47 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-11 15:43:25 -07:00
let messageDescription = " Saved Position Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-21 10:15:47 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-06-21 10:15:47 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-06-21 10:15:47 -07:00
}
2022-06-28 06:56:50 -07:00
2022-09-07 22:33:44 -07:00
public func saveWiFiConfig ( config : Config . NetworkConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-08-02 09:44:59 -07:00
var adminPacket = AdminMessage ( )
2022-09-07 22:33:44 -07:00
adminPacket . setConfig . network = config
2022-08-02 09:44:59 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-08-02 09:44:59 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
let messageDescription = " Saved WiFi Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
return Int64 ( meshPacket . id )
}
return 0
}
2022-08-12 08:58:10 -07:00
public func saveCannedMessageModuleConfig ( config : ModuleConfig . CannedMessageConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-11 15:43:25 -07:00
2022-07-02 12:18:20 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setModuleConfig . cannedMessage = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( toUser . num )
meshPacket . from = 0 // U I n t 3 2 ( f r o m U s e r . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-07-02 12:18:20 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-11 15:43:25 -07:00
let messageDescription = " Saved Canned Message Module Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-07-02 12:34:45 -07:00
2022-07-11 15:43:25 -07:00
return Int64 ( meshPacket . id )
2022-07-02 12:34:45 -07:00
}
2022-07-11 15:43:25 -07:00
return 0
2022-07-02 12:34:45 -07:00
}
2022-07-08 12:05:39 -07:00
public func saveCannedMessageModuleMessages ( messages : String , fromUser : UserEntity , toUser : UserEntity , wantResponse : Bool ) -> Int64 {
var adminPacket = AdminMessage ( )
2022-08-15 19:40:46 -07:00
adminPacket . setCannedMessageModuleMessages = messages
2022-07-08 12:05:39 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( toUser . num )
meshPacket . from = 0 // U I n t 3 2 ( f r o m U s e r . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-12 08:58:10 -07:00
meshPacket . wantAck = true
2022-07-08 12:05:39 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
2022-08-11 23:34:09 -07:00
dataMessage . wantResponse = wantResponse
2022-07-08 12:05:39 -07:00
meshPacket . decoded = dataMessage
2022-10-09 18:32:21 -07:00
let messageDescription = " 💾 Saved Canned Message Module Messages for \( toUser . longName ? ? " Unknown " ) "
2022-07-09 06:42:30 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-07-08 12:05:39 -07:00
2022-07-09 06:42:30 -07:00
return Int64 ( meshPacket . id )
2022-07-08 12:05:39 -07:00
}
2022-07-09 06:42:30 -07:00
return 0
2022-07-08 12:05:39 -07:00
}
2022-07-08 06:31:47 -07:00
2022-10-09 18:32:21 -07:00
public func getChannel ( channelIndex : UInt32 , fromUser : UserEntity , toUser : UserEntity , wantResponse : Bool ) -> Bool {
2022-07-31 19:05:47 -04:00
var adminPacket = AdminMessage ( )
adminPacket . getChannelRequest = channelIndex
var meshPacket : MeshPacket = MeshPacket ( )
2022-10-09 18:32:21 -07:00
meshPacket . to = UInt32 ( toUser . num )
2022-09-28 15:50:35 -07:00
meshPacket . from = 0 // U I n t 3 2 ( c n o d e N u m )
2022-07-31 19:05:47 -04:00
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
meshPacket . wantAck = wantResponse
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
2022-07-31 19:53:44 -04:00
dataMessage . wantResponse = true
2022-07-31 19:05:47 -04:00
meshPacket . decoded = dataMessage
2022-10-09 18:32:21 -07:00
let messageDescription = " 🛎️ Sent a Get Channel \( channelIndex ) Request Admin Message for node: \( String ( connectedPeripheral . num ) ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
return true
2022-07-31 19:05:47 -04:00
}
return false
}
2022-07-26 07:35:16 -07:00
public func getCannedMessageModuleMessages ( destNum : Int64 , wantResponse : Bool ) -> Bool {
var adminPacket = AdminMessage ( )
2022-08-15 19:40:46 -07:00
adminPacket . getCannedMessageModuleMessagesRequest = true
2022-07-26 07:35:16 -07:00
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-11 23:34:09 -07:00
meshPacket . wantAck = true
2022-08-02 09:44:59 -07:00
meshPacket . decoded . wantResponse = wantResponse
2022-07-26 07:35:16 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
2022-08-03 07:28:11 -07:00
dataMessage . wantResponse = wantResponse
2022-07-26 07:35:16 -07:00
meshPacket . decoded = dataMessage
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " ✈️ Sent a Canned Messages Module Get Messages Request Admin Message for node: \( String ( destNum ) ) " )
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
return true
2022-07-26 07:35:16 -07:00
}
return false
}
2022-08-11 23:34:09 -07:00
public func saveExternalNotificationModuleConfig ( config : ModuleConfig . ExternalNotificationConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-09 06:42:30 -07:00
2022-07-02 12:34:45 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setModuleConfig . externalNotification = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( toUser . num )
meshPacket . from = 0 // U I n t 3 2 ( f r o m U s e r . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-11 23:34:09 -07:00
meshPacket . wantAck = true
2022-07-02 12:34:45 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-09 06:42:30 -07:00
let messageDescription = " Saved External Notification Module Config for \( toUser . longName ? ? " Unknown " ) "
2022-07-02 12:34:45 -07:00
2022-07-09 06:42:30 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-07-02 12:18:20 -07:00
2022-07-09 06:42:30 -07:00
return Int64 ( meshPacket . id )
2022-07-02 12:18:20 -07:00
}
2022-07-09 06:42:30 -07:00
return 0
2022-07-02 12:18:20 -07:00
}
2022-09-04 21:45:03 -07:00
public func saveMQTTConfig ( config : ModuleConfig . MQTTConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
var adminPacket = AdminMessage ( )
adminPacket . setModuleConfig . mqtt = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
meshPacket . wantAck = true
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
let messageDescription = " Saved WiFi Config for \( toUser . longName ? ? " Unknown " ) "
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
return Int64 ( meshPacket . id )
}
return 0
}
2022-08-11 23:34:09 -07:00
public func saveRangeTestModuleConfig ( config : ModuleConfig . RangeTestConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-06-29 20:04:20 -07:00
2022-06-28 06:56:50 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setModuleConfig . rangeTest = config
var meshPacket : MeshPacket = MeshPacket ( )
2022-07-02 10:06:50 -07:00
meshPacket . to = UInt32 ( toUser . num )
meshPacket . from = 0 // U I n t 3 2 ( f r o m U s e r . n u m )
2022-06-28 06:56:50 -07:00
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-11 23:34:09 -07:00
meshPacket . wantAck = true
2022-06-28 06:56:50 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-09 06:42:30 -07:00
let messageDescription = " Saved Range Test Module Config for \( toUser . longName ? ? " Unknown " ) "
2022-06-28 06:56:50 -07:00
2022-07-09 06:42:30 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-28 06:56:50 -07:00
2022-07-09 06:42:30 -07:00
return Int64 ( meshPacket . id )
2022-06-28 06:56:50 -07:00
}
2022-07-09 06:42:30 -07:00
return 0
2022-06-28 06:56:50 -07:00
}
2022-06-28 20:20:02 -07:00
2022-08-11 23:34:09 -07:00
public func saveSerialModuleConfig ( config : ModuleConfig . SerialConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-02 13:43:13 -07:00
2022-06-28 20:20:02 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setModuleConfig . serial = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( connectedPeripheral . num )
meshPacket . from = 0 // U I n t 3 2 ( c o n n e c t e d P e r i p h e r a l . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-11 23:34:09 -07:00
meshPacket . wantAck = true
2022-06-28 20:20:02 -07:00
meshPacket . hopLimit = 0
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-09 06:42:30 -07:00
let messageDescription = " Saved Serial Module Config for \( toUser . longName ? ? " Unknown " ) "
2022-06-28 20:20:02 -07:00
2022-07-09 06:42:30 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-28 20:20:02 -07:00
2022-07-09 06:42:30 -07:00
return Int64 ( meshPacket . id )
2022-07-02 13:43:13 -07:00
}
2022-07-09 06:42:30 -07:00
return 0
2022-07-02 13:43:13 -07:00
}
2022-08-11 23:34:09 -07:00
public func saveTelemetryModuleConfig ( config : ModuleConfig . TelemetryConfig , fromUser : UserEntity , toUser : UserEntity ) -> Int64 {
2022-07-09 06:42:30 -07:00
2022-07-02 13:43:13 -07:00
var adminPacket = AdminMessage ( )
adminPacket . setModuleConfig . telemetry = config
var meshPacket : MeshPacket = MeshPacket ( )
meshPacket . to = UInt32 ( toUser . num )
meshPacket . from = 0 // U I n t 3 2 ( f r o m U s e r . n u m )
meshPacket . id = UInt32 . random ( in : UInt32 ( UInt8 . max ) . . < UInt32 . max )
meshPacket . priority = MeshPacket . Priority . reliable
2022-08-11 23:34:09 -07:00
meshPacket . wantAck = true
2022-07-02 13:43:13 -07:00
var dataMessage = DataMessage ( )
dataMessage . payload = try ! adminPacket . serializedData ( )
dataMessage . portnum = PortNum . adminApp
meshPacket . decoded = dataMessage
2022-07-09 06:42:30 -07:00
let messageDescription = " Saved Telemetry Module Config for \( toUser . longName ? ? " Unknown " ) "
2022-07-02 13:43:13 -07:00
2022-07-09 06:42:30 -07:00
if sendAdminMessageToRadio ( meshPacket : meshPacket , adminDescription : messageDescription , fromUser : fromUser , toUser : toUser ) {
2022-06-28 20:20:02 -07:00
2022-07-09 06:42:30 -07:00
return Int64 ( meshPacket . id )
2022-06-28 20:20:02 -07:00
}
2022-07-09 06:42:30 -07:00
return 0
2022-06-28 20:20:02 -07:00
}
2022-07-08 12:05:39 -07:00
// S e n d a n a d m i n m e s s a g e t o a r a d i o , s a v e a m e s s a g e t o c o r e d a t a f o r l o g g i n g
2022-07-09 06:42:30 -07:00
private func sendAdminMessageToRadio ( meshPacket : MeshPacket , adminDescription : String , fromUser : UserEntity , toUser : UserEntity ) -> Bool {
var toRadio : ToRadio !
toRadio = ToRadio ( )
toRadio . packet = meshPacket
let binaryData : Data = try ! toRadio . serializedData ( )
2022-07-08 12:05:39 -07:00
if connectedPeripheral ! . peripheral . state = = CBPeripheralState . connected {
let newMessage = MessageEntity ( context : context ! )
2022-07-09 06:42:30 -07:00
newMessage . messageId = Int64 ( meshPacket . id )
2022-07-08 12:05:39 -07:00
newMessage . messageTimestamp = Int32 ( Date ( ) . timeIntervalSince1970 )
newMessage . receivedACK = false
newMessage . admin = true
newMessage . adminDescription = adminDescription
newMessage . fromUser = fromUser
newMessage . toUser = toUser
do {
2022-07-09 06:42:30 -07:00
connectedPeripheral . peripheral . writeValue ( binaryData , for : TORADIO_characteristic , type : . withResponse )
2022-07-08 12:05:39 -07:00
try context ! . save ( )
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💾 \( adminDescription ) " )
2022-07-09 06:42:30 -07:00
return true
2022-07-08 12:05:39 -07:00
} catch {
context ! . rollback ( )
let nsError = error as NSError
2022-10-15 10:14:08 -07:00
MeshLogger . log ( " 💥 Error inserting new core data MessageEntity: \( nsError ) " )
2022-07-08 12:05:39 -07:00
}
}
2022-07-09 06:42:30 -07:00
return false
2022-07-08 12:05:39 -07:00
}
2021-09-10 07:41:26 -07:00
}