chibi:bit에 CoreBluetooth로 연결하기

chibi:bit에 CoreBluetooth로 연결하기



chibi : 비트가 스위치 과학에서 공식적으로 출시 되었기 때문에
iOS의 CoreBluetooth를 사용하여 협력을 시도했습니다.

chibi: 비트는?



다음은 스위치 과학 페이지에서 발췌한 것입니다.

//mag.switch-science.com/2016/12/19/chibibit_release/더 발췌
chibi:bitは、イギリスの教育向けマイコンボード「BBC micro:bit」の互換機です。
chibi:bitには工事設計認証(いわゆる技適)付きのBLEモジュールを搭載しており、日本国内で使用することができます。
(BBC micro:bitには技適が無いため、日本国内では使用できません)

micro:bit이란?



BBC는 어린이 프로그래밍 교육용 보드입니다.
Scratch와 같은 GUI 외에도 python, js, C++에서 개발할 수 있습니다.
C++의 경우는 chibi:bit나 micro:bit의 IDE가 아니라 mbed의 IDE를 사용합니다.
아래 사진의 왼쪽에서 본가 BBC micro:bit, chibi:bit, chibi:bit 테스트판입니다.


htp // 미 c로비 t. 오 rg
htps //w w. 인후 q. 코 m / jp / 네 ws / 2015/07 /

Bluetooth Button Service 감지



chibi : bit에는 전용 IDE 환경이 준비되어 있으므로,
그것을 사용하여 다음과 같은 코드를 그려 보았습니다.
htp // 치비비 t. 이오 / 이데 /

새 프로젝트에서는 메뉴에 블루투스가 표시되지 않으므로 메뉴 아래의 + 버튼에서 블루투스를 선택하여 추가합시다.


이때 블루투스와 라디오 중 하나를 삭제하게 되므로 라디오를 삭제해 주십시오.


그리고 메뉴에서 다음과 같은 코드를 그려 보았습니다.
기동시의 메세지, 접속시의 표시, 접속시의 ButtonService의 개시, 단절시의 표시에 대해서 기재하고 있습니다.


chibi : bit에 설치



chibi:bit은 PC에 연결하면 외부 스토리지로 인식될까 생각합니다. IDE의 "Download"버튼으로 떨어지는 파일을 드래그 앤 드롭으로 복사하면 설치가 완료됩니다.

iOS 측 샘플 코드



iOS측은 센트럴로서 주변기기인 chibi:bit에 접속합니다.

접속하는데 필요한 UUID의 정보는 MicroBitService 에 Enum로 정리해 정의해 일어났습니다.
import Foundation
import CoreBluetooth

enum MicroBitService {
    case button
    case accelerometer
    case ioPin
    case led
    case magnetometer
    case temperature
    case uart
    case eventService


    func uuid() -> CBUUID {
        switch self {
        case .button:
            return CBUUID(string: "E95D9882-251D-470A-A062-FA1922DFA9A8")
        case .accelerometer:
            return CBUUID(string: "E95D0753-251D-470A-A062-FA1922DFA9A8")
        case .ioPin:
            return CBUUID(string: "E95D127B-251D-470A-A062-FA1922DFA9A8")
        case .led:
            return CBUUID(string: "E95Dd91D-251D-470A-A062-FA1922DFA9A8")
        case .magnetometer:
            return CBUUID(string: "E95DF2D8-251D-470A-A062-FA1922DFA9A8")
        case .temperature:
            return CBUUID(string: "E95D6100-251D-470A-A062-FA1922DFA9A8")
        case .uart:
            return CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
        case .eventService:
            return CBUUID(string: "")
        }
    }

    func characteristics() -> [CBUUID] {
        switch self {
        case .button:
            return [
                ButtonCharacteristic.button1State.uuid(),
                ButtonCharacteristic.button2State.uuid()
            ]
        case .accelerometer:
            return [
                AccelerometerCharacteristic.data.uuid(),
                AccelerometerCharacteristic.period.uuid(),
            ]
        case .ioPin:
            return [
                IoPinCharacteristic.pinData.uuid(),
                IoPinCharacteristic.pinAdConfiguration.uuid(),
                IoPinCharacteristic.pinIoConfiguration.uuid()
            ]
        case .led:
            return [
                LedCharacteristic.matrixState.uuid(),
                LedCharacteristic.text.uuid(),
                LedCharacteristic.scrollingDelay.uuid()
            ]
        case .magnetometer:
            return [
                MagnetometerCharacteristic.data.uuid(),
                MagnetometerCharacteristic.period.uuid(),
                MagnetometerCharacteristic.bearing.uuid()
            ]
        case .temperature:
            return [
                TemperatureCharacteristic.temperature.uuid()
            ]
        case .uart:
            return [
                UartCharacteristic.rx.uuid(),
                UartCharacteristic.tx.uuid()
            ]
        case .eventService:
            return [
            ]
        }
    }

    private enum AccelerometerCharacteristic: String {
        case data   = "E95DCA4B-251D-470A-A062-FA1922DFA9A8"
        case period = "E95DFB24-251D-470A-A062-FA1922DFA9A8"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum ButtonCharacteristic: String {
        case button1State = "E95DDA90-251D-470A-A062-FA1922DFA9A8"
        case button2State = "E95DDA91-251D-470A-A062-FA1922DFA9A8"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum IoPinCharacteristic: String {
        case pinData            = "E95D8D00-251D-470A-A062-FA1922DFA9A8"
        case pinAdConfiguration = "E95DDA90-251D-470A-A062-FA1922DFA9A8"
        case pinIoConfiguration = "E95DDA91-251D-470A-A062-FA1922DFA9A8"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum LedCharacteristic: String {
        case matrixState    = "E95D7b77-251D-470A-A062-FA1922DFA9A8"
        case text           = "E95D93EE-251D-470A-A062-FA1922DFA9A8"
        case scrollingDelay = "E95D0d2d-251D-470A-A062-FA1922DFA9A8"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum MagnetometerCharacteristic: String {
        case data    = "E95Dfb11-251D-470A-A062-FA1922DFA9A8"
        case period  = "E95D386C-251D-470A-A062-FA1922DFA9A8"
        case bearing = "E95D9715-251D-470A-A062-FA1922DFA9A8"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum TemperatureCharacteristic: String {
        case temperature = "E95D9250-251D-470A-A062-FA1922DFA9A8"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum UartCharacteristic: String {
        case rx = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
        case tx = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }

    private enum EventServiceCharacteristic: String {
        case microbitRequirements = "E95DB84C-251D-470A-A062-FA1922DFA9A8";
        case microbitEvent        = "E95D9775-251D-470A-A062-FA1922DFA9A8";
        case clientRequirements   = "E95D23C4-251D-470A-A062-FA1922DFA9A8";
        case clientEvent          = "E95D5404-251D-470A-A062-FA1922DFA9A8";

        func uuid() -> CBUUID {
            return CBUUID(string: self.rawValue)
        }
    }
}


이번은 샘플이므로 잡히 각종 델리게이트를 ViewController에 붙였습니다.
import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
    let manager: CBCentralManager = CBCentralManager()
    var peripherals: [CBPeripheral] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        manager.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func tappedScan(_ sender: Any) {
        if manager.isScanning {
            debugPrint("stop scan")
            manager.stopScan()
        } else {
            debugPrint("scan start")
            manager.scanForPeripherals(withServices: nil, options: nil)
        }
    }

    @IBAction func tappedDisconnect(_ sender: Any) {
        peripherals.forEach { (peripheral) in
            manager.cancelPeripheralConnection(peripheral)
        }
    }

    // MARK: - CBCentralManagerDelegate
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        debugPrint(#function)
        var stateString = ""
        switch central.state {
        case .poweredOff:
            stateString = "powerOff"
        case .poweredOn:
            stateString = "powerOn"
        case .resetting:
            stateString = "resetting"
        case .unauthorized:
            stateString = "unauthorized"
        case .unknown:
            stateString = "unknown"
        case .unsupported:
            stateString = "unsupported"
        }
        debugPrint("central state: \(stateString)")
    }
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        debugPrint("\(#function), peripheral: \(peripheral.name)")
        peripheral.discoverServices([MicroBitService.button.uuid()])
//        peripheral.discoverServices(nil)
    }
    func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
        debugPrint(#function)
    }
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        debugPrint("\(#function), pripheral: \(peripheral.name)")
    }
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        debugPrint("\(#function), peripheral: \(peripheral.name)")
    }
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
//        debugPrint(#function)
        if peripheral.name?.range(of: "micro:bit") != nil{
            debugPrint("didDiscover, peripheral: \(peripheral.name)")
            if peripherals.filter({ (keepedPeripheral) -> Bool in
                return keepedPeripheral.identifier == peripheral.identifier ? true : false
            }).count == 0 {
                peripherals.append(peripheral)
                peripheral.delegate = self
            }
            manager.connect(peripheral, options: nil)
        }
    }

    // MARK: - CBPeripheralDelegate
    func peripheralDidUpdateName(_ peripheral: CBPeripheral) {
        debugPrint(#function)
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        debugPrint(#function)
        peripheral.services?.forEach({ (service) in
            debugPrint("ServiceUUID: \(service.uuid)")
            peripheral.discoverCharacteristics(MicroBitService.button.characteristics(), for: service)
//            peripheral.discoverCharacteristics(nil, for: service)
        })
    }

    func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
        debugPrint(#function)
    }

    func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
        debugPrint(#function)
    }

    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
        debugPrint(#function)
    }
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?) {
        debugPrint(#function)
    }
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        debugPrint(#function)
        service.characteristics?.forEach({ (characteristic) in
            debugPrint("CharacteristicUUID: \(characteristic.uuid)")
            peripheral.setNotifyValue(true, for: characteristic)
//            peripheral.readValue(for: characteristic)
        })
    }
    func peripheral(_ peripheral: CBPeripheral, didDiscoverIncludedServicesFor service: CBService, error: Error?) {
        debugPrint(#function)
    }
    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
        debugPrint(#function)
    }
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        debugPrint("\(#function): \(characteristic.value)")
    }
    func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
        debugPrint(#function)
    }
    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
        debugPrint(#function)
    }
}

샘플이므로 화면은 꽤 빼고 이런 느낌입니다.


Scan을 시작하면 ButtonService에서 ButtonCharacteristic을 검색하고 변경 감지를 위해 setNotifyValue를 실행합니다.
안전한 연결이 완료되면 A 버튼을 눌러 Xcode 콘솔 로그에 변경 감지 로그가 표시되는지 확인하십시오.

※나의 환경에서는 B버튼의 Characteristic가 검출되지 않고, B버튼을 눌렀을 때의 이벤트를 검지할 수 없습니다. 원인을 조사 중입니다.

Tips?



드물게 chibi:bit가 아무리 Scan해도 발견되지 않는 등의 현상이 발생합니다. 현재 내가 알고있는 방법으로 cibhi : bit를 페어링 모드로 설정하고 micro : bit 앱으로 페어링을 시도하는 것입니다.
iOS의 Bluetooth에서 chibi:bit는 기기 등록에서 해제해 주세요.

마지막으로



이번에는 ButtonService의 감지를 시도했지만,
마찬가지로 Accelerometer나 LED, Temperature등의 값도 같은 방법으로 읽을 수 있을까 생각합니다(아직 시도하지 않았다...)
iOS에서 CoreBluetooth를 시도 할 때 iOS끼리 외에도 Konashi와 같은 보드가 자주 사용되는 것을 보지만, cibhi : bit은 Konashi보다 약간 싸기 때문에 앞으로 CoreBluetooth를 공부하는 것이 좋습니다. 어쩌면
htps //w w. 슈 tch-s 시엔세. 코 m/타타 g/2900/

좋은 웹페이지 즐겨찾기