BLE Beacon を探そう [PSoC]
PSoC Advent Calendar 2016の5日目の記事です。
3日目の記事で作成した BLE Beacon は Advertisement パケットを発信します。 発信されたパケットは、 Central または Observer 役のデバイスが「スキャン」することによって受信します。 今回の記事では、 CYALKIT-E03 Solar-Powered BLE Sensor 5 Pack から発信された BLE Beacon パケットを受信する Observer 役のアプリケーションを作成します。
使用するハードウェア
この記事では、上記のセンサキットに加えて、 CY8CKIT-042-BLE Bluetooth® Low Energy (BLE) Pioneer Kit も使用します。 CY8CKIT-042-BLE のベースボードにドータボード CY8CKIT-142: PSoC 4 BLE Module を搭載し、受信したパケットの情報を UART で出力し、 KitProg の仮想シリアルを通じて PC で観測します。
回路図
必要なコンポーネントは、 BLE と UART だけです。 あとは、ファームウェアで BLE を制御し、取得した情報を UART で表示させます。
クロック設定
CY8CKIT-142 モジュールには、 24MHz と 32.768kHz の二つの水晶が搭載されています。 このアプリケーションでは、高速クロックとして、 24MHz 水晶で作ったクロックをそのまま使用します。 内蔵クロックの IMO は使用しないので、止めてしまっています。
低速クロックも外部水晶で作ったクロックを使用します。 内蔵クロックの ILO は止めています。 このアプリケーションでは、低速タイマは使用していません。
BLE コンポーネントの設定
先に述べたように、 BLE コンポーネントは、 "Observer" 役として作成します。 General タブで、 "Broadcaster/Observer" を選択し、さらに "Observer" を選択します。 これで、 "Observer" 役のデバイスを作成できるようになります。
この時に「GAP Settings の内容を削除しても良いか」というダイアログが現れますが、このプロジェクトでは必要ありませんので削除されても大丈夫です。
次は、 "GAP Settings" タブの "General" ノードを設定します。 ここでは、 "Device name" を設定できますが、 "Observer" 役は電波を受信するだけで送信する事がありません。 したがって、ここに何らかの名前を入れても使われる事がありません。 使われないとはわかっていますが、 "Observer" と入れてみました。
"Scan settings" ノードでは、 Advertisement パケットの「スキャン」を行う際の設定を行います。
"Scanning state" は "Active" として、常にスキャンを行わせます。 また、 "Filter policy" は、 "All" として、すべての Advertisement パケットを受信できるようにします。 受信したパケットを使うか否かは、ファームウェアで判断します。
"Fast scan parameters" で "Scan timeout" のチェックをはずすと、永遠に "Fast scan" が実行されるようになります。 この時、どのようなタイミングで受信機を動作させるかを表すのが "Scan window" と "Scan interval" です。 これらの時間を調整する事で、スキャンのタイミングを制御する事ができます。
"Advanced" タブでは、 "Use BLE low power mode" のチェックを外します。 ここで作成するアプリケーションでは消費電力など考えず、動き続ける事を目的としているので、 "low power mode" に入らないようにしておきます。
以上で、 BLE コンポーネントの設定は終わりです。
UART コンポーネントの設定
UART コンポーネントの "UART Basic" タブでは、通信に使われるフォーマットを指定します。 ボーレートには、最近よく使われる 115200bps を使用しています。
このダイアログでは、 "Oversampling" の項目も変更しています。 "Oversampling" は、デフォルトでは 12 に設定されているのですが、 12 のままだと実際のボーレートが 117647bps (+1.2%) となってしまい、 UART で通信するには誤差が大きくなってしまいます。
そこで、 "Oversampling" を 16 に設定しました。 これにより、ボーレートは 115385bps (+0.2%) となっています。
"UART Advanced" タブでは、バッファのサイズと割り込みの使用方法を設定します。 まず、 "TX buffer size" を 64 に設定します。 これは、受信したパケットの情報を表示する間も BLE の通信を継続させるためです。 これにより、長いメッセージを表示させる場合でも、 UART の通信を待つことがなくなります。 一方、 "RX buffer size" は、デフォルトの 8 のままにしておきます。
"TX buffer size" を設定する事で、割り込みのモードが "None" から "Internal" に変わります。 これは、バッファの処理に内部で定義した割り込み処理ルーチンを使うためです。 アプリケーションでは、割り込みを使いませんので、 "Interrupt sources" のすべてのチェックをはずしておきます。
端子の設定
割り当てを設定しなくてはならない端子は、 UART の RX/TX だけです。 それぞれ P1[4]/P1[5] に割り当てます。 これらの端子は、 CY8CKIT-042-BLE キットに搭載された KitProg の UART 信号に接続されています。 これで、 KitProg の仮想シリアルを使って通信を行う事ができます。
ファームウェア
ユーザのファームウェアは、いつものように main.c
にまとめられています。
#include <project.h> #include <stdio.h> // Beaconのパケット構造体 struct BeaconPacket { uint8 length1; // 02 uint8 adType1; // 01 uint8 adData1; // 04 uint8 length2; // 1A uint8 adType2; // FF uint8 companyId[2]; // 4C 00 uint8 deviceType; // 02 uint8 length3; // 15 uint8 uuid[16]; // 00 05 00 01 00 00 10 00 80 00 00 80 5F 9B 01 31 uint8 major[2]; // 00 xx uint8 minor[2]; // xx xx uint8 rssi; // xx };
最初に Beacon パケットの構造体を宣言しています。 このアプリケーションでは、この構造体のフォーマットにそったパケットのみを取り扱います。 これ以外の長さやフォーマットのパケットは無視されます。 パケットの詳細は、 CYALKIT-E02 Solar-Powered BLE Sensor Beacon Reference Design Kit (RDK) の関連文書を参照してください。
// Advertisementパケットの情報を格納する変数 CYBLE_GAPC_ADV_REPORT_T advReport; // 受信したパケットを格納する変数 struct BeaconPacket beaconPacket;
Advertisement パケットを受信した時、パケットの中身以外にパケットの送信元などの情報が引き渡されます。 ここでは、その情報を受け取るための変数として advReport を宣言しています。 さらに、 beaconPacket として、パケットの中身を受け取る変数も宣言しています。
// 探すべきUUID const uint8 targetUuid[16] = { 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x01, 0x31 }; // 探すべきID(major) uint8 id = 0; // 着目するID
受信したパケットが、目的の Beacon から送られてきたものか否かを判断するために、 UUID と ID を確認します。 ここで宣言された targetUuid と受信したパケットの uuid とが比較されます。 一方の ID は、8ビットの変数になっています。 このアプリケーションでは、 ID を0から255までの値に限定しており、 UART から指定する事ができます。
// Reportの中身を格納する変数群 volatile CYBIT reportUpdated = 0; // Report更新フラグ uint8 temp; // 温度データ uint8 humid; // 湿度データ int8 rssi; // RSSIデータ
パケットを受信したら、そこから必要な情報を取り出して、これらの変数に格納しておきます。 そして reportUpdated フラグをセットして、変数が更新されたことをメインループに通知します。
// BLEのイベントを処理するハンドラ void StackEventHandler(uint32 event, void *eventParam) { switch (event) { //====================================================== // 必須イベント //====================================================== case CYBLE_EVT_STACK_ON: // BLEスタックが構築された // 高速なBLEスキャンを開始する。スキャンは止まらない。 CyBle_GapcStartScan(CYBLE_SCANNING_FAST); break;
BLE のスタックからイベントを受け取り、処理を行うハンドラです。 BLE スタックが構築されたら、イベント CYBLE_EVT_STACK_ON が発行されます。 ここでは、 Advertisement パケットを受信する「スキャン」動作を開始します。 このアプリケーションでは、一度始めた「スキャン」は、止めません。 電源の続く限り、「スキャン」を行い、 Advertisement パケットを探し続けます。
//====================================================== // GAPイベント //====================================================== case CYBLE_EVT_GAPC_SCAN_START_STOP: // BLEスキャンが開始・停止された // 何もしない break;
GAP 関連のイベント CYBLE_EVT_GAPC_SCAN_START_STOP は、「スキャン」動作が開始または停止された時に発行されます。 このアプリケーションでも、「スキャン」が開始された時にこのイベントが発行されますが、特に何も行いません。
case CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT: // BLEスキャンがデバイスを見つけた { // Reportデータをコピーする advReport = *(CYBLE_GAPC_ADV_REPORT_T *)eventParam; // Reportパケットの長さが期待される長さであるか確認する if (advReport.dataLen == sizeof beaconPacket) { // Reportパケットをバッファにコピーする memcpy(&beaconPacket, advReport.data, advReport.dataLen); // 見つけたBeaconが着目しているBeaconか確認する // UUIDフィールドとMAJORフィールドだけを検証する if ( (memcmp(beaconPacket.uuid, targetUuid, sizeof targetUuid) == 0) && (beaconPacket.major[0] == 0x00) && (beaconPacket.major[1] == id) ) { // 取り出したい情報をコピーする rssi = advReport.rssi; humid = beaconPacket.minor[0]; temp = beaconPacket.minor[1]; // Report更新フラグをセットする reportUpdated = 1; } } } break;
Advertisement パケットを受信した時に発行されるのが、イベント CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT です。 受信したパケットに関する情報は、ハンドラの引数 eventParam で渡されます。 着目している Beacon から発信されたパケットである事を確認したら、必要な情報を変数にコピーして、更新フラグをセットします。
//====================================================== // 汎用イベント //====================================================== case CYBLE_EVT_TIMEOUT: // 時間切れイベント // 何もしない break; //====================================================== // 処理されないイベント //====================================================== default: // その他のイベントは単に無視する break; } }
その他のイベントが発行される事もありますが、処理せずにハンドラを終えます。 イベントの処理は、これだけです。
int main(void) { // 割り込みを許可する CyGlobalIntEnable; // UARTを起動する UART_Start(); // BLEを起動する { CYBLE_API_RESULT_T apiResult; apiResult = CyBle_Start(StackEventHandler); // BLEスタックの初期化が成功したか確認する CYASSERT(apiResult == CYBLE_ERROR_OK); } // 初期メッセージを表示する UART_UartPutString("Beacon Observer\r\n");
main()
関数の冒頭では、割り込みを許可し、 UART コンポーネントと BLE コンポーネントの初期化を行います。
次に、最初のメッセージを UART に出力します。
for(;;) { // BLEスタックのイベントを処理する CyBle_ProcessEvents(); // Reportパケットが到着したか確認する if (reportUpdated) { char buffer[64]; // UART出力のバッファ int16 t, h; // 温度と湿度を格納する変数 // 更新フラグをクリアする reportUpdated = 0; // 温度と湿度を1/10単位の整数で計算する t = ((17572L * temp) / 256 - 4685 + 5) / 10; h = ((12500L * humid) / 256 - 600 + 5) / 10; // Reportパケットの内容を表示する sprintf(buffer, "ID=%d TEMP=%d.%d HUMID=%d.%d RSSI=%d\r\n", id, t/10, t%10, h/10, h%10, rssi); UART_UartPutString(buffer); }
メインループの前半では、 BLE スタックに関連した処理を行い、着目した Advertisement パケットが見つかった場合は、 UART への出力処理を行います。 Beacon から届いたパケットには、温度と湿度の情報がセンサから取り出したままのデータが含まれています。 このまま表示されても人間には理解できませんので、センサの仕様にしたがって摂氏温度とパーセント湿度を計算して表示しています。
出力には、 RSSI という電波強度を示す数値も表示されます。
// 着目するBeaconのIDを変更する { uint32 ch = UART_UartGetChar(); if (ch) { // UARTから有効な文字を検出した char buffer[64]; // IDを計算して格納する // 0..9 が有効 その他の文字も使おうと思えば使える id = ch - '0'; // 新しいIDを表示する sprintf(buffer, "SET ID=%d\r\n", id); UART_UartPutString(buffer); } } } }
UART の入力を使って、着目するセンサの ID が変更できるようになっています。 ID を計算するために、単純に文字コードから '0' ($30) を減じています。 このため、 '1' を入れると ID=1 に設定され、 'A' を入れると ID=17 に設定されます。 ID が設定されたら、設定後の ID が表示されます。
実行結果
実行すると、仮想シリアルにこのようなレポートが上がってきます。 この例では、1から6まで UART から文字を送り、それぞれのセンサの値を取得しています。
プロジェクトアーカイブ
この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できます。
参考サイト
- CY8CKIT-042-BLE Bluetooth® Low Energy (BLE) Pioneer Kit
- この記事で使用した開発キットです。 BLE 関連アプリケーションの作成が可能です。
- CY8CKIT-142: PSoC 4 BLE Module
- 上記のキットに含まれているドータボードです。 今回は、 PSoC 4 BLE を使ってアプリケーションを作成していますが、 PRoC BLE や EZ-BLE モジュールでも使用できます。
- CYALKIT-E02 Solar-Powered BLE Sensor Beacon Reference Design Kit (RDK)
- Wireless Sensor Node (WSN) の実験に使用できるリファレンスキットです。 このキットには、センサーノードがひとつ入っています。 このノードには、 ID=1 が付いています。
- CYALKIT-E03 Solar-Powered BLE Sensor 5 Pack
- 上記キットのセンサーノードだけを5個パックにしたキットです。 ID=2 から ID=6 までが、あらかじめ割り当てられています。
コメント 0