[英]have to initiate a BLE peripheral every time i use it in Swift
with CBCentralManager i succesully scan multiple BLE UART devices and connect to them, de devices are stored in the array periphirals[], but when i want to send data to them one by one, only the last one connected i can send succesfully send data to, i solved it by calling blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID])before writing data again, but i think this is not the right solution, can someone explain what i am doing wrong?使用 CBCentralManager 我成功扫描多个 BLE UART 设备并连接到它们,de 设备存储在数组 periphirals[] 中,但是当我想一个一个地向它们发送数据时,只有最后一个连接的我可以成功发送数据到,我在再次写入数据之前通过调用 blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID]) 解决了这个问题,但我认为这不是正确的解决方案,有人可以解释我做错了什么吗?
Below the code i use, the scanning and connecting start by didload and startCyclus starts the first device, after the data recieved "didUpdateValueFor" is entered, getting the data and direct send data to the next peripheral在我使用的代码下面,扫描和连接由 didload 和 startCyclus 启动第一个设备,在输入接收到的数据“didUpdateValueFor”后,获取数据并直接发送数据到下一个外设
import Foundation
import UIKit
import CoreBluetooth
var txCharacteristic : CBCharacteristic?
var rxCharacteristic : CBCharacteristic?
var blePeripheral : CBPeripheral?
var characteristicASCIIValue = NSString()
var Running = false
var currentNode = 0;
var updateService = false
var maxNodes = Int()
class ViewController : UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate{
//Data
var centralManager : CBCentralManager!
var RSSIs = [NSNumber]()
var data = NSMutableData()
var peripherals: [CBPeripheral] = []
var characteristicValue = [CBUUID: NSData]()
var timer = Timer()
var characteristics = [String : CBCharacteristic]()
var teller = 0
//UI
@IBOutlet weak var baseTableView: UITableView!
@IBOutlet weak var refreshButton: UIBarButtonItem!
@IBAction func naarRun(_ sender: Any) {
print("naarRun")
self.performSegue(withIdentifier:"naarRunView" , sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if (segue.identifier == "naarRunView") {
let vc = segue.destination as! ViewRun
vc.peripherals = peripherals
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//print("View Cleared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Stop Scanning")
centralManager?.stopScan()
}
/*Okay, now that we have our CBCentalManager up and running, it's time to start searching for devices. You can do this by calling the "scanForPeripherals" method.*/
func startScan() {
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: [ParticlePeripheral.BLEService_UUID] , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
Timer.scheduledTimer(withTimeInterval: 3, repeats: false) {_ in
self.cancelScan()
self.connectToAllDevices()
}
}
/*We also need to stop scanning at some point so we'll also create a function that calls "stopScan"*/
func cancelScan() {
self.centralManager?.stopScan()
print("Scan Stopped")
print("Number of Peripherals Found: \(peripherals.count)")
}
func disconnectFromDevice () {
if blePeripheral != nil {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
}
func restoreCentralManager() {
//Restores Central Manager delegate if something went wrong
centralManager?.delegate = self
}
/*
Called when the central manager discovers a peripheral while scanning. Also, once peripheral is connected, cancel scanning.
*/
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {
blePeripheral = peripheral
teller+=1
self.peripherals.append(peripheral)
self.RSSIs.append(RSSI)
peripheral.delegate = self
//self.baseTableView.reloadData()
//if blePeripheral == nil {
print("Found new pheripheral devices with services")
print("Peripheral name: \(String(describing: peripheral.name))")
print("**********************************")
print ("Advertisement Data : \(advertisementData)")
//}
}
//Peripheral Connections: Connecting, Connected, Disconnected
//-Connection
func connectToDevice () {
centralManager?.connect(blePeripheral!, options: nil)
}
func connectToAllDevices(){
var seconds = 0.0
for per in peripherals
{
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
blePeripheral = per
print("Connecting naar " + (blePeripheral?.name!)!)
self.connectToDevice ()
}
seconds = seconds + 0.5;
}
}
/*
Invoked when a connection is successfully created with a peripheral.
This method is invoked when a call to connect(_:options:) is successful. You typically implement this method to set the peripheral’s delegate and to discover its services.
*/
//-Connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("*****************************")
print("Connection complete")
print("Peripheral info: \(String(describing: blePeripheral))")
//Erase data that we might have
data.length = 0
//Discovery callback
peripheral.delegate = self
//Only look for services that matches transmit uuid
peripheral.discoverServices([ParticlePeripheral.BLEService_UUID])
/*
//Once connected, move to new view controller to manager incoming and outgoing data
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let uartViewController = storyboard.instantiateViewController(withIdentifier: "UartModuleViewController") as! UartModuleViewController
uartViewController.peripheral = peripheral
navigationController?.pushViewController(uartViewController, animated: true)
*/
}
/*
Invoked when the central manager fails to create a connection with a peripheral.
*/
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
if error != nil {
print("Failed to connect to peripheral")
return
}
}
func disconnectAllConnection() {
centralManager.cancelPeripheralConnection(blePeripheral!)
}
/*
Invoked when you discover the peripheral’s available services.
This method is invoked when your app calls the discoverServices(_:) method. If the services of the peripheral are successfully discovered, you can access them through the peripheral’s services property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
print("Discovered Services: \(services)")
}
/*
Invoked when you discover the characteristics of a specified service.
This method is invoked when your app calls the discoverCharacteristics(_:for:) method. If the characteristics of the specified service are successfully discovered, you can access them through the service's characteristics property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let characteristics = service.characteristics else {
return
}
print("Found \(characteristics.count) characteristics!")
for characteristic in characteristics {
//looks for the right characteristic
if characteristic.uuid.isEqual(ParticlePeripheral.BLE_Characteristic_uuid_Rx) {
rxCharacteristic = characteristic
//Once found, subscribe to the this particular characteristic...
peripheral.setNotifyValue(true, for: rxCharacteristic!)
// We can return after calling CBPeripheral.setNotifyValue because CBPeripheralDelegate's
// didUpdateNotificationStateForCharacteristic method will be called automatically
peripheral.readValue(for: characteristic)
print("Rx Characteristic: \(characteristic.uuid)")
}
if characteristic.uuid.isEqual(ParticlePeripheral.BLE_Characteristic_uuid_Tx){
txCharacteristic = characteristic
print("Tx Characteristic: \(characteristic.uuid)")
}
peripheral.discoverDescriptors(for: characteristic)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if error != nil {
print("\(error.debugDescription)")
return
}
guard let descriptors = characteristic.descriptors else { return }
descriptors.forEach { descript in
print("function name: DidDiscoverDescriptorForChar \(String(describing: descript.description))")
print("Rx Value \(String(describing: rxCharacteristic?.value))")
print("Tx Value \(String(describing: txCharacteristic?.value))")
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
} else {
print("Characteristic's value subscribed")
}
if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Message sent")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Succeeded!")
}
// MARK: - Getting Values From Characteristic
/** After you've found a characteristic of a service that you are interested in, you can read the characteristic's value by calling the peripheral "readValueForCharacteristic" method within the "didDiscoverCharacteristicsFor service" delegate.
*/
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
guard characteristic == rxCharacteristic,
let characteristicValue = characteristic.value,
let ASCIIstring = NSString(data: characteristicValue,
encoding: String.Encoding.utf8.rawValue)
else { return }
characteristicASCIIValue = ASCIIstring
let ontvangen = String(characteristicASCIIValue)
let waarde = haalwaarde(recieved: ontvangen)
print("Value Recieved: " + String(characteristicASCIIValue) )
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: self)
if(updateService){updateService=false; return}
if(!waarde.isNumber){print("waarde is no number");return}
if(Running ){Vervolg()}
}
func haalNode(recieved:String)->String{
//nodenr
if(recieved.count<10){return "fout";}
let temp = recieved
let lengte = recieved.count;
let start = temp.index(temp.startIndex, offsetBy: 7)
let end = temp.index(temp.endIndex, offsetBy: -(lengte-8))
let range = start..<end
let nodeNr = String(temp[range])
//print("nodeNr=", nodeNr)
return nodeNr
}
func haalwaarde(recieved:String)->String{
//Reactietijd
if(recieved.count<10){return "fout"};
let temp = recieved
let lengte = recieved.count;
let start = temp.index(temp.startIndex, offsetBy: 1)
let end = temp.index(temp.endIndex, offsetBy: -(lengte-7))
let range = start..<end
let Reactietijd = String(temp[range])
//print("\nreactietijd=", Reactietijd)
return Reactietijd
}
func startCyclus(){
currentNode = 0
if maxNodes == 0 {return}
Running = true
blePeripheral = peripherals[0]
updateService = true
blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID])
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.writeValue(data: "N 5000G55")
currentNode += 1
}
func Vervolg(){
print("vervolg")
if currentNode == maxNodes {Running = false;return}
blePeripheral = peripherals[currentNode]
updateService = true
blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID])
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) {
self.writeValue(data: "N 5000G55")
currentNode += 1
}
}
// Write functions
func writeValue(data: String){
print("schrijfdata " + String(currentNode))
let valueString = (data as NSString).data(using: String.Encoding.utf8.rawValue)
//change the "data" to valueString
if let blePer = blePeripheral{
if let txCharacteristic = txCharacteristic {
blePer.writeValue(valueString!, for: txCharacteristic, type: CBCharacteristicWriteType.withoutResponse)
}
}
}
/*
Invoked when the central manager’s state is updated.
This is where we kick off the scan if Bluetooth is turned on.
*/
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
// We will just handle it the easy way here: if Bluetooth is on, proceed...start scan!
print("Bluetooth Enabled")
startScan()
} else {
//If Bluetooth is off, display a UI alert message saying "Bluetooth is not enable" and "Make sure that your bluetooth is turned on"
print("Bluetooth Disabled- Make sure your Bluetooth is turned on")
let alertVC = UIAlertController(title: "Bluetooth is not enabled", message: "Make sure that your bluetooth is turned on", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "ok", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) -> Void in
self.dismiss(animated: true, completion: nil)
})
alertVC.addAction(action)
self.present(alertVC, animated: true, completion: nil)
}
}
}
extension String {
var isNumber: Bool {
let characters = CharacterSet.decimalDigits.inverted
return !self.isEmpty && rangeOfCharacter(from: characters) == nil
}
}
I think it's your logging is hiding what's really happening.我认为这是您的日志记录隐藏了真正发生的事情。
You reassign blePeripheral
before each connection, but if any of them take longer than 0.5 seconds, by the time didConnect
is called, the device that has connected won't be the one that's referred to by blePeripheral
.您在每次连接之前重新分配blePeripheral
,但如果其中任何一个花费的时间超过 0.5 秒,则在调用didConnect
时,已连接的设备将不再是blePeripheral
引用的设备。
I would suggest removing blePeripheral
entirely, and explicitly pass the CBPeripheral
object into connectToDevice
.我建议完全删除blePeripheral
,并将CBPeripheral
object 显式传递给connectToDevice
。 Also, in didConnect
, use the peripheral
parameter that's passed in.此外,在didConnect
中,使用传入的peripheral
参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.