chakokuのブログ(rev4)

日々のごった煮ブログです

BLEを動かすためにnRF52840のボードを買った->CircuitPythonによるBLE Keyboardが動いた

本来の目的が何なのか分からなくなっているが、道楽だからいいだろうということで、、nRF52840のボードを買った。外観は以下

目の前の目的はBLEでiOSと接続できるKeyboard風SWを実現するため。CircuitPythonを焼いて、modulesで使えるモジュールを表示させた。どうもBLEのライブラリが無いようなのだが。。なぜか!?

Adafruit CircuitPython 7.0.0 on 2021-09-20; Adafruit Feather nRF52840 Express with nRF52840
>>> help('modules')
__main__          bitmaptools       math              sharpdisplay
_bleio            board             microcontroller   storage
adafruit_bus_device                 builtins          micropython       struct
adafruit_pixelbuf busio             msgpack           supervisor
aesio             collections       neopixel_write    synthio
alarm             countio           onewireio         sys
analogio          digitalio         os                terminalio
array             displayio         pulseio           time
atexit            errno             pwmio             touchio
audiobusio        fontio            rainbowio         traceback
audiocore         framebufferio     random            ulab
audiomixer        gc                re                usb_cdc
audiomp3          getpass           rgbmatrix         usb_hid
audiopwmio        io                rotaryio          usb_midi
binascii          json              rtc               vectorio
bitbangio         keypad            sdcardio          watchdog
Plus any modules on the filesystem

BLEは組み込まれておらず、外部モジュールとして手動で加えるようであった。。
https://github.com/adafruit/Adafruit_CircuitPython_BLE
adafruitのbundleを落としてきて、ZIPを解凍して、BLEライブラリをCopy&Pasteするようであった。

iOSと接続している実装例がAdafruit社から出ていて、コードの冒頭は以下である。これらのライブラリを入手してセットアップする必要がある。(
https://learn.adafruit.com/ble-hid-keyboard-buttons-with-circuitpython/ble-keyboard-buttons-libraries-and-code
)

import adafruit_ble
from adafruit_ble.advertising import Advertisement
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.standard.hid import HIDService
from adafruit_ble.services.standard.device_info import DeviceInfoService
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode

V7のbundleを展開して、adafruit_ble , adafruit_hidを nRF52840にコピーした。これにより上記のライブラリ importはエラーなく実行できたが、ソースコード本体の実行でエラーが出た。特に、、
adafruit_bleモジュール内に BLERadioクラスがある前提で書かれているが、このクラスがどこか別のモジュールに移っているようである。あるいは、、使い方が変わったのか??

ble = adafruit_ble.BLERadio()

BLE Keyboard Buttons Libraries and Code | BLE HID Keyboard Buttons with CircuitPython | Adafruit Learning System

# PyLint can't find BLERadio for some reason so special case it here.
ble = adafruit_ble.BLERadio()  # pylint: disable=no-member

https://www.digikey.com/en/maker/projects/circuitpython-ble-multi-temperature-monitoring/5c208beeafa74418a59e1fafde853ae9

再起動してdir()関数で確認するとBLERadioが存在した。先ほどエラーになったのは、adafruit_bleを何かで上書きしてしまったせいだろうか。

Adafruit CircuitPython 7.0.0 on 2021-09-20; Adafruit Feather nRF52840 Express with nRF52840
>>> import adafruit_ble
>>> dir(adafruit_ble)
['__class__', '__name__', '__file__', '__path__', '__version__', 'Service', '_bleio', 'advertising', 'characteristics', 'sys', 'services', 'Advertisement', '__repo__', 'BLEConnection', 'BLERadio', 'attributes']

Git上にあったBLE_HIDサンプルを動かしてみた。
https://github.com/adafruit/Adafruit_CircuitPython_BLE/blob/main/examples/ble_hid_periph.py

エラーなく動作して、iOSではペアリングまで行えた。以下はCircutPython側のログ表示

advertising
Start typing:
a1
i1
u1
e1
o1

Basicで言うところのinkey$関数のような動作をしているので、nRF52840と接続しているシリアルコンソール(REPL画面)からaiueoと打ち込んだ。以下はiOSの画面。BLEキーボードからキー入力されたと認識され、「あいうえお」と表示された。

まとめ
MicroPython版のESP32用BLEライブラリではiOSと接続できてもペアリングまで進められなかった。CircuitPythonの場合、ペアリングも可能でキーボード入力まで行えた。なお、、MicroPython版のSTM32用BLEライブラリだと、NimBLEが使われており、ペアリングも可能かもしれない。が、、適当なSTM32ボードが見つけられなかった(たしか。なぜCircuitPythonに切り替えたのだったか、少し忘れかけているが。) 自分に実力があったらESP32 + MicroPythonでBLEライブラリをデバッグしてなんとかペアリングも実装してしまえるのだろうけど、、そんな余力も時間も知力もない。ということで、、今後BLEのアプリを作る場合は、動作が安定しているCircuitPythonを使うことにする。夜の8時過ぎにボードが届いて、CiruitPythonのファームをボードに焼いて、適当に調べながら2時間ぐらいでBLE Keyboardの試作が動いた。CircuitPythonのBLEは作りこまれているなーと感心いたします。

■追記
adafruit_bleのソースを読んでみたが、ハードレイヤーを制御するコードが全くなかった。よく見ると、import _bleioを実行しており、そっちに任せているようであった。改めて組み込みモジュールを再確認すると、、_bleioが存在していた。(見落としていた)

>>> import _bleio
>>> dir(_bleio)
['__class__', '__init__', '__name__', 'Adapter', 'Address', 'Attribute', 'BluetoothError', 'Characteristic', 'CharacteristicBuffer', 'Connection', 'Descriptor', 'PacketBuffer', 'RoleError', 'ScanEntry', 'ScanResults', 'SecurityError', 'Service', 'UUID', 'adapter', 'set_adapter']

_bleioのソースは確認していないけど、BLEコントローラを制御していると思われる。(といっても、ミドルウエアを介してハードを制御しているのだろうと推測しますが)

ご参考
最新版のBundle
https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20211207/adafruit-circuitpython-bundle-7.x-mpy-20211207.zip