10 SPPスレーブ

BlueLabのインストールディレクトリの中にexamplesというフォルダがあり、そのなかにspp_dev_aとspp_dev_bがあります.

spp_dev_aはマスターであるようです.

以下ではspp_dev_bについてソースコードを眺めてみました.

C:\BlueLab41\apps\examples\spp_dev_b

このプログラムは、ボタンを押すと、50秒間bluetoothホストを探索し、ホストが見つからなかったら断念します.

ホストが見つかったら、接続します.

main.c

#include "spp_dev_private.h"

#include "spp_dev_init.h"

#include "spp_dev_inquire.h"

#include "spp_dev_auth.h"

#include "spp_dev_b_leds.h"

#include "spp_dev_b_buttons.h"

#include <connection.h>

#include <panic.h>

#include <stdio.h>

#include <stream.h>

#include <pio.h>

いろいろなインクルードがありますが、なんなのかはまだよくわかりません.

#ifdef DEBUG_ENABLED

#define DEBUG(x) {printf x;}

#else

#define DEBUG(x)

#endif

デバッグのためのprintf()定義

static sppTaskData theSppApp;

sppTaskDataは、spp_dev_private.h で定義されています.

typedef struct {

TaskData task; --->message_.hで定義されています.typedef struct TaskData { void (*handler)(Task, MessageId, Message); } TaskData;

SPP* spp;

bdaddr bd_addr; --->bdaddr_.hで定義されています.typedef struct { uint32 lap; uint8 uap; uint16 nap; } bdaddr;

sppDevState spp_state;

} sppTaskData;

SPPは、spp_private.hの中の__SPPで定義されています.

struct __SPP {

TaskData task;

Task clientTask;

sppState state;

uint32 sdp_record_handle;

uint16 priority;

Sink sink;

uint8 local_server_channel;

uint16 lazy;

uint16 length_sr;

const uint8 *sr;

uint16 max_frame_size;

};

sppStateはspp_private.hの中でenum定義されています.

typedef enum {

sppInitialising,

sppReady,

sppSearching,

sppConnecting,

sppConnected

} sppState;

sppDevStateは、spp_dev_private.hの中でenum定義されています.

typedef enum {

sppDevInitialising,

sppDevReady,

sppDevInquiring,

sppDevConnecting,

sppDevConnected,

sppDevDisconnecting

} sppDevState;

Task getAppTask(void) { return &theSppApp.task; }

イベントハンドラを返す関数です.

static void unhandledSppState(sppDevState state, MessageId id) {

DEBUG(("SPP current state %d message id 0x%x\n", state, id));

}

unhandledなので、予期しないメッセージが来たときに、デバッグのため表示する関数.

void setSppState(const sppDevState state) {

DEBUG(("SPP State - C=%d N=%d\n",theSppApp.spp_state, state)); デバッグ用表示

theSppApp.spp_state = state; sppDevStateを上書きする

switch (state) { stateによりLEDの点滅を変える

case sppDevConnected: ledsPlay(RED_FLASH); break; 接続中ならREDチカチカ

default: ledsPlay(RED_BLUE_ALT); break; それ以外なら青緑チカチカ

}

}

static void app_handler(Task task, MessageId id, Message message) {

SPPのメッセージハンドラがこれです.以下に示すとおり、壮絶なるメッセージ分岐処理だと言えるでしょう.

sppDevState state = theSppApp.spp_state;

上でstaticに確保したsppTaskData構造体のなかから、SPPのステータスを取り出します.

switch(id) {

case CL_INIT_CFM: 初期化完了という意味があるらしい

DEBUG(("CL_INIT_CFM\n"));

if(((CL_INIT_CFM_T*)message)->status == success) sppDevInit(); 初期化成功なら初期化する

else Panic();

break;

case CL_DM_LINK_SUPERVISION_TIMEOUT_IND: remote deviceのtimeoutが変更されたとかなんとか.bluetooth2.1のみ

DEBUG(("CL_DM_LINK_SUPERVISION_TIMEOUT_IND\n")); break;

case CL_DM_SNIFF_SUB_RATING_IND: sniff subrating機能とは省電力機能のこと

DEBUG(("CL_DM_SNIFF_SUB_RATING_IND\n")); break;

case SPP_INIT_CFM: SPP初期化のための関数であるSppInit() SppInitEx() SppInitLazy()の実行結果が返ってくる

DEBUG(("SPP_INIT_CFM\n"));

switch(state) {

case sppDevInitialising: SPPが初期化中なら、

if (((SPP_INIT_CFM_T *) message)->status == spp_init_success) { 初期化成功なら、

setSppState(sppDevReady); SPP status ready に変更する

sppDevInquire(&theSppApp); SPPのインクワイリーを開始する

}

break;

case sppDevReady:

case sppDevPairable:

case sppDevConnecting:

case sppDevConnected:

default: unhandledSppState(state, id); break;

}

break;

case SPP_CONNECT_CFM: { SPP接続のための関数であるSppConnect() SppConnectEx() SppConnectLazy()の実行結果が返ってくる

SPP_CONNECT_CFM_T *cfm = (SPP_CONNECT_CFM_T *) message;

DEBUG(("SPP_CONNECT_CFM result = %d\n", cfm->status));

switch(state) {

case sppDevConnecting: 接続中なら、

if (cfm->status == rfcomm_connect_success) { RFCOMM接続成功なら

DEBUG(("Device connected...\n"));

(void) StreamConnect(StreamUartSource(), cfm->sink); RFCOMMとUARTを接続する

(void) StreamConnect(StreamSourceFromSink(cfm->sink), StreamUartSink()); RFCOMMとUARTを接続する

theSppApp.spp = cfm->spp; よくわからない

setSppState(sppDevConnected); SPP stateを接続中にする

ConnectionWriteScanEnable(hci_scan_enable_off); よくわからない関数です.connection.hで定義されています.

(void) MessageCancelFirst(&theSppApp.task, SPP_DEV_INQUIRY_TIMEOUT_IND); メッセージキューの最初を消去する

}

else { RFCOMM断線なら

setSppState(sppDevPairable); SPP stateを「ペアリングできる」にする

DEBUG(("Connection failed\n"));

}

break;

case sppDevPairable: ペアリングできる状態なら、

if (cfm->status == rfcomm_connect_success) { RFCOMM接続完了なら、

SppDisconnect(cfm->spp); ペアリングモードにするために現在の接続を切る

}

break;

case sppDevInitialising:

case sppDevReady:

case sppDevConnected:

default: unhandledSppState(state, id); break;

}

}

break;

case SPP_CONNECT_IND: リモートデバイスが当方に接続しようとしているなら、

DEBUG(("SPP_CONNECT_IND\n"));

switch(state) {

case sppDevPairable: ペアリングできる状態なら、

sppDevAuthoriseConnectInd(&theSppApp,(SPP_CONNECT_IND_T*)message); 接続要求をオーソライズする(って何?)

setSppState(sppDevConnecting); stateを接続中にする

break;

case sppDevInitialising:

case sppDevConnecting:

case sppDevReady:

case sppDevConnected:

default: unhandledSppState(state, id); break;

}

break;

case SPP_DISCONNECT_IND: 自分がSppDisconnect()したか、リモートがロストした場合、

DEBUG(("SPP_DISCONNECT_IND\n"));

switch(state) {

case sppDevConnected: 接続中なら

sppDevInquire(&theSppApp); SPPインクワイリープロセスを開始する(ってなに?)

break;

case sppDevInitialising:

case sppDevPairable:

case sppDevConnecting:

case sppDevReady:

default: unhandledSppState(state, id); break;

}

break;

case SPP_DEV_INQUIRY_TIMEOUT_IND: インクワイリーがタイムアウトなら(ってなに?)

DEBUG(("SPP_DEV_INQUIRY_TIMEOUT_IND\n"));

switch(state) {

case sppDevPairable: ペアリングできる状態なら

ConnectionWriteScanEnable(hci_scan_enable_off); よくわからない関数

setSppState(sppDevReady); SPP stateをreadyにする

break;

case sppDevConnected:

case sppDevInitialising:

case sppDevConnecting:

case sppDevReady:

default: unhandledSppState(state, id); break;

}

break;

case CL_DM_ACL_OPENED_IND: DEBUG(("CL_DM_ACL_OPENED_IND\n")); break; よくわかりません

case CL_DM_ACL_CLOSED_IND: DEBUG(("CL_DM_ACL_CLOSED_IND\n")); break; よくわかりません

case CL_SM_PIN_CODE_IND: リモートデバイスが認証を求めている

DEBUG(("CL_SM_PIN_CODE_IND\n"));

sppDevHandlePinCodeRequest((CL_SM_PIN_CODE_IND_T *) message);

break;

case CL_SM_AUTHORISE_IND: 知らないリモートデバイスが認証したがっている?

DEBUG(("CL_SM_PIN_CODE_IND\n"));

sppDevAuthoriseResponse((CL_SM_AUTHORISE_IND_T*) message);

break;

case CL_SM_AUTHENTICATE_CFM: ConnectionSmAuthenticate()の結果発生するメッセージ.BT2.1にて

DEBUG(("CL_SM_AUTHENTICATE_CFM\n"));

sppDevSetTrustLevel((CL_SM_AUTHENTICATE_CFM_T*)message);

break;

case CL_SM_ENCRYPTION_KEY_REFRESH_IND: 暗号化キーが変わったとき

DEBUG(("CL_SM_ENCRYPTION_KEY_REFRESH_IND\n")); break;

case CL_DM_LINK_POLICY_IND: DEBUG(("CL_DM_LINK_POLICY_IND\n")); break; よくわかりません

case CL_SM_IO_CAPABILITY_REQ_IND: リモートからIO capabilityリクエストがきたとき BT2.1にて

DEBUG(("CL_SM_IO_CAPABILITY_REQ_IND\n"));

ConnectionSmIoCapabilityResponse( &theSppApp.bd_addr, cl_sm_io_cap_no_input_no_output, FALSE, TRUE, FALSE, 0, 0 );

break;

case CL_SM_REMOTE_IO_CAPABILITY_IND: { リモートデバイスのIO capabilityがわかったとき? BT2.1にて

CL_SM_REMOTE_IO_CAPABILITY_IND_T *csricit = ( CL_SM_REMOTE_IO_CAPABILITY_IND_T *) message;

DEBUG(("CL_SM_REMOTE_IO_CAPABILITY_REQ_IND\n"));

DEBUG(("\t Remote Addr: nap %04x uap %02x lap %08lx\n", csricit->bd_addr.nap, csricit->bd_addr.uap, csricit->bd_addr.lap ));

theSppApp.bd_addr = csricit->bd_addr;

}

break;

case SPP_MESSAGE_MORE_DATA: DEBUG(("SPP_MESSAGE_MORE_DATA\n")); break; よくわかりません

case SPP_MESSAGE_MORE_SPACE: DEBUG(("SPP_MESSAGE_MORE_SPACE\n")); break; よくわかりません

case BUTTON_RESET_PRESS: リセットボタンが押されたら、ペアリングを開始する

DEBUG(("Button pressed\n"));

switch(theSppApp.spp_state) {

case sppDevInitialising: return; break;

case sppDevReady:

case sppDevPairable:

case sppDevConnecting: sppDevInquire(&theSppApp); break; 接続しようとしてたらインクワイリーにする

case sppDevConnected: SppDisconnect(theSppApp.spp); break; 接続中なら切断する

}

break;

default:

/* An unexpected message has arrived - must handle it */

DEBUG(("main app - msg type not yet handled 0x%x\n", id));

break;

}

}

int main(void) {

PioState pio_state;

spp_dev_b_buttons.hの中で定義されています.

typedef struct {

TaskData task;

Task client;

PioStoredState pio_states;

} PioState;

typedef struct {

InternalState store_held;

InternalState double_press;

uint16 pio_raw_bits;

uint16 pskey_wakeup;

uint16 store_bits;

uint16 store_count;

uint16 timed_id;

} PioStoredState;

typedef enum {

sBUTTON_RESET,

Unknown

} InternalState;

DEBUG(("Main Started...\n"));

#ifndef NO_UART_CHECK

/* Make sure Uart has been successfully initialised before running */

if (StreamUartSource())

#endif

{

theSppApp.task.handler = app_handler; メッセージハンドラをセットします

setSppState(sppDevInitialising); SPP初期化を起動

theSppApp.spp = 0; sppをゼロにする意味は不明

pioInit(&pio_state, &theSppApp.task); PIOを初期化します

spp_dev_b_buttons.cで定義されていますが、複雑で何をやっているのかよくわかりません.

ConnectionInit(&theSppApp.task); connection managerを初期化

MessageLoop();

}

/* Will never get here! */

DEBUG(("Main Ended!\n"));

return 0;

}