UI・センサー関連

ディスプレイ(OLED)

概要

本製品には前面部に有機ELディスプレイ(以下OLED)を搭載しています。ここではOLEDをレシピ言語から制御する方法を紹介します。

OLED機能の特徴

OLED機能の特徴を以下に示します。

OLED仕様

※OLEDは発光し続けると焼付きや寿命が早まる(暗くなる)等の性質があります。システムとして表示している内容を一定時間(10秒)で消灯する設計をしています。表示し続けたい場合は定期的に表示命令を呼ぶ事で点灯状態を維持することが可能ですが、点灯を継続することはOLEDの劣化を招きますので注意ください。


OLEDのシステムからの利用

本製品が起動時する際にOLEDの表示機能を利用しています。またボタンを押下した際にも時計や状態表示としてシステムからOLEDへの表示を行なっています。このためユーザ利用の際にはこのシステムからの表示との競合が起こりますので、意図した表示にする際には、システムからの表示タイミングを理解しておく必要があります。

[システムからの利用タイミング]

OLEDシステム利用

[ユーザ表示の強制表示]

デバッグ等でボタン押下でユーザ画面を表示したい場合に、システムからの利用タイミングにも強制的にユーザ画面を表示する機能も提供されています。
APIの第1引数に「実行権限」があり、ここに「OLC_CHAR_FORCE」を指定することにより強制的に描画を行います。強制的に描画する際には今ある画面に上書きをすることから、現在表示されている画面に書いた文字が重なる事になるので注意が必要です。

OLEDの強制書込

ボタン押下時に文字表示を行う場合にこの状態になりますので、この場合はスペースなどで空白文字で行末まで埋めて表示する必要があります。


OLEDの制御

OLEDのAPI

OLEDを制御するAPIは以下となります。

API 内容
1 OLC_DisplayPict() 時計画面/状態画面を表⽰する
2 OLC_DisplayChar() 指定した文字列を表示する
3 OLC_DisplayFree() 任意のピクセルを表示する

OLC_DiplayPict ()

OLEDに時計画面、または状態画面を表示するAPIになります。

OLC_DisplayPict(uint8 id);
   id : 画面の種類
        OLC_PICT_STATE  : 時計画面
        OLC_PICT_SET    : 状態画面

時計画面は電源起動時やボタンを1秒以下で押下した時に表示される画面です。
状態画面は時計画面が表示されている間にもう一回ボタンを押下すると切り換わるります。

画面のイメージは以下の通りです。

OLEDの表示画面

[コード例]
#incliude "olcAPI.h"
   ~
func any_func() {

    OLC_DisplayPict(OLC_PICT_STATE);

    return(0);
}

上記サンプルコードは時計画面を表示します。


OLC_DiplayChar ()

OLEDに文字を表示するAPIとなります。

OLC_DisplayChar(uint8 priority, uint8 line, uint8 offset, str disp_str);
   priority : 実行権限
        OLC_CHAR_USER  : 時計等のシステムが表示する内容を優先します
        OLC_CHAR_FORCE : システムが表示する内容に上書きをします
    line : 表示行(上下方向)
        0~18 [pixel] : 18を超えて指定すると表示されません
    offset : 表示列(左右方向)
        0~15[文字]:16文字を超えた内容は表示されません
    disp_str : 表示する文字データ

表示出来る文字はASCIIの記号と数字、英数字の大文字/小文字です。
(※エスケープ文字は非対応のためダブルクオーテーションは表示出来ません。)

文字レイアウト

[コード例]
#include "olcAPI.h"
   ~
// 初期化
func event_init() {
    //直接文字列を指定
    OLC_DisplayChar(OLC_CHAR_FORCE,0,0, "Hello World!   ");
    OLC_DisplayChar(OLC_CHAR_FORCE,18,0, "Recipe Language");
    return(0);
}

func any_func() {
    str outstr[20];
    outstr = "Hello World!   ";
    //文字変数を指定
    OLC_DisplayChar(OLC_CHAR_FORCE,0,0, outstr);
}

OLC_DiplayFree ()

OLEDに自由にピクセルを表示するAPIになります。

OLC_DisplayFree(uint8 priority, uint8 line, uint32 pixel_data0, uint32
         pixel_data1, uint32 pixel_data2, uint32 pixel_data3, uint8 size)
   priority : 実行権限
        0:OLC_CHAR_USER  : 時計等のシステムが表示する内容を優先します
        1:OLC_CHAR_FORCE : システムが表示する内容に上書きをします
    line : 表示行(上下方向)
        0~35 [pixel] : 
    pixel_data0~3 : 表示データ
        32pixel単位のビットパターンで表現される表示データ
    size : 8pixel単位での左から表示するデータの個数

横方向のピクセルパターンをlineごとに指定するAPIです。全画面の描画するためには35行分の指定が必要です。

フリーレイアウト

[コード例]
#include "olcAPI.h"
   ~
// 初期化
func event_init() {

    uint32 ptn1; ptn1 = 0xff00ff00;
    uint32 ptn2; ptn2 = 0x00ff00ff;
    OLC_DisplayFree(OLC_FREE_FORCE,0,ptn1,ptn1,ptn1,ptn1,16);
    OLC_DisplayFree(OLC_FREE_FORCE,2,ptn2,ptn2,ptn2,ptn2,8);

    return(0);
}

上記サンプルコードでは破線のパターンを表示します。2段めは破線のパターンを半分(8pixel x 8個 = 64pixel分)表示となります。


通知ランプ(LED)

概要

本製品には前面部に通知ランプ(以下LED)を搭載しています。ここではLEDをレシピ言語から制御する方法を紹介します。

LED

LED機能の特徴

LED機能の特徴を以下に示します。

LEDの制御

LEDのAPI

LEDを制御するAPIは以下となります。

API 内容
1 LED_DoLightup() LEDを指定の色で点灯する
2 LED_DoBlink() LEDを指定の色と周期で点滅させる

LED_DoLightup ()

LEDを指定した色で点灯及び消灯させるAPIとなります。時間指定(ミリ秒)が可能となり指定時間点灯します。

LED_DoLightup(uint8 color, uint32 time)
   color : 色指定
        0:LED_COLOR_RED     : 赤色
        1:LED_COLOR_GREEN   : 緑色
        2:LED_COLOR_ORANGE  : 橙色
        3:LED_COLOR_STOP    : 消灯
    time : 点灯時間
        0       : 点灯し続ける
        0以外   : 指定ミリ秒点灯後、消灯する
[コード例]

LEDを赤→緑→橙の順で1秒毎に点灯させる。

#include "ledAPI.h"
   ~
// 初期化
func event_init() {

    LED_DoLightup(LED_COLOR_RED, 1000);
    rcplib_SYS_Sleep(2000);
    LED_DoLightup(LED_COLOR_GREEN, 1000);
    rcplib_SYS_Sleep(2000);
    LED_DoLightup(LED_COLOR_ORANGE, 1000);

    return(0);
}

LED_DoBlink ()

LEDを指定した色と回数、間隔を指定して点滅させるAPIとなります。

LED_DoBlink(uint8 color, uint16 count, uint32 interval)
   color : 色指定
        0:LED_COLOR_RED     : 赤色
        1:LED_COLOR_GREEN   : 緑色
        2:LED_COLOR_ORANGE  : 橙色
        3:LED_COLOR_STOP    : 消灯
    count : 点滅回数
    interval : 点滅間隔[ミリ秒]
[コード例]

LEDを赤色で1秒毎に10回点滅させる。

#include "ledAPI.h"
   ~
// 初期化
func event_init() {

    LED_DoBlink(LED_COLOR_RED, 10, 1000);

    return(0);
}

ボタン

概要

本製品には前面部にボタンを搭載しています。ここではボタンをレシピ言語から制御する方法を紹介します。

Button

ボタン機能の特徴

ボタン機能の特徴を以下に示します。


[ボタン押下時間とイベントの種類]

ボタンの押下時間は押下してから離すまでの時間です。該当の押下時間に応じて発行されるイベントの種類が変わります。

押下時間 発行されるイベント
0.1~1秒 短押下イベント
1~4秒 長押下イベント
[ボタンのシステム側から利用]

ボタンは押下時にディスプレイに時計を表示するなどシステム側からも利用しています。ボタンをユーザイベントとして利用する際にはこれらとの競合がありますので、意図した動作にする際にはシステムからの利用タイミングを理解しておく必要があります。
システム側からのボタン利用:

押下時間 本製品動作
1秒以下 ディスプレイが点灯し時計画面が表示されます
4秒以上 電源をオフします(USB Type-C非接続時のみ)
13秒以上 強制的に再起動します

ボタンの制御

ボタンのAPI

ボタンを制御するAPIは以下となります。

API 内容
1 UIC_SenseButton() ボタン押下時のイベント登録
2 UIC_SenseButtonS() 0.1~1秒押し時のイベント登録
3 UIC_SenseButtonM() 1~4秒押し時のイベント登録

UIC_SenseButton ()

ボタン押下時のイベント登録をするためのAPIです。

UIC_SenseButton(uint32 sense_min, uint32 sense_max, uint8 event_id)
   sense_min : ボタン押下時間の最⼩値 [msec]
   sense_max : ボタン押下時間の最⼤値 [msec]
   event_id  : ボタン押下時のイベントID

最小値と最大値間の間でボタン押下と検出した場合に、このAPIを利用したタスクに対して、登録されたイベントを発行します。最大値は13秒以上には登録しても、製品仕様により強制的に再起動となります。
※このAPIを主としてUIC_SenseButtonS,MのAPIを構成しています。

[コード例]

ボタン押下時間が1秒~4秒の場合に、イベントを発行する

#include "uicAPI.h"

// ボタン押下イベント
#define UNSYNC_EVENT_BUTTON 1
~
// mainループ処理
void main_loop() {
   ~
    // ボタン検出イベントの処理
    else if(event_id == UNSYNC_EVENT_BUTTON) {
        event_key();
    }
   ~

func any_func() {
    // ボタン押しのイベント登録
    UIC_SenseButton(1000,4000,UNSYNC_EVENT_BUTTON);
    return(0);
}

func event_key() {
    // ボタンイベントの内容を記述

} 

UIC_SenseButtonS ()

ボタン押下(0.1~1秒押し)時のイベント登録をするためのAPI

UIC_SenseButtonS(uint8 event_id)
    event_id     : ボタン押下時のイベントID
  ※本APIはUIC_SenseButton(100,1000,event_id)を実行します。

UIC_SenseButtonM ()

ボタン押下(1~4秒押し)時のイベント登録をするためのAPI

UIC_SenseButtonM(uint8 event_id)
    event_id     : ボタン押下時のイベントID
  ※本APIはUIC_SenseButton(1000,4000,event_id)を実行します。

位置情報

概要

本製品にはGNSSの電波を受信して位置情報を取得する機能を搭載しています。ここではレシピ言語から位置情報を取得する方法を紹介します。

位置情報取得機能の特徴

内蔵のGNSS受信機能の特徴を以下に示します。

位置情報の制御

位置情報の取得は該当のAPIをコールすることで、GNSSのハードウェアをONにしてGNSSのスキャンを開始します。GNSSは環境によって位置測位時間が変わることから、捕捉出来るまで処理を待たせる方法と捕捉したタイミングでイベントを発行する使い方がAPIで選択が出来ます。

位置情報の制御API

位置情報を制御するAPIは以下となります。

API 内容
1 MMG_GetGNSS() GNSS位置情報を取得するAPI

MMG_GetGNSS ()

GNSS位置情報を取得するAPIです。
1回だけ取得を行う方法と繰り返し取得を行う方法の2種類あります。

MMG_GetGNSS(int32 timeout, uint8 event_id, uint8 mode)
   timeout  : APIのタイムアウト時間[msec]
   event_id : 非同期実行の場合=API処理完了後のイベントID=1〜254
         同期実行の場合=0(EAPI_SYNC_RESULT)
   mode     : 動作の指定
        MMG_GNSS_END 0              :位置測位の停止
        MMG_GNSS_START_ONESHOT 1    :1回だけ位置情報の測位をする(非同期/同期)
        MMG_GNSS_START_POLLING 2    :1秒毎の繰り返しで位置情報の測位をする(非同期のみ)
    ※event_id=0の時にmode=2の指定は禁止です。

※測位できる時間は環境にも影響するため、同期実行で利用される際には位置情報の取得用のAPIのタイムアウト値に注意ください。


位置情報(緯度経度)の値の取り方

取得した位置情報は、タスク間のデータ引継ぎ用メモリに格納されています。
APIのrcplib_TASK_GetArg()を利用して取り出します。

メモリの番号 内容 説明
rcplib_TASK_GetArg(0) double 緯度(latitude) 単位 [deg] (-90.0~+90.0) ※latitude=99999.0(MMG_GET_GNSS_RESULT)の場合は位置情報以外の通知
rcplib_TASK_GetArg(1) double 緯度(longitude) 単位 [deg] (-180.0~+180.0) ※latitudeが位置情報以外の通知の場合、longitudeはその内容になります。("modemMgrTask.h"の「API実行時のリザルトコード」参照)

非同期処理と同期処理の使い方

GNSS位置情報を取得するAPIを「非同期」で使用する際には、第2引数のevent_idに1-254の値を入れてAPIコールを行います。非同期のAPIコールはすぐにアプリケーションのコンテキストがもどってくるため、第1引数のAPIタイムアウト時間は意味を持ちません。
GNSS_UNSYNC

GNSS位置情報を取得するAPIを「同期」で使用する際には、第2引数のevent_idに0の値を入れてAPIコールを行います。同期のAPIコールはGNSSが捕捉出来るか、指定したTIMEOUT時間が過ぎるのどちらかまではアプリケーションのコンテキストが止まります。位置情報が捕捉出来たら次を実行するなどの連続した処理にはこちらの使い方が向いています。
GNSS_UNSYNC

SDKのサンプルコード内に非同期と同期のそれぞれの使い方のコードがありますので詳細はそちらをご参照願います。


コード例

位置情報を10分周期的に取得し、取得できた値を保存する例。
10分のタイマーを設定し、10分毎にMMG_GetGNSS()を1回だけ取得を試みます。

#include "eventLib.h"
#include "modemMgrTask.h"
#include "logAPI.h"
#include "olcAPI.h"

//////////////////////////////////////////////////////////////////
// internal define //
//////////////////////////////////////////////////////////////////
// 内部非同期イベント
#define EVENT_INIT   0
#define EVENT_TIMER  1
#define EVENT_GNSS_NOTIFY 2

// 10分タイマー値
#define TIMER_ID  0
#define GNSS_TIMER  1000*60*10 //60秒*10 = 10分

//GNSSタイムアウト値
#define TIMEOUT 60*1000 //1分

//////////////////////////////////////////////////////////////////
// event driven task process //
//////////////////////////////////////////////////////////////////
#ifdef C_SYNTAX
void main_loop(){
    WAIT_REQUEST_EVENT_QUEUE
#endif // C_SYNTAX
    rcplib_TASK_InitArg();

    uint16 event_id;
    event_id = rcplib_SV_Read(ENGINE_SVITEM_ID_TASKEVENTITEM_EVENT_ID);

    // 初期設定
    if(event_id == EVENT_INIT) {
        event_init();
    }
        // 周期イベント
    else if(event_id == EVENT_TIMER) {
        event_timer();
    }
    // GNSS受信イベント受信時の処理
    else if(event_id == EVENT_GNSS_NOTIFY) {
        event_gnss_notify(rcplib_TASK_GetArg(0), rcplib_TASK_GetArg(1));
    }
#ifdef C_SYNTAX
}
#endif // C_SYNTAX

//////////////////////////////////////////////////////////////////
// event function //
//////////////////////////////////////////////////////////////////

// 初期化処理
func event_init() {
    // 10分周期タイマー設定
    rcplib_TIMER_Create(TIMER_ID,GNSS_TIMER,1,EVENT_TIMER); 
    rcplib_TIMER_Start(TIMER_ID);

    // GNSS取得開始
    MMG_GetGNSS(TIMEOUT, EVENT_GNSS_NOTIFY, MMG_GNSS_START_ONESHOT);
}

// 10分周期イベント
func event_timer() {
    // GNSS取得再開
    MMG_GetGNSS(TIMEOUT, EVENT_GNSS_NOTIFY, MMG_GNSS_START_ONESHOT);
}

// GNSS受信のイベント処理
func event_gnss_notify(double latitude, double longitude) {
    str msg_1[18];        // GNSSログ出力用の文字列変数
    str msg_2[18];

    if(latitude == MMG_GET_GNSS_RESULT) {
        // エラー値の場合 MMG_GET_GNSS_RESULT==99999 
        rcplib_FORMAT_String(msg_1, "Error:%d        ", longitude);
        OLC_DisplayChar(OLC_CHAR_FORCE,0,0,msg_1);
        rcplib_LOG_Print(msg_1);
        MMG_GetGNSS(TIMEOUT, EVENT_GNSS_NOTIFY, MMG_GNSS_END);
    } else {
        // 取得に成功した緯度経度を保存
        rcplib_FORMAT_String(msg_1, "lat:%9.7f       ", latitude);
        rcplib_FORMAT_String(msg_2, "lon:%9.7f       ", longitude);
        OLC_DisplayChar(OLC_CHAR_FORCE,0,0,msg_1);
        OLC_DisplayChar(OLC_CHAR_FORCE,18,0,msg_2);
        rcplib_LOG_Print(msg_1);
        rcplib_LOG_Print(msg_2);
   }
    return(0);
}

内蔵センサー

概要

本製品には内蔵センサーとして加速度センサーとジャイロセンサーを搭載しています。ここでは内蔵センサーをレシピ言語から制御する方法を紹介します。

内蔵センサー機能の特徴

内蔵センサーである加速度センサーとジャイロセンサーの機能の特徴を以下に示します。

加速センサー

加速度センサー機能の特徴

加速度センサーはX,Y,Zの3軸あります。加速度センサーは端末が動いた瞬時的な値に加えて、常に重力方向に力を受けていることにより傾きの値の変化で端末の姿勢が分かります。

ACC_axis


加速度センサーの制御API

加速度センサーを制御するAPIは以下があります。

API 内容
1 ACC_SetDeviceMeasure() パフォーマンスモードとODRを変更する
2 ACC_SetDeviceRange ダイナミックレンジを変更する
3 ACC_GetDataOneShot() 加速度センサー測定値を一回取得する
4 ACC_StartPolling() 加速度センサー測定値を周期取得する

ACC_SetDeviceMeasure()

加速度センサーのパフォーマンスモードとODRを変更するAPIです。

ACC_SetDeviceMeasure(int8 performance, int8 odr) 
    performance : パフォーマンスモード
        ACC_LOW_PERF : Lowパフォーマンス
        ACC_HIGH_PERF : Highパフォーマンス  ※推奨
    odr : 動作周波数
        ACC_ODR1_002Hz : 2Hz
        ACC_ODR2_013Hz : 13Hz
        ACC_ODR3_026Hz : 26Hz
        ACC_ODR4_052Hz : 52Hz
        ACC_ODR5_104Hz : 104Hz
        ACC_ODR6_208Hz : 208Hz
        ※ODRを複数タスクから指定した場合は最も高い設定値が適用されます。

加速度センサーのパフォーマンスモードはHighパフォーマンスに設定することを推奨します。Highパフォーマンスモードに設定することにより内部のノイズフィルターが働きます。Lowパフォーマンスはセンサーの消費電流を0.2mA減らすことが出来ますが、ACアダプタ駆動の環境下ではHighパフォーマンスモード固定でのご利用が適しています。

odrは加速度センサーの内部の測定周期となります。プログラムで取得したい周期以上の設定が必要となります。例えば10ms毎に加速度センサーの値を取得しようとした場合は104Hz以上を指定する必要があります。

ACC_SetDeviceRange()

加速度センサーのダイナミックレンジを変更するAPIです。

ACC_SetDeviceRange(uint8 range)
    range       : ダイナミックレンジの種類
         ACC_DRANGE_2  = 1 :±2[G]
         ACC_DRANGE_4  = 2 :±4[G]
         ACC_DRANGE_8  = 4 :±8[G] 
         ACC_DRANGE_16 = 8 :±16[G]

    ※ダイナミックレンジは最新の設置値のみが有効になります。
        ダイナミックレンジは動的に変更は出来ないため、
        ACC_GetDataOneShot(),ACC_StartPolling()で測定を開始していない
        間のみ変更が可能となります。

ACC_GetDataOneShot()

加速度センサーの動作を開始し測定したデータを1回取得するAPIです。
周期取得動作は行いません。
重力方向を検出して傾きや姿勢を知る場合などにこのAPIが有用です。

ACC_GetDataOneShot(uint8 sync, int32 timeout, int32 interval)
    sync       : 同期/非同期
        同期     :EAPI_SYNC_RESULT
        非同期   :イベントID <1〜254>
    timeout    : タイムアウト値 [msec]
    interval   : 何秒後に測定値を取得するか [msec]

    ※timeoutは同期実行時に指定時間データが取得出来なかった場合に
     APIからコンテキストが戻ります。非同期実行時は値に意味は持ちません。
    ※timeout > intervalで値を設定する必要があります。

APIの同期/非同期の動作

APIは同期及び非同期で実行することが出来ます。同期実行の場合はセンサーの値が取得出来るまでコンテキストがAPIに移ります。この場合APIから処理が戻って来たタイミングで値が取得出来るので、一連の流れとして処理を記述する時に有用です。非同期での実行の場合は、値が取得出来たタイミングでイベントが発生しますので、タスクの処理と並列で値の取得を行いたいケースに有用です。

ACC同期/非同期


加速度センサーの値の取り方

加速度センサーの値は、タスク間のデータ引継ぎ用メモリに格納されています。
APIのrcplib_TASK_GetArg()を利用して取り出します。

メモリの番号 説明
rcplib_TASK_GetArg(0) int32 レジスタのX軸値 <-32768~+32767>
rcplib_TASK_GetArg(1) int32 レジスタのY軸値 <-32768~+32767>
rcplib_TASK_GetArg(2) int32 レジスタのZ軸値 <-32768~+32767>
rcplib_TASK_GetArg(3) float 重力加速度のX軸値 [mG]<-16000~+16000>
rcplib_TASK_GetArg(4) float 重力加速度のY軸値 [mG]<-16000~+16000>
rcplib_TASK_GetArg(5) float 重力加速度のZ軸値 [mG]<-16000~+16000>

※レジスタの軸値はセンサーICの出力するレジスタ値がそのまま入ります。
 重力加速度はセンサータスクでmGに単位変換した値が入ります。


同期実行のコード例
#incliude "sensorAPI.h"
   ~
func any_func() {
    // センサーデータを格納するための変数定義
    int16 acc_x; int16 acc_y; int16 acc_z;
    float acc_f_x; float acc_f_y; float acc_f_z;

    // timeout設定 1000[msec], 値を取得までの時間 100[msec]指定で一回取得する
    ACC_GetDataOneShot(EAPI_SYNC_RESULT, 1000, 100);

    // APIが終了した後、以下でデータを取得出来ます。
    acc_x = rcplib_TASK_GetArg(0);
    acc_y = rcplib_TASK_GetArg(1);
    acc_z = rcplib_TASK_GetArg(2);
    acc_f_x = rcplib_TASK_GetArg(3);
    acc_f_y = rcplib_TASK_GetArg(4);
    acc_f_z = rcplib_TASK_GetArg(5);

    return(0);
}

ACC_StartPolling()

加速度センサー測定を周期的に開始するAPIです。

ACC_StartPolling(int32 interval, uint8 notify_event_id)
    interval : イベント通知周期 [msec]
        0      : 通知停止
        10以上 : 通知周期 <msec> 
    notyfy_event_id : 通知イベントID

    ※通知周期の最小値
     Highパフォーマンスモード時:10[msec]
     Lowパフォーマンスモード時:45[msec]
     ジャイロセンサーと両方を方利用する場合:90[msec]

このAPIは非同期実行のAPIとなります。このためAPI実行など後に指定した周期毎に取得した値を通知するイベントが発生します。

ACC_Polling


加速度センサーの値の取り方

イベント発生後に取得したデータを取り出せます。
データの取得方法は、上記[ACC_GetDataOneShot()]の説明を参照ください。


周期取得のコード例
#incliude "sensorAPI.h"
   ~
// 内部非同期イベント
#define UNSYNC_EVENT_INIT 0
#define UNSYNC_EVENT_ACC_POLL 1
   ~
// mainループ処理
void main_loop() {
   ~
// 周期取得イベントの処理
    else if(event_id == UNSYNC_EVENT_ACC_POLL) {
        event_acc_poll(rcplib_TASK_GetArg(0), rcplib_TASK_GetArg(1),
                       rcplib_TASK_GetArg(2), rcplib_TASK_GetArg(3),
                       rcplib_TASK_GetArg(4), rcplib_TASK_GetArg(5));
    }
   ~
}

func any_func() {
    // 取得周期1000[msec], イベント通知番号1として開始する。
    ACC_StartPolling(1000, UNSYNC_EVENT_ACC_POLL);
    return(0);
}

// 周期取得イベントの処理
func event_acc_poll(int16 acc_x, int16 acc_y, int16 acc_z, float acc_f_x, float acc_f_y, float acc_f_z) {
   // 加速度センサーのデータは各種引数(acc_x~acc_f_z)から取得可能
   ~
    return(0);
}
周期取得停止のコード例
#incliude "sensorAPI.h"
   ~
func any_func() {
    // 周期取得を停止する
    ACC_StartPolling(0, 0);

    return(0);
}

複数タスクから利用時の注意事項

加速度センサーは複数のタスクから利用できますが、モードや動作条件の有効値は1つのみです。よって下記の優先度で動作します。

※加速度センサーが稼動している場合は、ダイナミックレンジ設定の変更はできません。


ジャイロセンサー

ジャイロセンサー機能の特徴

搭載しているジャイロセンサーはX,Y,Zの3軸があります。ジャイロセンサーは静止しているときは値は動かず、デバイスの回転を検出するとその瞬時的な値を出力します。これにより、端末がどの方向に回転したかが分かります。

GYR_axis


ジャイロセンサーの制御API

ジャイロセンサーを制御するAPIは以下があります。

API 内容
1 GYR_SetDeviceMeasure() パフォーマンスモード、ODRを変更する
2 GYR_SetDeviceRange ダイナミックレンジを変更する
3 GYR_GetDataOneshot() ジャイロセンサー測定値を一回取得する
4 GYR_StartPolling() ジャイロセンサー測定値を周期取得する

GYR_SetDeviceMeasure()

ジャイロセンサーのパフォーマンスモードを変更するAPIです。

GYR_SetDeviceMeasure(int8 performance, int8 odr)
    performance : パフォーマンスモード
        GYR_LOW_PERF : Lowパフォーマンス
        GYR_HIGH_PERF : Highパフォーマンス  ※推奨
    odr : 動作周波数
        GYRO_ODR1_013Hz : 13Hz
        GYRO_ODR2_026Hz : 26Hz
        GYRO_ODR3_052Hz : 52Hz
        GYRO_ODR4_104Hz : 104Hz
        GYRO_ODR5_208Hz : 208Hz
        ※ODRを複数タスクから指定した場合は最も高い設定値が適用されます。

ジャイロセンサーのパフォーマンスモードはHighパフォーマンスに設定することを推奨します。Highパフォーマンスモードに設定することにより内部のノイズフィルターが働きます。Lowパフォーマンスはセンサーの消費電流を0.1mA減らすことが出来ますが、ACアダプタ駆動の環境下ではHighパフォーマンスモード固定でのご利用が適しています。

odrはジャイロセンサーの内部の測定周期となります。プログラムで取得したい周期以上の設定が必要となります。例えば10ms毎にジャイロセンサーの値を取得しようとした場合は104Hz以上を指定する必要があります。

GYR_SetDeviceRange()

ジャイロセンサーのダイナミックレンジを変更するAPIです。

GYR_SetDeviceRange(uint8 range) 
    range       : ダイナミックレンジの種類
         GYR_DRANGE_250  =  1 :±250[dps]
         GYR_DRANGE_500  =  2 :±500[dps]
         GYR_DRANGE_1000 =  4 :±1000[dps]
         GYR_DRANGE_2000 =  8 :±2000[dps]

    ※ダイナミックレンジは最新の設置値のみが有効になります。
        ダイナミックレンジは動的に変更は出来ないため、
        GYR_GetDataOneShot(),GYR_StartPolling()で測定を開始していない
        間のみ変更が可能となります。

GYR_GetDataOneshot()

ジャイロセンサーの動作を開始し測定したデータを1回取得するAPIです。
周期取得動作は行いません。

GYR_GetDataOneshot(uint8 sync, int32 timeout, int32 interval) 
    sync      : 同期/非同期
        同期     :EAPI_SYNC_RESULT
        非同期   :イベントID <1〜254>
    timeout    : タイムアウト値 [msec]
    interval   : 何秒後に測定値を取得するか [msec]

    ※timeoutは同期実行時に指定時間データが取得出来なかった場合に
     APIからコンテキストが戻ります。非同期実行時は値に意味は持ちません。
    ※timeout > intervalで値を設定する必要があります。

APIの同期/非同期の動作

API仕様の考え方は、前記ACC_GetDataOneShot()と同じであるため、動きの詳細はACC_GetDataOneShot()の項をご参照ください。


ジャイロセンサーの値の取り方

ジャイロセンサーの値は、タスク間のデータ引継ぎ用メモリに格納されています。
APIのrcplib_TASK_GetArg()を利用して取り出します。

メモリの番号 説明
rcplib_TASK_GetArg(0) int32 レジスタのX軸値 <-32768~+32767>
rcplib_TASK_GetArg(1) int32 レジスタのY軸値 <-32768~+32767>
rcplib_TASK_GetArg(2) int32 レジスタのZ軸値 <-32768~+32767>
rcplib_TASK_GetArg(3) float 角速度X軸値 [dps]<-2000.0~+2000.0>
rcplib_TASK_GetArg(4) float 角速度Y軸値 [dps]<-2000.0~+2000.0>
rcplib_TASK_GetArg(5) float 角速度Z軸値 [dps]<-2000.0~+2000.0>

※レジスタの軸値はセンサーICの出力するレジスタ値がそのまま入ります。
 角速度値はセンサータスクでdps単位変換した値が入ります。


同期実行のコード例
#incliude "sensorAPI.h"
   ~
func any_func() {
    // センサーデータを格納するための変数定義
    int16 gyr_x; int16 gyr_y; int16 gyr_z;
    float gyr_f_x; float gyr_f_y; float gyr_f_z;

    // timeout設定 1000[msec], 値を取得までの時間 100[msec]指定で一回取得する
    GYR_GetDataOneshot(EAPI_SYNC_RESULT, 1000, 100);

    // APIが終了した後、以下でデータを取得出来ます。
    gyr_x = rcplib_TASK_GetArg(0);
    gyr_y = rcplib_TASK_GetArg(1);
    gyr_z = rcplib_TASK_GetArg(2);
    gyr_f_x = rcplib_TASK_GetArg(3);
    gyr_f_y = rcplib_TASK_GetArg(4);
    gyr_f_z = rcplib_TASK_GetArg(5);

    return(0);
}

GYR_StartPolling()

ジャイロセンサー測定を周期的に開始するAPIです。

GYR_StartPolling(int32 interval, uint8 notify_event_id) 
    interval : イベント通知周期 [msec]
        0      : 通知停止
        10以上 : 通知周期 <msec> 
    notyfy_event_id : 通知イベントID

    ※通知周期の最大値
     Highパフォーマンスモード時:10[msec]
     Lowパフォーマンスモード時:45[msec]
     加速度センサーと両方を方利用する場合:90[msec]

このAPIは非同期実行のAPIとなります。このためAPI実行など後に指定した周期毎に取得した値を通知するイベントが発生します。
非同期実行の動きは前記のACC_StartPolling()と同じになりますので、そちらに動作イメージ図がありますので、合わせてご参照ください。


ジャイロセンサーの値の取り方

イベント発生後に取得したデータを取り出せます。
データの取得方法は、上記[GYR_GetDataOneshot()]の説明を参照ください。


周期取得のコード例
#incliude "sensorAPI.h"
   ~
// 内部非同期イベント
#define UNSYNC_EVENT_INIT 0
#define UNSYNC_EVENT_GYR_POLL 1
   ~
// mainループ処理
void main_loop() {
   ~
// 周期取得イベントの処理
    else if(event_id == UNSYNC_EVENT_GYR_POLL) {
        event_gyr_poll(rcplib_TASK_GetArg(0), rcplib_TASK_GetArg(1),
                       rcplib_TASK_GetArg(2), rcplib_TASK_GetArg(3),
                       rcplib_TASK_GetArg(4), rcplib_TASK_GetArg(5));
    }
   ~
}

func any_func() {
    // 取得周期1000[msec], イベント通知番号1として開始する。
    GYR_StartPolling(1000, UNSYNC_EVENT_GYR_POLL);
    return(0);
}

// 周期取得イベントの処理
func event_gyr_poll(int16 gyr_x, int16 gyr_y, int16 gyr_z, float gyr_f_x, float gyr_f_y, float gyr_f_z) {
   // ジャイロセンサーのデータは各種引数(gyr_x~gyr_f_z)から取得可能
   ~
    return(0);
}
周期取得停止のコード例
#incliude "sensorAPI.h"
   ~
func any_func() {
    // 周期取得を停止する
    GYR_StartPolling(0, 0);

    return(0);
}

複数タスクから利用時の注意事項

ジャイロセンサーは複数のタスクから利用できますが、モードや動作条件の有効値は1つのみです。よって下記の優先度で動作します。

※ジャイロセンサーが稼動している場合は、ダイナミックレンジ設定の変更はできません。


振動検出

加速度センサーを用いた振動検出機能をAPIで提供しています。
振動検出機能を利用すると、本製品を設置した場所が振動したことを検出して動作を開始する等のアプリケーションに利用することが出来ます。(例えば車両に設置をして動き出したら位置情報を上げる等)

振動検出機能の特徴

振動検出機能は内蔵の加速度センサーICに振動のトリガとなる閾値を設定して、該当の振動を検出したら通知が入る仕組みをしています。このため振動が検出するまでの間はソフトウェアの動作リソースを減らすことが出来、待ち受けの消費電流を少なく出来ます。


振動検出の制御API

振動検出を制御するAPIは以下があります。

API 内容
1 ACC_SetVibrationMode() 振動検出を設定する
2 VIB_SetSenseMode() 指定回数の振動検出時にイベントを通知する
3 VIB_SetCountInterval() 振動検出のカウンタをクリアするインターバルを設定する

ACC_SetVibrationMode()

振動検出の有効化無効化を設定するAPIです。

ACC_SetVibrationMode(int8 sw, uint8 notify_event_id)
    sw  : 有効/無効
        有効 :ACC_VIB_ENABLE  <1>
        無効 :ACC_VIB_DISABLE <0>
    nofify_event_id :通知するイベントID <1〜254>

検出する振動の大きさの調整方法

検出する振動の大きさは、ACC_SetDeviceRange()で設定するダイナミックレンジで調整が出来ます。計算式は、[ダイナミックレンジ / 256]となります。
設定するダイナミックレンジと検出の大きさの関係は以下となります。

DynamicRange Define 検出値
±2[G] ACC_DRANGE_2 ±7[mG]
±4[G] ACC_DRANGE_4 ±15[mG]
±8[G] ACC_DRANGE_8 ±31[mG]
±16[G] ACC_DRANGE_16 ±52[mG]

※ダイナミックレンジの設定は最後に設定した値が優先されますので、振動検出以外で加速度センサーを利用する際の設定に影響されますのでご注意ください。

検出する周期の調整方法

検出する周期は、ACC_SetDeviceMeasure()で設定するODR周波数で設定が出来ます。
設定するODRと検出周期の関係は以下となります。

ODR Define 検出周期
2[Hz] ACC_ODR1_002Hz 500[ms]
13[Hz] ACC_ODR2_013Hz 76[ms]
26[Hz] ACC_ODR3_026Hz 38[ms]
52[Hz] ACC_ODR4_052Hz 19[ms]
104[Hz] ACC_ODR5_104Hz 9[ms]
208[Hz] ACC_ODR6_208Hz 4[ms]

※周波数を高くすることで検出頻度をあげられますが、この頻度で加速度センサーICからの割り込みが入りますので、ソフトウェアの動作リソースを消費します。52Hz以下で設定する事を推奨します。


振動検出のコード例
#include "sensorAPI.h"
#include "vibAPI.h"
   ~
// 内部非同期イベント
#define UNSYNC_EVENT_INIT 0
#define UNSYNC_EVENT_VIB_NOTIFY 1
   ~
// mainループ処理
void main_loop() {
   ~
    // 振動検出イベントの処理
    else if(event_id == UNSYNC_EVENT_VIB_NOTIFY) {
        event_vib_detected();
    }
   ~
}
   ~
func any_func() {

    // 振動検出を開始する
    // DynamicRange ±8G, ODR 52Hzを設定
    ACC_SetDeviceRange(ACC_DRANGE_8);
    ACC_SetDeviceMeasure(ACC_HIGH_PERF, ACC_ODR4_052Hz);
    // 振動検出 Enable
    ACC_SetVibrationMode(ACC_VIB_ENABLE, UNSYNC_EVENT_VIB_NOTIFY);
    return(0);
}

// 振動検出イベントの処理
func event_vib_detected() {
    // 振動検出時の処理をここに記載

    return(0);
}

VIB_SetSenseMode()

指定回数の振動を検出した際にイベントに通知を出すAPIです。

VIB_SetSenseMode(uint8 sw, uint16 sens, uint8 notify_event_id)
    sw  : 有効/無効
        有効  : VIB_SENSE_ENABLE <1>
        無効  : VIB_SENSE_ENABLE <0>
    sens  : イベントを通知するための振動検出回数 <1~65535>
    nofify_event_id :通知するイベントID <1〜254>

指定回数の振動を検出した際にイベント通知を出すコード例
#include "logAPI.h"
#include "vibAPI.h"
   ~
// 内部非同期イベント
#define UNSYNC_EVENT_INIT 0
#define UNSYNC_VIB_DETECT_EVENT 1
// 振動検知回数
#define VIB_DETECT_COUNT 30
   ~
// mainループ処理
void main_loop() {
   ~
   // 初期化
   if(event_id == UNSYNC_EVENT_INIT) {
        event_init();
   }
    // 振動検出イベントの処理
    else if(event_id == UNSYNC_VIB_DETECT_EVENT) {
        event_vib_detected();
    }
   ~
}
func event_init() {

    // 初期化時に振動検出設定を有効化
    // 30回振動検出時に、VIB_DETECT_EVENTのイベント通知を出す
    VIB_SetSenseMode(VIB_SENSE_ENABLE, VIB_DETECT_COUNT, UNSYNC_VIB_DETECT_EVENT);
    return(0);
}

// 振動検出イベントの処理
func event_vib_detected() {
    // 振動検出時の処理をここに記載
    rcplib_LOG_Print("vib detected !");
    return(0);
}

VIB_SetCountInterval()

振動検出回数をクリアするインターバルを設定するAPIです。
本関数を用いてインターバルを設定しない場合、標準で10000[msec]のインターバルで動作します。

VIB_SetCountInterval(uint32 count_timer)
    count_timer :インターバルの間隔 <1〜4294967295[msec]>

振動検出の回数をクリアするインターバルを設定するコード例
#include "logAPI.h"
#include "vibAPI.h"
   ~
// 内部非同期イベント
#define UNSYNC_EVENT_INIT 0
#define UNSYNC_DETECT_EVENT 1
// 振動検知回数
#define VIB_DETECT_COUNT 30
#define VIB_DETECT_COUNT_CLEAR_INTERVAL (30 * 1000)
   ~
// mainループ処理
void main_loop() {
   ~
   // 初期化
   if(event_id == UNSYNC_EVENT_INIT) {
        event_init();
   }
    // 振動検出イベントの処理
    else if(event_id == UNSYNC_DETECT_EVENT) {
        event_vib_detected();
    }
   ~
}
func event_init() {

    // 初期化時に振動検出設定を有効化
    // 30回振動検出時に、UNSYNC_DETECT_EVENTのイベント通知を出す
    VIB_SetSenseMode(VIB_SENSE_ENABLE, VIB_DETECT_COUNT, UNSYNC_DETECT_EVENT);
    // 30秒で振動検出のカウンタをクリアするように設定
    VIB_SetCountInterval(VIB_DETECT_COUNT_CLEAR_INTERVAL);

    // 上記のように設定した場合、30秒以内に30回振動を検出した場合にイベント通知がでる
    return(0);
}

// 振動検出イベントの処理
func event_vib_detected() {
    // 振動検出時の処理をここに記載
    rcplib_LOG_Print("vib detected !");
    return(0);
}

Bluetooth® Low Energy

概要

本製品にはBluetooth® Low Energyの送受信機能を搭載しています。ここではBluetooth® Low Energy機能をレシピ言語から制御する方法を紹介します。

ビーコン機能の特徴

レシピ言語から扱えるビーコン機能の特徴は以下の通りです。

本機能提供の範囲ではペアリングを伴う制御は非対応です。

ビーコン

ここではビーコンの受信及び送信の機能を説明します。本機能は様々なタイプのビーコンに対応するために、やや難しい設定が必要となりますので、前半部では機能を理解する上での背景部分を解説をし後半部でAPIの利用方法を述べます。

ビーコンのPDU

本機能ではBluetooth® Low Energyの標準フォーマットに準拠した形で発信しているAdvertising Packet を受信しています。Bluetooth® Low EnergyのAdvertising Packet の構成は下図の構成となり、特にビーコンでは特定機器へのペアリングせずに不特定多数への発信を目的としている事から、Protocol Data Unit(PDU)の種類はADV_NONCONN_INDのTypeで規定されるフォーマットが利用されます。
本機能ではこのPDUの中の情報に注目して、対象のビーコンが特定出来るAPIを提供しています。

beacon_pdu

[Advertiser’s Address (AdvA)]

ビーコンで利用されるPDUフォーマットでは、Payload内にあるAdvertiser’s Address(以降 AdvA)は機器固有の番号になり、機器を特定する目的で利用されます。AdvAはBluetooth®機器の製品の外装にラベリングなどにて表記されており、Bluetooth®アドレスと表記されることもあります。

しかし、AdvAはランダムな値の可能性もあるため、必ずしもAvdAが明記されているとは限りません。また、本製品の送信機能ではランダムアドレスは非対応となりますが、受信においてはランダムアドレス機器に対応出来るAPIの設計となっています。

[Advertiser’s Data (AdvData)]

ビーコンには特定のIDを発信することで存在を示す役割の他に、ビーコン自体が持っている情報を一緒に配信することが出来ます。センサーの付いているビーコン(温度や湿度センサーなど)はこの情報をAdvertiser’s Data(以降 AdvData)内のAD Dataに入れて発信を行なっています。
beacon_advdata

Advertising Packet を受信した機器は、AD Dataの該当部分からデータを取得してアプリケーション等で利用する事が出来ます。

※ビーコンのAdvertising Packet内のデータ配列は製品ごとに違うため、ビーコンのマニュアル等を確認願います。


ビーコンの特定

Bluetooth® Low EnergyのAdvertising Packetはビーコン以外でも使われており、スマートフォンのスキャンアプリ等で検出を行うと、多くのBluetooth®機器のAdvertising Packetが検出されます。この中から該当のビーコンのみを抽出するために、本APIでは「フィルタリング機能」と「ビットマスク機能」を備えております。

[フィルタリング機能]

ビーコンは受信側に機器を特定してもらう為の固有値をAdvertising Packetの中に含めています。固有値としてはAdvAの他に、製品固有番号をAdvDataの中に埋め込んでいるものなど様々あります。このため、検出したいビーコンの固有値の場所と数値がわかれば、それに対応したパターン情報を設定し、パターンマッチするパケットのみ通すフィルタを作ることが出来ます。(このフィルタのパターンは50個まで指定することが可能です)
beacon_pattern

[ビットマスク機能]

ビーコンの検出は一つの個体のみを特定したいこともあれば、製品という単位で特定したい場合もあります。特定対象となるビーコンが少数であれば個別のフィルタを準備する事も出来ますが、ビットマスク機能を利用することで1つのフィルタで機種単位でのビーコンを特定する設定が出来ます。
例えば製品固有番号が「会社番号+製品番号+製造番号」の様な組み合わせの場合、「会社番号+製品番号」の部分だけビットマスク機能で抜き出し、抜き出した結果とフィルタのパターン情報をマッチングさせる事が出来ます。
beacon_mask
※ビットマスクは取得したデータとの論理積(AND)を取ります。上図ではFF・・と設定していますが、バイト単位で論理積(AND)を取るためビット単位でのマスク値を指定することが出来ます。


送信と受信のタイミング

ビーコンは発信する側の機器が受信側との同期を取らずに独自のタイミング(周期)で発信します。このため受信側は常に待ち受けをしないと受信し損ねる可能性がありますが、常に受信し続けると機器の電力消費が多くなります。Bluetooth®では低消費電力制御の観点から受信を開始する周期と、受信時間(受信窓幅)を指定する事でこれに対応出来る仕組みがあります。本APIにはこれに対応したパラメータがあり下図の様に受信時間と受信周期を変更することが出来ます。

beacon_rcv

本機器でACアダプタから電源を供給する場合、低消費制御が必要ないため受信周期と受信時間を同じにすることによりビーコンの受信失敗を防ぐ事が出来ます。


ビーコン受信の抑制

ビーコンの発信周期は100msのものや30秒のものなど製品や設定によって様々となります。発信周期が早いビーコンを検出する場合、受信側はその周期ごとに検出イベントを受けることからシステムの負荷が高くなります。本機能ではこれに対応するために一度受信したビーコンを一定期間受信抑制する(受信しても検出イベントを上げない)仕組みを搭載しています。

beacon_restrain

例えば1秒周期で送信するビーコンがあり、抑制期間を30秒に設定した場合、最初の受信時にはイベントが上がりますが、その後同じビーコンを受信したとしても30秒間はイベント発行が停止します。

[受信抑制期間の弊害]

ビーコン受信抑制期間はシステム構築を行う上では必要な機能ですが、前記のビットマスク機能による製品単位の受信フィルタを設定した場合に意図しない弊害が生じる事があります。下図の様にフィルタで同じビーコンとして扱われた場合、抑制期間中は同一製品の検出イベントが上がらない状態になります。

beacon_effect

これを回避するために、フィルタは製品単位として機能するが、受信抑制時に指定の数値部分は別なビーコンとして扱うという、特殊な設定をすることが出来ます。抑制時間はビーコンごとに設定されますので、下図の場合の通り受信後から別々な抑制時間が設定されます。

beacon_effect2

※上記の特殊マスクは、後述のBLE_FilterDataSetSensor()のAPIのf2_ad_data_free_mask引数が該当します。


ビーコンの受信

本機能のAPIを利用することでAdvertising Packetに対するフィルタ値を指定して特定のビーコンを受信し、内容のデータを取得する事が出来ます。ここではビーコンを受信するためのAPIの扱い方を説明します。

[ビーコンの受信手順]

ビーコンを受信して中のセンサーデータ等の値を取得するには以下の手順です。

  1. ビーコン受信周期などの基本設定を行う。
  2. 受信したビーコンを選別するためのフィルタを設定する。
  3. 該当のビーコンを受信した時の通知イベントを設定する。
  4. 受信したビーコンのAdvertising Channel PDUからデータを取得する。

制御するAPIと動きの全体イメージ図は以下のようになります。

beacon_api


ビーコン受信制御のAPI

ビーコン受信制御に関連するAPIは以下の通りです。

API 内容
1 BLE_SettingDataSet() 送受信機能の基本設定を行う
2 BLE_FilterDataSetSensor() 受信機能のフィルタ設定を行う
3 BLE_StartPolling() ビーコンの受信を開始する
4 BLE_StartOneShot() ビーコンを1回受信する
5 BLE_ScanStop() ビーコンの送信と受信を停止する

BLE_SettingDataSet()

送受信機能の基本設定を行うAPIです。

BLE_SettingDataSet(int32 timeout, uint8 sync, uint32 send_interval, uint32 recv_width, uint32 recv_interval, int8 recv_rssi_th, uint32 ibeacon_recv, uint32 sensor_recv)
    timeout : API実行時のタイムアウト値 ([msec]で指定)
    sync    : API実行方法 (EAPI_SYNC_RESULT固定)
    send_interval : Advertise送信周期 (20~10000[msec])
    rcv_width     : Advertise受信時間(3~40000[msec])
    rcv_interval  : Advertise受信周期(3~3600000[msec])
    rcv_rssi_th   : 受信時の信号強度閾値 (-128~0[dBm])
    ibeacon_recv  : iBeacon毎の通知を抑制する期間 (1[秒]以上,0指定で1回だけ通知を行う)
    sensor_recv  : センサービーコン毎の通知を抑制する期間 (1[秒]以上,0指定で1回だけ通知を行う)

timeout, sync
このAPIは同期実行(関数がリターンするまでAPI側にコンテキストが移る)の為、APIが応答しない場合用にtimeout値を指定します。30秒など明らかに異常である場合の時間を指定します。syncのEAPI_SYNC_RESULTは同期実行の指定となります。

send_interval
送信時に何秒周期で送信するかを指定します。このAPIは送信/ビーコン受信/iBeacon受信の共用であるため、送信をする時にはここで値を指定しておきます。

rcv_width, rcv_interval
前記「送信と受信のタイミング」で説明をした内容で、受信の幅と周期を指定します。500ms,500ms等同じ数値を設定することにより、100% dutyの受信となり、ビーコンの取り逃しがなくなります。

rcv_rssi_th
信号強度閾値(rcv_rssi_th)は、ここで設定した受信強度より小さな電波は受け取らない設定となります。この設定を調整することで、ある程度近くにあるビーコンのみ受信する等の設定が可能となります。
設定する単位は[dBm]となり設定する数値と距離のイメージは以下の通りです。

RSSI

ibeacon_recv, sensor_recv
前記「ビーコン受信の抑制」で説明をした内容で、一回受信したビーコンのイベン通知を一定時間抑制する時間となります。iBeaconとそれ以外のビーコンそれぞれで値を設定できます。(iBeacon以外をここではセンサービーコンと表現することもある為、引数の名前がsensor_recvとなっています。)
本機能のAPIとタスクの動作模式図は以下となります。

iBeacon_rcv

このAPIはビーコンの基本設定として送信と受信の両方を定義をするため、行いたい内容によって利用する引数が限定されます。

引数 送信設定
(Long Range含む)
受信設定
(ビーコン、
Long Range)
受信設定
(iBeacon)
send_interval
recv_width
recv_interval
recv_rssi_th
ibeacon_recv
sensor_recv

※「☓」項目は引数への設定が不要です。(0を設定してください)
※「ビーコンの送信」「Long Rangeビーコンの送信」「ビーコンの受信」「LongeRangeビーコンの受信」を同時に利用することはできません。


BLE_FilterDataSetSensor ()

ビーコンを検出するためのフィルタとビットマスクを指定するAPIです。

BLE_FilterDataSetSensor(int32 timeout, uint8 sync, int64 filter_id, uint8 beacon_type, uint8 adv_address[], uint8 f1_ad_type[], uint8 f1_ad_data_filter[], uint8 f1_ad_data_mask[], uint8 f2_ad_type[], uint8 f2_ad_data_offset, uint8 f2_ad_data_filter[], uint8 f2_ad_data_mask[], uint8 f2_ad_data_free_mask[])
   timeout              : APIのタイムアウト値 [msec]
   sync                 : 同期実⾏のみ(EAPI_SYNC_RESULT)
   filter_id            : 任意のビーコン設定番号 <0〜49、iBeaconの設定と共有>
   beacon_type          : ビーコンの設定Type2~5
   adv_address[]        : AdvA <6Byte配列>
   f1_ad_type[]         : フィルタ設定1のAD Type <1Byte配列またはuint8変数>
   f1_ad_data_filter[]  :フィルタ設定1のAD Data <32Byte配列>
   f1_ad_data_mask[]    :フィルタ設定1のAD Dataの場所 <32Byte配列でビットマスク> 
   f2_ad_type[]         :フィルタ設定2のAD Type <1Byte配列またはuint8変数>
   f2_ad_data_offset    :フィルタ設定2のAD Dataのオフセット指定 <0〜29> 
   f2_ad_data_filter[]  :フィルタ設定2のAD Data <6Byte配列> 
   f2_ad_data_mask[]    :フィルタ設定2のAD Dataの場所。<6Byte配列でビットマスク>
   f2_ad_data_free_mask[]:フィルタ設定2のAD Dataに対する部分一致を利用する場合の個々の特定範囲用のビットマスク箇所 <6Byte配列でビットマスク>

filter_id
本機能では50種類までフィルタのパターンを持つことが出来ます。filter_idではこれから設定するフィルタの番号を指定します。後述のビーコン検出を開始するAPIにて、ここで指定したfilter_idを指定します。

beacon_type
フィルタを定義するにあたりAdvertising PDUのどの要素を利用するかを指定します。Typeの番号と利用する要素の関係は以下の通りです。
Beacon_type

設定する引数との対応表は以下の通り

beacon_type Type2 Type3 Type4 Type5
adv_address
f1_ad_type
f1_ad_data_filter
f1_ad_data_mask
f2_ad_type
f2_ad_data_offset
f2_ad_data_filter
f2_ad_data_mask
f2_ad_data_free_mask

※「☓」項目は利用しない為、引数の設定が不要となります。
※Type2でAdvAだけで検出する場合は、”f1_ad_type”は”0x00”を設定します。

adv_address
フィルタに設定するAdvAの情報を指定します。フィルタとしてAdvAを利用しない場合は空の配列を指定してください。
※ここで指定するAdvAは「リトルエンディアン」で指定をします。Bluetooth®SIGでの定義されているAdvertising Packet PDU内はリトルエンディアンでの定義です。

f1_ad_type
1つ目のAD Structureを特定するためのAD Typeを指定します。
f1_ad_data_filter, f1_ad_data_mask
1つ目のフィルタ情報とビットマスク情報を設定します。

f2_ad_type
2つ目のAD Structureを特定するためのAD Typeを指定します。
f2_ad_data_filter, f2_ad_data_offset, f2_ad_data_mask
2つ目のフィルタ情報とビットマスク情報を設定します。2つ目のフィルタはフィルタ開始のオフセットをかけることが出来るため、より柔軟に設定が出来ます。

f2_ad_data_free_mask
「受信抑制期間の弊害」の項で説明をした「特殊マスク情報」の設定になります。


BLE_StartPolling()

ビーコンの受信を開始するAPIです。

BLE_StartPolling(int32 timeout, uint8 sync, int64 filter_id, uint8 event_id)
    timeout : API実行時のタイムアウト値 ([msec]で指定)
    sync    : API実行方法 (EAPI_SYNC_RESULT固定)
    filter_id   :  フィルタ番号 (0~49, センサービーコンと共有)
    event_id    :  ビーコンの受信をした場合に発行するイベント番号

filter_id
前記で設定したフィルタのIDを指定することで、そのフィルタでのビーコンの受信を開始します。フィルタは50個設定出来ますので、設定した50個のビーコンを受信しようとした場合は、ここのIDを変更して50回このAPIをコールする動きとなります。

event_id
フィルタに該当したビーコンが受信した場合に、(event_id)で指定したイベントが発行される動きとなります。イベントが発行されるとこのAPIを実行したアプリケーションにイベントが通知されます。


BLE_StartOneShot()

ビーコンの受信を1回行うAPIです。

BLE_StartOneShot(int32 timeout, uint8 sync, int64 filter_id, uint8 event_id)
    timeout : API実行時のタイムアウト値 ([msec]で指定)
    sync    : API実行方法 (EAPI_SYNC_RESULT固定)
    filter_id   :  フィルタ番号 (0~49, センサービーコンと共有)
    event_id    :  ビーコンの受信をした場合に発行するイベント番号

利用方法はBLE_StartPolling()と同じですが、このAPIでは該当のビーコンが1回受信されたらその時点でスキャンを停止します。


BLE_ScanStop ()

ビーコンの受信と送信を停止するAPIとなります。

func  BLE_ScanStop(int32 timeout, uint8 sync, uint8 event_id)
         timeout  :  タイムアウト時間[msec]
         sync     :  同期方式のみ(EAPI_SYNC_RESULT)
         event_id :  処理完了後に発行するイベントID ※ビーコンの送信を停止する場合はこの入力値は不要です。

event_idにはBLE_StartPolling()で指定した同一のIDを指定することで、ビーコンの受信を停止することが出来ます。


受信したビーコンデータの取出し

フィルタに該当したビーコンを受信した場合、ビーコンデータの内容はFixedバッファと呼ばれるバッファに格納されています。受信イベントの引数にはこのFixedバッファの番号が通知されるため、その番号を利用してバッファからデータを取得します。

Beacon_fixedbuf

受信イベント引数 説明
rcplib_TASK_GetArg(0) int32 受信データのあるFixedバッファのIndex番号
rcplib_TASK_GetArg(1) uint8 受信データのあるFixedバッファのバッファID

受信イベント引数のindex番号とバッファIDを用いて、Fixedバッファから取り出すAPIであるrcplib_FIXBUF_Pop()を用いてAdvertising Packetを取出します。

   uint8 received_data[37]; // 受信データの格納先
   int32 fixed_buff_index; //Fixedバッファindex
   uint8 fixed_buff_id; //FixedバッファID

   fixed_buff_index = rcplib_TASK_GetArg(0);
   fixed_buff_id = rcplib_TASK_GetArg(1);

   // FixdバッファからBLE受信データを取得
   rcplib_FIXBUF_Pop(fixed_buff_id, fixed_buff_index, received_data);

取り出されるデータは下図ようにAdvertising Channel PDUの部分のパケットフォーマットになります。

Beacon_packet

uint8配列にAdvAから順にPDUの内容が入っているため、ビーコンの製品マニュアル等を参考に該当のbyte位置からデータを取り出します。

例:温度データがAdvDataの先頭から14byte目
  湿度データがAdvDataの先頭から16byte目 の場合
  uint8配列はAdvAの先頭からのため、AdvAの6byteを加味する

    temperature = (received_data[6+14]*256) + received_data[6+15];
    humidity = (received_data[6+16]*256) + received_data[6+17];

    上記例は2byteのデータがビッグエンディアンで格納されている場合です。
    ビーコンによってエンディアンが違うので確認が必要です。

iBeacon

iBeaconの特徴

iBeaconはBluetooth® Low Energyの標準フォーマットに準拠した形で、Advertising Packet PDU内のAdvData内のフォーマットをApple社が規定したものとなります。AdvData内のフォーマットをiBeacon frameと呼び、機器を特定するUUIDやデータなどの格納をするMajor, Minorなどのエリアが定義されています。

beacon_format

※iBeaconもAD Structureの構造に則っているため、前記までのビーコン受信のAPIでも受信は出来ますが、iBeacon対応の製品も多く出ていることからiBeaconに特化したAPIを提供しています。


iBeaconの受信

本機能のAPIを利用することでiBeaconのUUID/Major/Minorの値を指定して特定のiBeaconの受信をすることが出来ます。ここではiBeaconの受信するためのAPIの扱い方を紹介します。

[iBeaconの受信手順]

iBeaconを受信してMajorやMinorの値を取得するには以下の手順が必要です。

  1. ビーコン受信周期などの基本設定を行う。
  2. 受信したビーコンを選別するためのフィルタを設定する。
  3. 受信した時の通知イベントを設定し受信開始する。
  4. 受信したiBeacon frameからデータを取得する。

制御するAPIと動きの全体模式図は以下のようになります。

iBeacon_front


iBeacon受信制御のAPI

iBeacon受信制御に関連するAPIは以下の通りです。

API 内容
1 BLE_SettingDataSet() 送受信機能の基本設定を行う
2 BLE_FilterDataSetBeacon() 受信機能のフィルタ設定を行う
3 BLE_StartPolling() ビーコンの受信を開始する
4 BLE_ScanStop() ビーコンの送信と受信を停止する

上記1,2,4のAPIは前記「ビーコンの受信」と同様の為、説明を割愛します。


BLE_FilterDataSetBeacon()

受信機能のフィルタ設定を行うAPIです。

BLE_FilterDataSetBeacon(int32 timeout, uint8 sync, int64 filter_id, uint8 uuid_filter[], uint8 uuid_mask[], uint8 major_filter[], uint8 major_mask[], uint8 minor_filter[], uint8 minor_mask[])
    timeout : API実行時のタイムアウト値 ([msec]で指定)
    sync    : 同期実行⽅法のみ (EAPI_SYNC_RESULT固定)
    filter_id : フィルタ番号 (0~49, センサービーコンと共有)
    uuid_filter   : UUIDに対するフィルタ設定 (16byte配列)
    uuid_mask     : UUIDに対するマスク設定 (16byte配列で対象箇所をbit指定)
    major_filter  : Majorに対するフィルタ設定 (2byte配列)
    major_mask    : Majorに対するマスク設定 (2byte配列で対象箇所をbit指定)
    minor_filter  : Minorに対するフィルタ設定 (2byte配列)
    minor_mask    : Minorに対するマスク設定 (2byte配列で対象箇所をbit指定)
[ビーコンのフィルタ]

送受信の基本設定で電波を受信できる条件に当てはまったビーコンは全て受信出来ることになりますが、受信した全てのビーコンをアプリケーション側で選別しなくて良いようにするために、フィルタを設定して通知するビーコンを限定する事が出来ます。

フィルタ設定にはUUID/Major/Minorそれぞれの値を設定することが出来ます。この設定によりUUIDのみでビーコンを特定する設定や、MajorやMinorも含めて該当のビーコンを更に限定することが出来ます。
※UUID/Major/Minorのフィルタはビッグエンディアンで設定します。

[UUIDのフィルタ設定]

UUIDのフィルタ設定には、マスク設定[uuid_mask]とフィルタ設定[uuid_filter]の2つの設定値で該当のUUIDを持つビーコンを限定します。フィルタは受信したUUIDを[uuid_mask]と論理和(AND)を取り、結果を[uuid_filter]と比較する仕組みとなります。

iBeacon_filter

[Major/Minorのフィルタ設定]

Major/Minorにも、UUIDのフィルタと同じ論理でフィルタを設定することが出来ます。またUUIDを検出対象とせずに、Major/Minorだけを検出対象とすることも出来ます。この場合は[uuid_mask]と[uuid_filter]に[0000...]と全て0を入れることで、UUIDフィルタを無効にすることが出来ます。


受信したビーコンデータの取出し

受信したビーコンデータの内容はFixedバッファと呼ばれるバッファに格納されています。受信イベントの引数にはこのFixedバッファの番号が通知されるため、その番号を利用してバッファからデータを取得します。

iBeacon_fixedbuf

受信イベント引数 説明
rcplib_TASK_GetArg(0) int32 受信データのあるFixedバッファのIndex番号
rcplib_TASK_GetArg(1) uint8 受信データのあるFixedバッファのバッファID

受信イベント引数のindex番号とバッファIDを用いて、Fixedバッファから取り出すAPIであるrcplib_FIXBUF_Pop()を用いてAdvertising Packetを取出します。

   uint8 received_data[37]; // 受信データの格納先
   int32 fixed_buff_index; //Fixedバッファindex
   uint8 fixed_buff_id; //FixedバッファID

   fixed_buff_index = rcplib_TASK_GetArg(0);
   fixed_buff_id = rcplib_TASK_GetArg(1);

   // FixdバッファからBLE受信データを取得
   rcplib_FIXBUF_Pop(fixed_buff_id, fixed_buff_index, received_data);

取り出されたデータは下図のパケットフォーマットになります。

iBeacon_packet

[UUIDの取出し]

受信したパケットはuint8の配列へ変数として扱えます。このため取出したデータをreceived_data[]という配列に入れた際には、UUIDはreceived_data[15]~received_data[30]として順列に取得が出来ます。

[Major/Minorの取出し]

UUIDと同じ様に配列から取り出せますが、Major/Minor共にBigEndianで保存がされている事から、以下の計算式で取り出す事が出来ます。

uint8配列はAdvAの先頭からのため、AdvAの6byteを加味する

    major = (received_data[6+25]*256) + received_data[6+26];
    minor = (received_data[6+27]*256) + received_data[6+28];

    上記例は2byteのデータがビッグエンディアンで格納されている場合です。
    ビーコンによってエンディアンが違う可能性があるので確認が必要です。

ビーコンの送信

受信のAPIではビーコンとiBeaconのAPIを分けていましたが、送信に関してはビーコン、iBeacon、Long Range共通となります。

Beacon_tx_packt
LongRange_tx_packt

※ビーコン送信ではAdvAは機器内に入っている値を自動的に付与します。

[ビーコンの送信手順]

ビーコンを送信するには以下の手順が必要です。

  1. ビーコン送信周期の基本設定を行う。
  2. 送信するAdvDataのデータ列を準備する。
  3. ビーコン送信APIにAdvDataを指定して送信開始する。

制御するAPIと動きの全体模式図は以下のようになります。
Beacon_tx

[Advertiser’s Address(AdvA)の確認方法]

本機器のAdvAは不揮発メモリーに書き込まれて工場出荷しています。このためBluetooth®の送信時にはこのアドレスが自動的に付与されます。
AdvAをプログラム中から読み出すには以下の様にrcplib_NV_Read()を用います。

    uint8 AdvA[6];
    //AdvAを読出します。
    rcplib_NV_Read(NV_RO_BLE_MAC, 0, AdvA);
[iBeaconフォーマットの作成例]

iBeacon送信をする内容はiBeaconのフォーマットに合わせてuint8配列にAdvDataの内容をそのまま設定します。Bluetooth®SIGにて規定しているフォーマットはリトルエンディアンですが、iBeaconのUUID, Major, Minorはビッグエンディアンで記載しますのでご注意ください。

Beacon_tx_format


ビーコン送信制御のAPI

ビーコン送信制御に関連するAPIは以下の通りです。

API 内容
1 BLE_SettingDataSet() 送受信機能の基本設定を行う
2 BLE_StartPDUSending() ビーコンの送信を開始する

BLE_StartPDUSending()

ビーコンの送信を開始するAPIです。

BLE_StartPDUSending(int32 timeout, uint8 sync, uint8 send_data[], uint32 size, uint8 long_range)
    timeout : API実行時のタイムアウト値 ([msec]で指定)
    sync    : API実行方法 (EAPI_SYNC_RESULT固定)
    send_data   :  送信対象とするuint8配列のデータ (最大31byte、Long Range送信時は最大244Byte)
    size        :  配列のデータサイズ (最大31byte、Range送信時は最大244Byte)
    long_range  : ビーコンの送信かLonRange送信の設定 (0:ビーコンの送信, 1:Long Range送信)

LongRange

本機器ではBluetooth® 5.1 LE Coded PHY (Long Range)の送受信に対応しています。

Long Range機能の特徴

Long Range機能の特徴は以下の通りです。

※Long Rangeの通信は、通信相手もLong Rangeに対応している必要があります。

[Long Range機能で扱うPDU]

Long Range機能では下図のAdvAとAdvDataの値を扱います。
LongRangePaket

※Bluetooth®5.0の規格では、Payloadが255まで利用出来ますが、本機能は250byteまでの対応となっています。それ以上は扱えません。


Long Range受信

[Long Rangeの受信手順]

Long Rangeを受信するには以下の手順が必要です。

  1. 受信周期などの基本設定を行う。
  2. 受信したPaketを選別するためのフィルタを設定する。
  3. 受信した時の通知イベントを設定し受信開始する。
  4. 受信したPaketからデータを取得する。

制御するAPIと動きの全体模式図は以下のようになります。

LongRangeAPI


Long Range受信制御のAPI

Long Range受信制御に関連するAPIは以下の通りです。

API 内容
1 BLE_SettingDataSet() 送受信機能の基本設定を行う
2 BLE_FilterDataSetLongRange() 受信機能のフィルタ設定を行う
3 BLE_StartPollingLongRange() Long Rangeの受信を開始する
4 BLE_StartOneShotLongRange() Long Rangeを1回受信する
5 BLE_ScanStop() Long Rangeの送信と受信を停止する

上記1,4のAPIは前記「ビーコンの受信」と同様の為、説明を割愛します。


BLE_FilterDataSetLongRange()

意図したLong Rangeを検出する為のフィルタ設定をするAPIです。

BLE_FilterDataSetLongRange(int32 timeout, uint8 sync, int64 filter_id,
uint8 filter[], uint8 mask[])
   timeout  : タイムアウト時間[msec]
   sync     : 同期方式のみ(EAPI_SYNC_RESULT)
   filter_id: 受信データに対するフィルタ設定 (0~1を利用可)
   filter   :受信データに対するフィルタ設定
       (256Byte配列でbit毎に指定、244Byteまで利用可能、利用しない範囲は0を代入)
   mask     :受信データに対するマスク設定
      (256Byte配列でフィルタ対象とする箇所をbit毎に指定、244Byteまで利用可能、利用しない範囲は0を代入)

filter_id
前記ビーコンとは別のIDとなり、0,1の2つまでフィルタを持つことが出来ます。

filter, mask
前記ビーコンと同じ形式のフィルタとビットマスクの設定を行います。Long Rangeでは0~244byteまでのAdvDataの内容に対してのフィルタとなります。(注:AdvAは含まれません)
LongRange_packet


BLE_StartPollingLongRange()

Long Rangeの受信を開始するAPIです。

BLE_StartPollingLongRange(int32 timeout, uint8 sync, int64 filter_id, uint8 event_id)
   timeout  : タイムアウト時間[msec]
   sync     : 同期方式のみ(EAPI_SYNC_RESULT)
   filter_id: 受信データに対するフィルタ設定
   event_id : LongeRangeを受信したときに発行するイベントID

設定したフィルタと受信時のイベントIDを指定して、Long Rangeの受信を開始します。


受信したデータの取り出し

Long Rangeの受信はサイズが違うのみで基本的には前記のビーコンと同じになります。
受信したLong RangeデータはFixedバッファと呼ばれるバッファに格納されています。受信イベントの引数にはこのFixedバッファの番号が通知されるため、その番号を利用してバッファからデータを取得します。

iBeacon_fixedbuf

受信イベント引数 説明
rcplib_TASK_GetArg(0) int32 受信データのあるFixedバッファのIndex番号
rcplib_TASK_GetArg(1) uint8 受信データのあるFixedバッファのバッファID

受信イベント引数のindex番号とバッファIDを用いて、Fixedバッファから取り出すAPIであるrcplib_FIXBUF_Pop()を用いてPacketを取出します。

   uint8 received_data[251]; // 受信データの格納先
   int32 fixed_buff_index; //Fixedバッファindex
   uint8 fixed_buff_id; //FixedバッファID

   fixed_buff_index = rcplib_TASK_GetArg(0);
   fixed_buff_id = rcplib_TASK_GetArg(1);

   // FixdバッファからBLE受信データを取得
   rcplib_FIXBUF_Pop(fixed_buff_id, fixed_buff_index, received_data);

取り出されたデータは下図の様に、AdvAから配列に格納されます。

LongRange_packet


Long Rangeの送信

Long Rangeの送信は、前記ビーコンの送信と同じAPIを使用します。
「ビーコンの送信」の項を参照ください。