M5Stack
iBeacon Sample †
ibeacon.c
#include <stdint.h>
#include <M5Atom.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEBeacon.h>
//
// iBeacon PDU
//
// Preamble [1]
// Access Address [4] 0x8E89BED6
// ProtocolData Unit [2-39]
// Header [2]
// AdvA [6]
// AdvData [31]
// AD Structure1
// Length [1] 0x02
// AD Type [1] 0x01:Flags (GAP通信における制御情報)
// AD Data [Length-1] 0x06 (iBeacon の場合大抵 0x06)
// bit0: LE Limited Discoverable Mode
// bit1: LE General Discoverable Mode
// bit2: BR/EDR Not Supported
// bit3: Simultaneous LE and BR/EDR to Same Device Capable (Controller)
// bit4: Simultaneous LE and BR/EDR to Same Device Capable (Host)
// AD Structure2
// Length [1] 0x1A
// AD Type [1] 0xFF:Manifacture Specific Data (任意送信データ)
// AD Data [Length-1]
// Campany ID [2] 0x4C00 ※Apple の Campany ID を使う必要がある。
// Beacon Type [2] 0x0215
// UUID [16] UUID <★>
// Major Num [2] Major <★>
// Minor Num [2] Minor <★>
// TX Power [2] TX <★>
// Padding [1] 0x00
// CRC [3]
//
// [備考] 三菱の BLE の Campany ID は、 0x0014
//
////////////////////////////////////////////////////////////////////////////////
//
// 構造体定義
//
/**
* ビーコン情報構造体
*/
struct BeaconInfo {
const char* uuid;
uint16_t major;
uint16_t minor;
int8_t tx_power;
};
/**
* LED情報構造体
*/
struct LedInfo {
uint8_t r;
uint8_t g;
uint8_t b;
};
/**
* ボタン押下毎に切り替える情報構造体
*/
struct BeaconData {
struct BeaconInfo beacon;
struct LedInfo led;
};
// データ!
struct BeaconData beaconData[] = {
//{{ UUID , major, minor, tx_power}, { R, G, B }},
{{ "00000000-0000-0000-0000-000000000000", 0x0000, 0x0000, -65 }, { 0, 0, 0 }}, // OFF
{{ "ff000000-0000-0000-0000-000000000014", 0x0001, 0x0001, -65 }, { 0, 0, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0002, 0x0001, -65 }, { 0, 255, 0 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0003, 0x0001, -65 }, { 255, 0, 0 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0004, 0x0001, -65 }, { 0, 255, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0005, 0x0001, -65 }, { 255, 0, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0006, 0x0001, -65 }, { 255, 255, 0 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0007, 0x0001, -65 }, { 255, 255, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0001, 0x0002, -65 }, { 0, 127, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0001, 0x0003, -65 }, { 127, 0, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0001, 0x0004, -65 }, { 127, 127, 255 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0002, 0x0002, -65 }, { 0, 255, 127 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0002, 0x0003, -65 }, { 127, 255, 0 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0002, 0x0004, -65 }, { 127, 255, 127 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0003, 0x0002, -65 }, { 255, 0, 127 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0003, 0x0003, -65 }, { 255, 127, 0 }},
{{ "ff000000-0000-0000-0000-000000000014", 0x0003, 0x0004, -65 }, { 255, 127, 127 }},
{{ NULL , 0x0000, 0x0000, -65 }, { 0, 0, 0 }} // 番兵
};
////////////////////////////////////////////////////////////////////////////////
//
// プロトタイプ宣言
//
static void toUUID(uint8_t* uuid, const char* uuid_str);
static uint8_t hexstrToNum(const uint8_t* str);
static void updateBeacon(struct BeaconInfo* info);
////////////////////////////////////////////////////////////////////////////////
//
// 変数
//
static BLEAdvertising* pAdvertising;
static int data_idx = 0;
/**
* ビーコン情報を更新します。
*
* @param info ビーコンの情報
*/
static
void updateBeacon(struct BeaconInfo* info) {
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setManufacturerId(0x4C00);
uint8_t uuid[16];
toUUID(uuid, info->uuid);
Serial.println(uuid[0]);
oBeacon.setProximityUUID(BLEUUID(uuid, 16, false));
oBeacon.setMajor(info->major);
oBeacon.setMinor(info->minor);
oBeacon.setSignalPower(info->tx_power);
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
oAdvertisementData.setFlags(0x04);
std::string strServiceData = "";
strServiceData += (char)26; // Len
strServiceData += (char) 0xFF; // Type
strServiceData += oBeacon.getData();
oAdvertisementData.addData(strServiceData);
pAdvertising->setAdvertisementData(oAdvertisementData);
pAdvertising->setScanResponseData(oScanResponseData);
}
CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
return (CRGB)(( r << 16) | (g << 8) | b);
}
/**
* 開始!
*/
void setup() {
// LCD : true
// Power : false
// Serial : true
M5.begin(true, false, true);
Serial.begin(115200);
BLEDevice::init("");
M5.dis.drawpix(0, dispColor(0, 0, 0));
pAdvertising = BLEDevice::getAdvertising();
data_idx = 0;
updateBeacon(&(beaconData[data_idx].beacon));
}
void loop() {
M5.update(); // For ボタン情報取得
if (M5.Btn.wasPressed())
{ // ボタンが押下された際に、iBeacon を切り替える。
Serial.println("wasPressed");
// インデックスを進める (末尾であれば、0 にする)
data_idx = (beaconData[data_idx + 1].beacon.uuid == NULL) ? 0 : (data_idx + 1);
// ビーコンの設定更新
updateBeacon(&(beaconData[data_idx].beacon));
}
if (data_idx != 0)
{
// ビーコン送信開始
pAdvertising->start();
M5.dis.drawpix(0, dispColor(
beaconData[data_idx].led.r,
beaconData[data_idx].led.g,
beaconData[data_idx].led.b));
delay(100);
// ビーコン送信終了
pAdvertising->stop();
}
M5.dis.drawpix(0, dispColor(0, 0, 0));
delay(900);
}
/**
* 文字列方言の UUID を 16 byte のバイナリに変換します。
*
* @param uuid 変換後のバイナリ格納用
* @param uuid_str 文字列表現のUUID [xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 形式]
*/
static
void toUUID(uint8_t* uuid, const char* uuid_str)
{
const uint8_t* ptr = (const uint8_t*) uuid_str;
for (int i = 0; i < 16; i++)
{
if (*ptr == '-')
{
ptr++;
}
uuid[i] = hexstrToNum(ptr);
ptr += 2;
}
}
/**
* 指定された16進数文字列を数値に変換します。
*
* @param str 16進数表現の文字列
* @return 数値
*/
static
uint8_t hexstrToNum(const uint8_t* str)
{
const uint8_t* ptr = str;
uint8_t msb = (*ptr > '9') ? (*ptr - 7) : *ptr;
ptr++;
uint8_t lsb = (*ptr > '9') ? (*ptr - 7) : *ptr;
return ((msb & 0x0f) << 4) | (lsb & 0x0f);
}