STM32 Simple BLE Beacon
はじめに
STM32リーフを使ったシンプルなBLE Beaconのサンプルデザインです。 「HELLO BEACON」という文字列を一定期間送信してからスリープを繰り返します。
サンプルのソースコード
使用するスケッチやツールのソースコードは下記のリポジトリで閲覧可能です。
Sample-Sketches/STM32_Simple_Beacon at master · Leafony/Sample-Sketches
用意するもの
使用するリーフ
動作方法
スケッチの解説
フローチャート
STM32_Simple_Beacon.ino
のloop()
関数の動作は下図のように、STM32リーフとBLEリーフが交互にスリープ状態とアクティブ状態を一定の時間繰り返しながらBeaconのパケット(Advertising data)を送信することで、省電力なシステムを実現しています。
STM32リーフがStartAdvData()
を実行すると、BLEリーフでブロードキャストしたいAdvertising dataを設定し、送信を開始するコマンドを送ります。
BLEリーフがAdvertising中、STM32リーフは何もしないため、LowPower.deepSleep()
関数でディープスリープモードに移行し、WAKE_INTERVAL
で設定した時間が経過後、再びアクティブ状態に戻ります。この間、STM32リーフでは必要最小限の電力で動作できるように不要な回路ブロックの電源を落とす等をし、非常に省電力な状態で動作します。
STM32リーフがアクティブ状態に移行後、sleepBLE()
関数を実行し、BLEリーフのAdvertisingを停止させ、BLEリーフをスリープモードに移行させます。その後すぐにSTM32リーフ自身もLowPower.deepSleep()
関数でSLEEP_INTERVAL
で設定した時間ディープスリープモードに移行します。この状態においては極わずかな電力しか消費せず、SLEEP_INTERVAL
の時間を長くすればするほど電池の持ちを良くすることができます。
STM32リーフがディープスリープから復帰後、すぐにBLEリーフを起動させ、再びStartAdvData()
を実行して最初の処理に戻ります。
Advertising dataの仕様
STM32_Simple_Beacon.ino
のStartAdvData()
関数では、BLEリーフにAdvertising dataを設定し、BLE Client(PCやスマホ、Raspberry Pi等のLeafonyとBLE接続する機器)でLeafonyを検出した際に表示されるデバイス名を「Leaf_A」とし、ユーザデータとして「HELLO BEACON」という文字列を送信しています。
adv_data[]
配列がAdvertising dataです。この配列はコメントに記載されているように、AD Structure 1
~AD Structure 3
というデータの塊を繋げたデータとなっています。これらのデータの内容については後述します。
ble112.ble_cmd_le_gap_set_adv_data()
でadv_data
をBLEリーフに登録し、BLEリーフ側から登録完了の信号が来るのを待つために、ble112.checkActivity()
を実行しています。
ble112.ble_cmd_le_gap_start_advertising()
を実行することで、BLEがAdvertisingを開始して、先程設定したAdvertising dataをブロードキャストし始めます。LE_GA_SCANNABLE_NON_CONNECTALBE
を設定したことで、BLE Client側はAdvertising dataをスキャンすることはできますが、このデバイスと接続を確立することは禁止しています。これは、接続要求が来た場合に発生するイベントの処理を減らして電力を削減するための設定です。
void StartAdvData()
{
// Advertising data; 25byte MAX
uint8_t adv_data[] = {
// AD Structure 1: Flag
(2), //0: field length
BGLIB_GAP_AD_TYPE_FLAGS, //1: field type (0x01)
(6), //2: data
// AD Structure 2: Complete local name
(7), //3: field length
BGLIB_GAP_AD_TYPE_LOCALNAME_COMPLETE, //4: field type (0x09)
('L'), //5:
('e'), //6:
('a'), //7:
('f'), //8:
('_'), //9:
('A'), //10:
// AD Structure 3: Manufacture specific
(13), //11: field length
(0xff), //12: field type (0xff)
('H'), //13:
('E'), //14:
('L'), //15:
('L'), //16:
('O'), //17:
(' '), //18:
('B'), //19:
('E'), //20:
('A'), //21:
('C'), //22:
('O'), //23:
('N'), //24:
};
// Register advertising packet
uint8_t stLen = sizeof(adv_data);
ble112.ble_cmd_le_gap_set_adv_data(SCAN_RSP_ADVERTISING_PACKETS, stLen, adv_data);
while (ble112.checkActivity(1000));
// index = 0 LE_GAP_SCANNABLE_NON_CONNECTABLE / LE_GAP_UNDIRECTED_CONNECTABLE
ble112.ble_cmd_le_gap_start_advertising(0, LE_GAP_USER_DATA, LE_GAP_SCANNABLE_NON_CONNECTABLE);
while (ble112.checkActivity(1000));
}
下図はBLEのAdvertisingで使用される、Advertising dataのフォーマットを表しています。
Advertising dataは複数のAD Structure
というデータの塊から構成されています。各AD Structure
の中身はLength
とData
に分けられ、Length
には、Data
のオクテット数(何byteか)が登録されます。
Data
の中身は更に、AD Type
とAD Data
に分けられ、AD Type
でこのAD Structure
がどのような意味のデータなのかが分かるようになっています。
例えば、上記コードのAD Structure 2
はLength
が7で、AD Type
はBGLIB_GAP_AD_TYPE_LOCALNAME_COMPLETE (0x09)
でデバイスのローカルネームであることがわかり、Data
にLeaf_A
と登録されています。
AD Structure 3
のAD Type
は0xffで、このAD Structure
には任意のデータを登録することができます。Data
には「HELLO BEACON」というテキストが登録されていて、このデータを変えれば自由にデータをAdvertising dataに載せてブロードキャストすることができます。
BLEリーフの動作
- 各種設定
- イベントハンドラ