-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I updated from version 3.1.5 to version 4.0.1. I need to update many interfaces and the changes are huge. Is there any convenient way? #592
Comments
Hi, I will try to help you here. What do you need help with? |
The biggest breaking change is minimum iOS version set to 13 due to use of |
How is the migration going? |
Hi @philips77, I recently updated from version 3.2.0 to 4.2.0 and am encountering some issues with the provisioning process. Could you please assist me with the migration? I am developing a Flutter plugin to interact with nRFMeshProvision from Flutter. The first problem I encountered is with the provisioning process. Below is a relevant excerpt from my QBleMesh class, where I have a provision method: import Foundation
import NordicMesh
import CoreBluetooth
public class QBleMesh {
var connection: NetworkConnection?
var unprovisionedDevices: [DiscoveredPeripheral] = [DiscoveredPeripheral]()
var discoveredDevices: [DiscoveredDevice] = [DiscoveredDevice]()
var statusEntities: [StatusEntity] = [StatusEntity]()
// callbacks
var provisionCallback: (_ provisionedNode: ProvisionedNode) -> Void = {_ in}
var statusCallback: (_ status: StatusEntity) -> Void = {_ in}
var discoveredDevicesCallback: (_ discoveredDevices: [DiscoveredDevice]) -> Void = {_ in}
var provisioningService: ProvisioningService?
var _meshNetworkManager: MeshNetworkManager?
var meshNetworkManager: MeshNetworkManager {
get {
if self._meshNetworkManager == nil {
_meshNetworkManager = initializeMeshNetworkManager()
}
return self._meshNetworkManager!
}
}
private func initializeMeshNetworkManager() -> MeshNetworkManager {
let meshNetworkManager = MeshNetworkManager()
meshNetworkManager.networkParameters = .advanced { parameters in
parameters.sarAcknowledgmentRetransmissionsCount = 2
parameters.acknowledgmentMessageInterval = 4.2
parameters.acknowledgmentMessageTimeout = 40.0
}
meshNetworkManager.logger = self
return meshNetworkManager
}
init() {
var meshLoaded = false
do {
meshLoaded = try meshNetworkManager.load()
} catch {
print(error)
}
if (meshLoaded) {
meshNetworkDidChange()
} else {
createNewMeshNetwork()
}
}
func startScan() -> Bool {
if let networkConnection = connection {
return networkConnection.startScanForPeripherals()
}
return false
}
func discoveredDevices(_ callback: @escaping (_ discoveredDevices: [DiscoveredDevice]) -> Void) {
discoveredDevicesCallback = callback
if let networkConnection = connection {
networkConnection.discoveredPeripherals() { (discoveredPeripheral: DiscoveredPeripheral) in
if !self.unprovisionedDevices.contains(where: { $0.peripheral.identifier == discoveredPeripheral.peripheral.identifier }) {
self.unprovisionedDevices.append((discoveredPeripheral.device, discoveredPeripheral.peripheral, discoveredPeripheral.rssi))
let device = DiscoveredDevice(address: discoveredPeripheral.peripheral.identifier.uuidString,
name: discoveredPeripheral.peripheral.name ?? "",
rssi: discoveredPeripheral.rssi)
if let updateIndex = self.discoveredDevices.firstIndex(where: { $0.address == device.address }) {
self.discoveredDevices[updateIndex] = device
} else {
self.discoveredDevices.append(device)
}
}
self.discoveredDevicesCallback(self.discoveredDevices)
}
}
}
func stopScan() -> Bool {
if let networkConnection = connection {
return networkConnection.stopScan()
}
discoveredDevicesCallback = {_ in}
return false
}
func identify(_ address: String, _ callback: @escaping (_ unprovisionedNode: UnprovisionedNode) -> Void) {
provisioningService?.identifyingComplete = callback
if let networkConnection = connection, let uuid = UUID(uuidString: address) {
let peripheral = networkConnection.centralManager.retrievePeripherals(withIdentifiers: [uuid]).first
let unprovisionedDevice = unprovisionedDevices.first(where: { $0.peripheral.identifier == peripheral?.identifier })
let deviceToIdentify = unprovisionedDevice?.device
deviceToIdentify?.name = unprovisionedDevice?.peripheral.name
provisioningService?.identify(deviceToIdentify, peripheral: peripheral)
}
}
func provision(_ node: UnprovisionedNode, _ callback: @escaping (_ provisionedNode: ProvisionedNode) -> Void) {
provisionCallback = callback
self.provisioningService?.provisioningComplete = { unicastAddress, unprovisionedDevice in
self.startConfiguration(unicastAddress, deviceToIdentify: unprovisionedDevice)
}
self.provisioningService?.provision()
}
} In this setup, I set the After debugging, I found that the code execution halts at the following line in the _ = try? manager.send(ConfigCompositionDataGet(), to: node) No response is received after this point. Full code for Could you please help me identify what might be causing this issue and how I can resolve it? Thank you! |
class ConfigurationService {
let manager: MeshNetworkManager
var compositionDataGetComplete: () -> Void = {}
var configurationComplete: (_ provisionedNode: ProvisionedNode) -> Void = {_ in}
init(manager: MeshNetworkManager) {
self.manager = manager
manager.delegate = self
}
func configure(unicastAddress: Address, name: String, address: String) {
var provisionedNode: ProvisionedNode = ProvisionedNode(name: name, address: address)
if let meshNetwork = self.manager.meshNetwork {
if let node = meshNetwork.node(withAddress: unicastAddress) {
if let appKey = meshNetwork.applicationKeys.first {
_ = try? manager.send(ConfigAppKeyAdd(applicationKey: appKey), to: node)
if node.isCompositionDataReceived {
setupModels(&provisionedNode, unicastAddress: unicastAddress)
} else {
_ = try? manager.send(ConfigCompositionDataGet(), to: node)
compositionDataGetComplete = {
self.setupModels(&provisionedNode, unicastAddress: unicastAddress)
}
}
}
}
}
}
func setupModels(_ provisionedNode: inout ProvisionedNode, unicastAddress: Address) {
if let meshNetwork = self.manager.meshNetwork {
if let node = meshNetwork.node(withAddress: unicastAddress) {
if let appKey = meshNetwork.applicationKeys.first {
if let primaryElement = node.primaryElement {
provisionedNode.primaryElement = configurePrimaryElement(primaryElement, appKey: appKey)
}
for element: Element in node.elements {
provisionedNode.segments.append(configureSegment(element, appKey: appKey))
}
}
}
}
self.configurationComplete(provisionedNode)
}
/// configure the primary element of the node
func configurePrimaryElement(_ element: Element, appKey: ApplicationKey) -> PrimaryElement {
let primaryElement: PrimaryElement = PrimaryElement(unicastAddress: element.unicastAddress)
if let batteryModel = element.model(withSigModelId: .genericBatteryServer) {
if let batteryConfig = ConfigModelAppBind(applicationKey: appKey, to: batteryModel) {
_ = try? self.manager.send(batteryConfig, to: element.parentNode!)
}
let localAddress: MeshAddress = MeshAddress(self.manager.localElements.first!.unicastAddress)
let publishMessage = Publish(to: localAddress, using: appKey, usingFriendshipMaterial: false, ttl: 8, period: Publish.Period(TimeInterval(15)), retransmit: Publish.Retransmit())
if let publicationSet = ConfigModelPublicationSet(publishMessage, to: batteryModel) {
_ = try? self.manager.send(publicationSet, to: element.parentNode!)
}
}
if let vendorHealthModel = element.model(withModelId: .healthModelId, definedBy: .companyId) {
if let healthConfig = ConfigModelAppBind(applicationKey: appKey, to: vendorHealthModel) {
_ = try? self.manager.send(healthConfig, to: element.parentNode!)
}
}
if let vendorCountdownModel = element.model(withModelId: .timerModelId, definedBy: .companyId) {
if let config = ConfigModelAppBind(applicationKey: appKey, to: vendorCountdownModel) {
_ = try? self.manager.send(config, to: element.parentNode!)
}
}
return primaryElement
}
/// configure a segment
func configureSegment(_ element: Element, appKey: ApplicationKey) -> Segment {
let segment: Segment = Segment(unicastAddress: element.unicastAddress)
if let onOffModel = element.model(withSigModelId: .genericOnOffServer) {
if let onOffAppKeyConfig = ConfigModelAppBind(applicationKey: appKey, to: onOffModel) {
_ = try? self.manager.send(onOffAppKeyConfig, to: element.parentNode!)
}
let localAddress: MeshAddress = MeshAddress(self.manager.localElements.first!.unicastAddress)
let publishMessage = Publish(to: localAddress, using: appKey, usingFriendshipMaterial: false, ttl: 8, period: Publish.Period(TimeInterval(15)), retransmit: Publish.Retransmit())
if let publicationSet = ConfigModelPublicationSet(publishMessage, to: onOffModel) {
_ = try? self.manager.send(publicationSet, to: element.parentNode!)
}
}
if let lightCtlModel = element.model(withSigModelId: .lightCTLServer) {
if let lightCtlAppKeyConfig = ConfigModelAppBind(applicationKey: appKey, to: lightCtlModel) {
_ = try? self.manager.send(lightCtlAppKeyConfig, to: element.parentNode!)
}
let localAddress: MeshAddress = MeshAddress(self.manager.localElements.first!.unicastAddress)
let publishMessage = Publish(to: localAddress, using: appKey, usingFriendshipMaterial: false, ttl: 8, period: Publish.Period(TimeInterval(15)), retransmit: Publish.Retransmit())
if let publicationSet = ConfigModelPublicationSet(publishMessage, to: lightCtlModel) {
_ = try? self.manager.send(publicationSet, to: element.parentNode!)
}
}
return segment
}
} extension ConfigurationService: MeshNetworkDelegate {
func meshNetworkManager(_ manager: MeshNetworkManager, didReceiveMessage message: MeshMessage, sentFrom source: Address, to destination: MeshAddress) {
if(message is ConfigCompositionDataStatus) {
self.compositionDataGetComplete()
}
}
} class ProvisioningService {
var identifyingComplete: (_ unprovisionedNode:UnprovisionedNode) -> Void = {_ in}
var provisioningComplete: (_ unicastAddress: Address?, _ provisionedDevice:UnprovisionedDevice?) -> Void = {_,_ in}
var peripheral: CBPeripheral?
var deviceToIdentify: UnprovisionedDevice?
var capabilitiesReceived: Bool = false
var bearer: ProvisioningBearer?
var pbGattBearer: PBGattBearer?
var manager : ProvisioningManager?
let meshManager: MeshNetworkManager
var authenticationMethod: AuthenticationMethod?
var publicKey: PublicKey?
init(meshNetworkManager meshManager: MeshNetworkManager) {
self.meshManager = meshManager
}
func identify(_ deviceToIdentify: UnprovisionedDevice?, peripheral: CBPeripheral?) {
self.deviceToIdentify = deviceToIdentify
self.peripheral = peripheral
if let item = self.peripheral {
pbGattBearer = PBGattBearer(target: item)
pbGattBearer?.logger = meshManager.logger
pbGattBearer?.delegate = self
pbGattBearer?.open()
}
}
func startIdentifyingProcess() {
if let unprovisionedDevice = self.deviceToIdentify, let bearer = self.bearer {
manager = try! meshManager.provision(unprovisionedDevice: unprovisionedDevice, over: bearer)
manager?.delegate = self
do {
let attentionTimer: UInt8 = 30
try self.manager?.identify(andAttractFor: attentionTimer)
} catch {
self.abortProvisioning()
return
}
}
}
func identifyOrOpenBearer() {
if(pbGattBearer?.isOpen ?? false) {
startIdentifyingProcess()
} else {
self.identify(self.deviceToIdentify, peripheral: peripheral)
}
}
func provision() {
guard (manager?.provisioningCapabilities) != nil else {
print("startProvisioning guard\n -> provisioningManager.provisioningCapabilities = \(String(describing:manager?.provisioningCapabilities))")
return
}
publicKey = publicKey ?? .noOobPublicKey
authenticationMethod = authenticationMethod ?? .noOob
if manager?.networkKey == nil {
let network = self.meshManager.meshNetwork!
let networkKey = try! network.add(networkKey: Data.random128BitKey(), name: "Primary Network Key")
manager?.networkKey = networkKey
}
// Start provisioning.
do {
print("start provisioning")
try self.manager?.provision(usingAlgorithm: .BTM_ECDH_P256_CMAC_AES128_AES_CCM,
publicKey: self.publicKey!,
authenticationMethod: self.authenticationMethod!)
} catch {
self.abortProvisioning()
print("startProvisioning Error \n \(error.localizedDescription)")
return
}
}
func abortProvisioning() {
do {
try self.bearer?.close()
} catch {
print("after update i added this here. bearer?.close has some error")
}
}
} extension ProvisioningService : BearerDelegate {
func bearerDidOpen(_ bearer: Bearer) {
self.bearer = bearer as? ProvisioningBearer
self.startIdentifyingProcess()
}
public func bearer(_ bearer: Bearer, didClose error: Error?) {
// Stop here when we are not finished provisioning
print("provisioning state \(String(describing: self.manager?.state))")
guard case .complete = self.manager?.state else {
return
}
// provisioning is completed
if meshManager.save() {
print("Mesh configuration saved.")
} else {
print("Mesh configuration could not be saved.")
}
self.pbGattBearer?.delegate = nil
self.pbGattBearer = nil
self.meshManager.delegate = nil
self.provisioningComplete(self.manager?.unicastAddress, self.deviceToIdentify)
self.deviceToIdentify = nil
}
} extension ProvisioningService : ProvisioningDelegate {
func authenticationActionRequired(_ action: AuthAction) {
// not needed
}
func inputComplete() {
// not needed
}
public func provisioningState(of unprovisionedDevice: UnprovisionedDevice, didChangeTo state: ProvisioningState) {
print("state changed to -> \(state)")
switch(state) {
case .ready:
print("ready to provision")
//check if we have a open gatt
self.identifyOrOpenBearer()
case .requestingCapabilities:
print("requesting capabilities for \(unprovisionedDevice.name ?? "unknown device")")
case .capabilitiesReceived(_):
let addressValid = self.manager?.isUnicastAddressValid ?? false
let deviceSupported = self.manager?.isDeviceSupported == true
let capabilitiesWereAlreadyReceived = self.capabilitiesReceived
self.capabilitiesReceived = true
if(deviceSupported && addressValid) {
if(capabilitiesWereAlreadyReceived) {
let isToran:Bool = unprovisionedDevice.name?.lowercased().starts(with: "toran") ?? false
let unprovisionedNode:UnprovisionedNode = UnprovisionedNode(
address: self.peripheral?.identifier.uuidString ?? "",
isToran: isToran,
name: unprovisionedDevice.name ?? ""
)
self.identifyingComplete(unprovisionedNode)
} else {
self.identifyOrOpenBearer();
}
}
case .complete:
// provisioning is done so we can close the connection to the gatt.
do {
try self.bearer?.close()
} catch {
print("bearer.close error after update to 4.2.0")
}
break
case .failed(_):
// provisioning failed so we should inform the user about the failure.
self.abortProvisioning()
break
default:
break
}
}
} |
Hello,
Anyway, you need to be connected to any provisioned Node before starting to send messages. I can't find reconnection in your code. In case of nRF Mesh app, there's In the latest version of nRF Mesh app it is also possible to reconnect immediately to the device (even if one was connected) to be able to configure Low Power Nodes (LPN), which don't have any Friend yet. By directly connecting to them using GATT the client can send what's needed without relying on Friends. Lines 392 to 401 in 2672168
|
Thank you for your answer. I have an extension for the QBleMesh class that facilitates the creation of a new MeshNetworkManager instance. The NetworkConnection class, derived from the nRFMesh app example with some small additional features, should ensure control over the GATT connection, ensuring it's opened or closed appropriately. Or am i missing something? extension QBleMesh {
func createNewMeshNetwork() {
let provisioner = Provisioner.init(name: UIDevice.current.name)
_ = meshNetworkManager.createNewMeshNetwork(withName: "bt-control", by: provisioner)
_ = meshNetworkManager.save()
meshNetworkDidChange()
}
func meshNetworkDidChange() {
let meshNetwork = meshNetworkManager.meshNetwork!
let primary: Element = Element(name: "PrimaryElement", location: .first, models: [
Model(sigModelId: .genericOnOffClient, delegate: GenericOnOffClientDelegate(meshNetworkManager, statusManager: self)),
Model(sigModelId: .lightCTLClient, delegate: LightCTLClientDelegate(meshNetworkManager, statusManager: self)),
Model(sigModelId: .genericBatteryClient, delegate: GenericBatteryClientDelegate(meshNetwork, statusManager: self)),
// Model(vendorModelId: .healthModelId, companyId: .companyId, delegate: VendorHealthClientDelegate(meshNetworkManager))
Model(vendorModelId: .timerModelId, companyId: .companyId, delegate: VendorCountdownClientDelegate(meshNetworkManager))
])
meshNetworkManager.localElements = [primary]
setApplicationKey()
setupModelApplicationKeysForLocalNode(meshNetwork.applicationKeys.first!)
print("meshNetwork.nodes \(meshNetwork.nodes)")
print("meshNetwork.groups \(meshNetwork.groups)")
connection = NetworkConnection(to: meshNetwork)
connection?.isConnectionModeAutomatic = true
connection?.dataDelegate = meshNetworkManager
connection?.logger = self
meshNetworkManager.transmitter = connection
connection?.open()
provisioningService = ProvisioningService(meshNetworkManager: meshNetworkManager)
meshNetworkManager.delegate = self
}
func setApplicationKey() {
let meshNetwork = meshNetworkManager.meshNetwork!
if(meshNetwork.applicationKeys.isEmpty) {
let defaults = UserDefaults.standard
var applicationKey:Data? = nil
if let storedKey = defaults.object(forKey: "ApplicationKey") as? Data {
applicationKey = storedKey
}
if applicationKey == nil {
applicationKey = Data.random128BitKey()
defaults.set(applicationKey!, forKey: "ApplicationKey")
}
do {
_ = try meshNetwork.add(applicationKey: applicationKey!, name: "\(UIDevice.current.name)")
} catch {
log(message: "Application Key could not be added", ofCategory: .access, withLevel: .error)
}
}
}
func setupModelApplicationKeysForLocalNode(_ applicationKey: ApplicationKey) {
// first setup battery client
if let localElements = meshNetworkManager.meshNetwork?.localProvisioner?.node?.elements {
for element: Element in localElements {
if let batteryModel = element.model(withSigModelId: .genericBatteryClient) {
if !batteryModel.isBoundTo(applicationKey) {
if let configModelAppBindMessage = ConfigModelAppBind(applicationKey: applicationKey, to: batteryModel) {
_ = try? meshNetworkManager.sendToLocalNode(configModelAppBindMessage)
}
}
}
if let healthModel = element.model(withModelId: .healthModelId, definedBy: .companyId) {
if !healthModel.isBoundTo(applicationKey) {
if let configModelAppBindMessage = ConfigModelAppBind(applicationKey: applicationKey, to: healthModel) {
_ = try? meshNetworkManager.sendToLocalNode(configModelAppBindMessage)
}
}
}
if let genericOnOffModel = element.model(withSigModelId: .genericOnOffClient) {
if !genericOnOffModel.isBoundTo(applicationKey) {
if let configModelAppBindMessage = ConfigModelAppBind(applicationKey: applicationKey, to: genericOnOffModel) {
_ = try? meshNetworkManager.sendToLocalNode(configModelAppBindMessage)
}
}
}
if let lightCtlModel = element.model(withSigModelId: .lightCTLClient) {
if !lightCtlModel.isBoundTo(applicationKey) {
if let configModelAppBindMessage = ConfigModelAppBind(applicationKey: applicationKey, to: lightCtlModel) {
_ = try? meshNetworkManager.sendToLocalNode(configModelAppBindMessage)
}
}
}
}
}
}
func startConfiguration(_ unicastAddress: Address?, deviceToIdentify: UnprovisionedDevice?) {
let discoveredPeripheral: DiscoveredPeripheral? = unprovisionedDevices.first { (device: UnprovisionedDevice, peripheral: CBPeripheral, rssi: Int32) in
device.uuid == deviceToIdentify?.uuid
}
let name = discoveredPeripheral?.peripheral.name ?? ""
let address = discoveredPeripheral?.peripheral.identifier.uuidString ?? ""
//clean up devices
unprovisionedDevices.removeAll { (device: UnprovisionedDevice, peripheral: CBPeripheral, rssi: Int32) in
device.uuid == deviceToIdentify?.uuid
}
if let unicastAddress: Address = unicastAddress {
let configService: ConfigurationService = ConfigurationService(manager: self.meshNetworkManager)
configService.configurationComplete = self.provisionCallback
configService.configure(unicastAddress: unicastAddress, name: name, address: address)
}
}
}
extension QBleMesh : MeshNetworkDelegate {
public func meshNetworkManager(_ manager: NordicMesh.MeshNetworkManager,
didReceiveMessage message: any NordicMesh.MeshMessage,
sentFrom source: NordicMesh.Address,
to destination: NordicMesh.MeshAddress) {
print("received a message -> \(message)")
print("received a message with opcode -> \(message.opCode)")
}
public func meshNetworkManager(_ manager: MeshNetworkManager,
failedToSendMessage message: MeshMessage,
from localElement: Element, to destination: MeshAddress,
error: Error) {
print("received error: \(error)")
switch error {
case let accessError as AccessError:
switch accessError {
case .timeout:
self.update(unicastAddress: destination.address, onOff: nil, luminosity: nil, temperature: nil, powerStatus: nil, onlineStatus: false)
default:
print("default case for AccessError")
}
default:
print("Unknown error occurred.")
}
}
} and here is NetworkConnection typealias DiscoveredPeripheral = (
device: UnprovisionedDevice,
peripheral: CBPeripheral,
rssi: Int32
)
class NetworkConnection: NSObject, Bearer {
private let connectionModeKey = "connectionMode"
/// Maximum number of connections that `NetworkConnection` can
/// handle.
static let maxConnections = 1
/// The Bluetooth Central Manager instance that will scan and
/// connect to proxies.
let centralManager: CBCentralManager
/// The Mesh Network for this connection.
let meshNetwork: MeshNetwork
/// The list of connected GATT Proxies.
var proxies: [GattBearer] = []
/// A flag set to `true` when any of the underlying bearers is open.
var isOpen: Bool = false
weak var delegate: BearerDelegate?
weak var dataDelegate: BearerDataDelegate?
weak var logger: LoggerDelegate? {
didSet {
proxies.forEach {
$0.logger = logger
}
}
}
var scanCallback: (_ discoveredPeripheral: DiscoveredPeripheral) -> Void = {_ in }
public var supportedPduTypes: PduTypes {
return [.networkPdu, .meshBeacon, .proxyConfiguration]
}
/// A flag indicating whether the network connection is open.
/// When open, it will scan for mesh nodes in range and connect to
/// them if found.
private var isStarted: Bool = false
/// Returns `true` if at least one Proxy is connected, `false` otherwise.
var isConnected: Bool {
return proxies.contains { $0.isOpen }
}
/// Returns the name of the connected Proxy.
var name: String? {
return proxies.first(where: { $0.isOpen })?.name
}
/// Whether the connection to mesh network should be managed automatically,
/// or manually.
var isConnectionModeAutomatic: Bool {
get {
return UserDefaults.standard.bool(forKey: connectionModeKey)
}
set {
UserDefaults.standard.set(newValue, forKey: connectionModeKey)
if newValue && isStarted && centralManager.state == .poweredOn {
centralManager.scanForPeripherals(withServices: [MeshProxyService.uuid], options: nil)
}
}
}
init(to meshNetwork: MeshNetwork) {
centralManager = CBCentralManager()
self.meshNetwork = meshNetwork
super.init()
centralManager.delegate = self
// By default, the connection mode is automatic.
UserDefaults.standard.register(defaults: [connectionModeKey : true])
showPermissionAlert()
}
func open() {
if !isStarted && isConnectionModeAutomatic &&
centralManager.state == .poweredOn {
if #available(iOS 13.0, *) {
if centralManager.authorization != .denied {
_ = startScanForPeripherals()
}else{
showPermissionAlert()
}
}
}
isStarted = true
}
func close() {
centralManager.stopScan()
proxies.forEach { $0.close() }
proxies.removeAll()
isStarted = false
}
func disconnectCurrent() {
proxies.first?.close()
}
func send(_ data: Data, ofType type: PduType) throws {
showPermissionAlert()
guard supports(type) else {
throw BearerError.pduTypeNotSupported
}
// Find the first connected proxy. This may be modified to find
// the closes one, or, if needed, the message can be sent to all
// connected nodes.
guard let proxy = proxies.first(where: { $0.isOpen }) else {
throw BearerError.bearerClosed
}
try proxy.send(data, ofType: type)
}
/// If manual connection mode is enabled, this method may set the
/// proxy that will be used by the mesh network.
///
/// - parameter bearer: The GATT Bearer proxy to use.
func use(proxy bearer: GattBearer) {
guard !isConnectionModeAutomatic else {
return
}
bearer.delegate = self
bearer.dataDelegate = self
bearer.logger = logger
proxies.filter { bearer.identifier != $0.identifier }.forEach { $0.close() }
proxies.append(bearer)
if bearer.isOpen {
bearerDidOpen(self)
}
}
func startScanForPeripherals() -> Bool {
showPermissionAlert()
centralManager.scanForPeripherals(withServices: [MeshProxyService.uuid, MeshProvisioningService.uuid],
options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
return true
}
func discoveredPeripherals(_ callback: @escaping (_ discoveredPeripheral: DiscoveredPeripheral) -> Void) {
scanCallback = callback
}
func stopScan() -> Bool {
centralManager.stopScan()
return true
}
func showPermissionAlert() {
if #available(iOS 13.0, *) {
if centralManager.authorization != .allowedAlways {
}
}
}
}
extension NetworkConnection: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
if isStarted && isConnectionModeAutomatic &&
proxies.count < NetworkConnection.maxConnections {
central.scanForPeripherals(withServices: [MeshProxyService.uuid], options: nil)
}
case .poweredOff, .resetting:
proxies.forEach { $0.close() }
proxies.removeAll()
default:
break
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any], rssi RSSI: NSNumber) {
if let unprovisionedDevice = UnprovisionedDevice(advertisementData: advertisementData) {
self.scanCallback((unprovisionedDevice, peripheral, RSSI.int32Value))
}
// Is it a Network ID or Private Network Identity beacon?
if let networkIdentity = advertisementData.networkIdentity {
guard meshNetwork.matches(networkIdentity: networkIdentity) else {
// A Node from another mesh network.
return
}
} else {
// Is it a Node Identity or Private Node Identity beacon?
guard let nodeIdentity = advertisementData.nodeIdentity,
meshNetwork.matches(nodeIdentity: nodeIdentity) else {
// A Node from another mesh network.
return
}
}
guard !proxies.contains(where: { $0.identifier == peripheral.identifier }) else {
return
}
let bearer = GattBearer(target: peripheral)
proxies.append(bearer)
bearer.delegate = self
bearer.dataDelegate = self
bearer.logger = logger
// Is the limit reached?
if proxies.count >= NetworkConnection.maxConnections {
// central.stopScan()
}
bearer.open()
}
}
extension NetworkConnection: GattBearerDelegate, BearerDataDelegate {
func bearerDidOpen(_ bearer: Bearer) {
guard !isOpen else {
return
}
isOpen = true
delegate?.bearerDidOpen(self)
}
func bearer(_ bearer: Bearer, didClose error: Error?) {
if let index = proxies.firstIndex(of: bearer as! GattBearer) {
proxies.remove(at: index)
}
if isStarted && isConnectionModeAutomatic &&
proxies.count < NetworkConnection.maxConnections {
centralManager.scanForPeripherals(withServices: [MeshProxyService.uuid], options: nil)
}
if proxies.isEmpty {
isOpen = false
delegate?.bearer(self, didClose: nil)
}
}
func bearerDidConnect(_ bearer: Bearer) {
if !isOpen, let delegate = delegate as? GattBearerDelegate {
delegate.bearerDidConnect(bearer)
}
}
func bearerDidDiscoverServices(_ bearer: Bearer) {
if !isOpen, let delegate = delegate as? GattBearerDelegate {
delegate.bearerDidDiscoverServices(bearer)
}
}
func bearer(_ bearer: Bearer, didDeliverData data: Data, ofType type: PduType) {
dataDelegate?.bearer(self, didDeliverData: data, ofType: type)
}
} |
Version
4.0.1 (Latest)
Ask the question
I updated from version 3.1.5 to version 4.0.1. I need to update many interfaces and the changes are huge. Is there any convenient way?
Relevant log output
No response
The text was updated successfully, but these errors were encountered: