Advertisement
Guest User

Untitled

a guest
Apr 21st, 2020
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 10.31 KB | None | 0 0
  1. //
  2. //  BLEManager.swift
  3. //  covidIsolate
  4. //
  5. //  Created by luick klippel on 12.04.20.
  6. //  Copyright © 2020 luick klippel. All rights reserved.
  7. //
  8.  
  9. import SwiftUI
  10. import Foundation
  11. import UIKit
  12. import CoreBluetooth
  13. import CoreData
  14. import os
  15.  
  16. class BLEPeripheral : NSObject {
  17.  
  18.     public static let covidIsolateServiceUUID = CBUUID(string: "86223527-b64e-475d-b646-bc45127e1cbb")
  19.    
  20.     public static let characteristicUUID = CBUUID(string: "87aa09fa-7345-406b-8f92-f12f6ba3eceb")
  21.    
  22.     public static var loaded = false
  23.    
  24.     let personnalContactIdSize = 320
  25.     var receiveBuffer:Data = Data()
  26.    
  27.     var peripheralManager: CBPeripheralManager!
  28.     var delContext = NSManagedObjectContext()
  29.  
  30.     var transferCharacteristic: CBMutableCharacteristic?
  31.     var connectedCentral: CBCentral?
  32.     var dataToSend = Data()
  33.     var sendDataIndex: Int = 0
  34.    
  35.     // MARK: - View Lifecycle
  36.    
  37.     func loadBLEPeripheral(context: NSManagedObjectContext) {
  38.         Alert(title: Text("Info"), message:     Text("listener loaded"), dismissButton: .default(Text("ok")))
  39.         BLEPeripheral.loaded = true
  40.         self.delContext = context
  41.         peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true])
  42.         // peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [BLEPeripheral.covidIsolateServiceUUID]])
  43.     }
  44.    
  45.     func stopBLEPeripheral() {
  46.         BLEPeripheral.loaded = false
  47.         peripheralManager.stopAdvertising()
  48.         os_log("Adertising stopped")
  49.  
  50.         receiveBuffer.removeAll(keepingCapacity: false)
  51.         dataToSend.removeAll(keepingCapacity: false)
  52.         sendDataIndex = 0
  53.     }
  54.  
  55.     public func startAdvertising() {
  56.         peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [BLEPeripheral.covidIsolateServiceUUID]])
  57.     }
  58.     public func stopAdvertising() {
  59.         peripheralManager.stopAdvertising()
  60.     }
  61.    
  62.     // peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [TransferService.serviceUUID]])
  63.     // peripheralManager.stopAdvertising()
  64.  
  65.     /*
  66.      *  Sends the next amount of data to the connected central
  67.      */
  68.     static var sendingEOM = true
  69.    
  70.     func sendData() {
  71.        
  72.         guard let transferCharacteristic = transferCharacteristic else {
  73.             return
  74.         }
  75.        
  76.         // First up, check if we're meant to be sending an EOM
  77.         if BLEPeripheral.sendingEOM {
  78.             // send it
  79.             let didSend = peripheralManager.updateValue("EOM".data(using: .utf8)!, for: transferCharacteristic, onSubscribedCentrals: nil)
  80.             // Did it send?
  81.             if didSend {
  82.                 // It did, so mark it as sent
  83.                 BLEPeripheral.sendingEOM = false
  84.                 os_log("Sent: EOM")
  85.             }
  86.             // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again
  87.             return
  88.         }
  89.        
  90.         // We're not sending an EOM, so we're sending data
  91.         // Is there any left to send?
  92.         if sendDataIndex >= dataToSend.count {
  93.             // No data left.  Do nothing
  94.             return
  95.         }
  96.        
  97.         // There's data left, so send until the callback fails, or we're done.
  98.         var didSend = true
  99.         while didSend {
  100.            
  101.             // Work out how big it should be
  102.             var amountToSend = dataToSend.count - sendDataIndex
  103.             if let mtu = connectedCentral?.maximumUpdateValueLength {
  104.                 amountToSend = min(amountToSend, mtu)
  105.             }
  106.            
  107.             // Copy out the data we want
  108.             let chunk = dataToSend.subdata(in: sendDataIndex..<(sendDataIndex + amountToSend))
  109.            
  110.             // Send it
  111.             didSend = peripheralManager.updateValue(chunk, for: transferCharacteristic, onSubscribedCentrals: nil)
  112.            
  113.             // If it didn't work, drop out and wait for the callback
  114.             if !didSend {
  115.                 return
  116.             }
  117.            
  118.             let stringFromData = String(data: chunk, encoding: .ascii)
  119.            
  120.             // It did send, so update our index
  121.             sendDataIndex += amountToSend
  122.             // Was it the last one?
  123.             if sendDataIndex >= dataToSend.count {
  124.                 // It was - send an EOM
  125.                
  126.                 // Set this so if the send fails, we'll send it next time
  127.                 BLEPeripheral.sendingEOM = true
  128.                
  129.                 //Send it
  130.                 let eomSent = peripheralManager.updateValue("EOM".data(using: .utf8)!,
  131.                                                              for: transferCharacteristic, onSubscribedCentrals: nil)
  132.                
  133.                 if eomSent {
  134.                     // It sent; we're all done
  135.                     BLEPeripheral.sendingEOM = false
  136.                     os_log("Sent: EOM")
  137.                 }
  138.                 return
  139.             }
  140.         }
  141.     }
  142.  
  143.     public func setupPeripheral() {
  144.        
  145.         // Build our service.
  146.        
  147.         // Start with the CBMutableCharacteristic.
  148.         let transferCharacteristic = CBMutableCharacteristic(type: BLEPeripheral.characteristicUUID,
  149.                                                              properties: [.notify, .writeWithoutResponse],
  150.                                                          value: nil,
  151.                                                          permissions: [.readable, .writeable])
  152.        
  153.         // Create a service from the characteristic.
  154.         let transferService = CBMutableService(type: BLEPeripheral.covidIsolateServiceUUID, primary: true)
  155.        
  156.         // Add the characteristic to the service.
  157.         transferService.characteristics = [transferCharacteristic]
  158.        
  159.         // And add it to the peripheral manager.
  160.         peripheralManager.add(transferService)
  161.        
  162.         // Save the characteristic for later.
  163.         self.transferCharacteristic = transferCharacteristic
  164.  
  165.     }
  166. }
  167.  
  168. extension BLEPeripheral: CBPeripheralManagerDelegate {
  169.     // implementations of the CBPeripheralManagerDelegate methods
  170.  
  171.     internal func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
  172.        
  173.         switch peripheral.state {
  174.         case .poweredOn:
  175.             // ... so start working with the peripheral
  176.             os_log("Peripheral CBManager is powered on")
  177.             setupPeripheral()
  178.         case .poweredOff:
  179.             os_log("Peripheral CBManager is not powered on")
  180.             // In a real app, you'd deal with all the states accordingly
  181.             return
  182.         case .resetting:
  183.             os_log("Peripheral CBManager is resetting")
  184.             // In a real app, you'd deal with all the states accordingly
  185.             return
  186.         case .unauthorized:
  187.             // In a real app, you'd deal with all the states accordingly
  188.             if #available(iOS 13.0, *) {
  189.                 switch peripheral.authorization {
  190.                 case .denied:
  191.                     os_log("You are not authorized to use Bluetooth")
  192.                 case .restricted:
  193.                     os_log("Bluetooth is restricted")
  194.                 default:
  195.                     os_log("Unexpected authorization")
  196.                 }
  197.             } else {
  198.                 // Fallback on earlier versions
  199.             }
  200.             return
  201.         case .unknown:
  202.             os_log("CBManager state is unknown")
  203.             // In a real app, you'd deal with all the states accordingly
  204.             return
  205.         case .unsupported:
  206.             os_log("Bluetooth is not supported on this device")
  207.             // In a real app, you'd deal with all the states accordingly
  208.             return
  209.         @unknown default:
  210.             os_log("A previously unknown peripheral manager state occurred")
  211.             // In a real app, you'd deal with yet unknown cases that might occur in the future
  212.             return
  213.         }
  214.     }
  215.  
  216.     /*
  217.      *  Catch when someone subscribes to our characteristic, then start sending them data
  218.      */
  219.     func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
  220.         os_log("Central subscribed to characteristic")
  221.        
  222.  
  223.         let user = cIUtils.fetchSingleUserFromCoreDb(context:self.delContext)!
  224.        
  225.         let personnalContactId = cIUtils.createPersonnalContactId(id: user.id, timeStamp: cIUtils.genStringTimeDateStamp(), privateKey: RSACrypto.getRSAKeyFromKeychain(user.keyPairChainTagName+"-private")!)
  226.        
  227.         // Get the data
  228.         dataToSend = NSData(bytes: personnalContactId, length: personnalContactId.count) as! Data
  229.        
  230.         // Reset the index
  231.         sendDataIndex = 0
  232.        
  233.         // save central
  234.         connectedCentral = central
  235.        
  236.         // Start sending
  237.         sendData()
  238.     }
  239.    
  240.     /*
  241.      *  Recognize when the central unsubscribes
  242.      */
  243.     func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) {
  244.         os_log("Central unsubscribed from characteristic")
  245.         connectedCentral = nil
  246.     }
  247.    
  248.     /*
  249.      *  This callback comes in when the PeripheralManager is ready to send the next chunk of data.
  250.      *  This is to ensure that packets will arrive in the order they are sent
  251.      */
  252.     func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
  253.         // Start sending again
  254.         sendData()
  255.     }
  256.    
  257.     /*
  258.      * This callback comes in when the PeripheralManager received write to characteristics
  259.      */
  260.     func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
  261.         for aRequest in requests {
  262.             guard let requestValue = aRequest.value,
  263.                 let stringFromData = String(data: requestValue, encoding: .utf8) else {
  264.                     continue
  265.             }
  266.             receiveBuffer.append(requestValue)
  267.             if receiveBuffer.count == personnalContactIdSize {
  268.                
  269.                 receiveBuffer.removeAll()
  270.             }
  271.             os_log("Received write request of %d bytes: %s", requestValue.count, stringFromData)
  272.            
  273.         }
  274.     }
  275. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement