だいぶ一般的になっているBLEについて。すごく概念的なことはあちこちに書いてある。が、下から上まで(むしろ下だけ)知りたいのに、資料少なすぎ。なので自力で調べる無茶な挑戦。第4回=nRF52840モジュールの電波を解析
コードはこんなやつ。出力パワーをいじった。
-
/*********************************************************************
-
This is an example for our nRF52 based Bluefruit LE modules
-
Pick one up today in the adafruit shop!
-
Adafruit invests time and resources providing this open source code,
-
please support Adafruit and open-source hardware by purchasing
-
products from Adafruit!
-
MIT license, check LICENSE for more information
-
All text above, and the splash screen below must be included in
-
any redistribution
-
*********************************************************************/
-
#include <bluefruit.h>
-
// Beacon uses the Manufacturer Specific Data field in the advertising
-
// packet, which means you must provide a valid Manufacturer ID. Update
-
// the field below to an appropriate value. For a list of valid IDs see:
-
// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
-
// 0x004C is Apple
-
// 0x0822 is Adafruit
-
// 0x0059 is Nordic
-
#define MANUFACTURER_ID 0x0059
-
// "nRF Connect" app can be used to detect beacon
-
uint8_t beaconUuid[16] =
-
{
-
0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
-
0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0
-
};
-
// A valid Beacon packet consists of the following information:
-
// UUID, Major, Minor, RSSI @ 1M
-
BLEBeacon beacon(beaconUuid, 0x0102, 0x0304, -54);
-
void setup()
-
{
-
Serial.begin(115200);
-
// Uncomment to blocking wait for Serial connection
-
while ( !Serial ) delay(10);
-
Serial.println("Bluefruit52 Beacon Example");
-
Serial.println("--------------------------\n");
-
Bluefruit.begin();
-
// off Blue LED for lowest power consumption
-
Bluefruit.autoConnLed(true);
-
Bluefruit.setTxPower(8); // Check bluefruit.h for supported values
-
// Manufacturer ID is required for Manufacturer Specific Data
-
beacon.setManufacturer(MANUFACTURER_ID);
-
// Setup the advertising packet
-
startAdv();
-
Serial.println("Broadcasting beacon, open your beacon app to test");
-
// Suspend Loop() to save power, since we didn't have any code there
-
suspendLoop();
-
}
-
void startAdv(void)
-
{
-
// Advertising packet
-
// Set the beacon payload using the BLEBeacon class populated
-
// earlier in this example
-
Bluefruit.Advertising.setBeacon(beacon);
-
// Secondary Scan Response packet (optional)
-
// Since there is no room for 'Name' in Advertising packet
-
Bluefruit.ScanResponse.addName();
-
-
/* Start Advertising
-
* - Enable auto advertising if disconnected
-
* - Timeout for fast mode is 30 seconds
-
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
-
*
-
* Apple Beacon specs
-
* - Type: Non connectable, undirected
-
* - Fixed interval: 100 ms -> fast = slow = 100 ms
-
*/
-
//Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_ADV_NONCONN_IND);
-
Bluefruit.Advertising.restartOnDisconnect(true);
-
Bluefruit.Advertising.setInterval(160, 160); // in unit of 0.625 ms
-
//Bluefruit.Advertising.setInterval(2, 2); // in unit of 0.625 ms
-
Bluefruit.Advertising.setFastTimeout(3600); // number of seconds in fast mode
-
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
-
}
-
void loop()
-
{
-
// loop is already suspended, CPU will not run loop() at all
-
}
保存されたデータをBLEを下から見ていく(2)のpythonコードで解析すると、
こうなる。
最初のほうをちょっと拡大してみると、
こうなっている。で、取り出したビットデータ列は
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 0 0 1 0 0 0 1 1 0 0 0 1 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 1 1 1 1 1 1 0 1 1 0 1 1 1 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 0 0 1 1 1 0 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 1 0 1 0 0 0 0 1 0 1 1 1 1 0 0 1 1 1 0 1 1 1 0 0 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 0 0 1 0 1 0 0 1 1 0 1 1 1 1 1 1 0 1 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 1 0 0 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 0 0 1 1 0 1 1 1 1 0 1 0 0 0 1 0 0 0 1 1 1 1 0 0 1 1 1 0 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 0 1 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 1 0 0 1 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0]
8E89BED6ってのがあるので、たぶんあっているんだろう。ここからよ。で、仕様書をもう一度よく読んでみるとwhitenって処理やってるぜって書いてある。青い歯をホワイトニングするんか、、、Channel Indexをキーにしてビットをぐやぐちゃにする定数を作るらしい。いや、こんなんじゃぐちゃぐちゃにはならんと思うので、なんともいまいちな感じもする。仕様書にはごちゃごちゃと書いてあるんだけど、Channel Indexさえわかれば定数の配列を作ることができて、それと入力または出力ビットで排他的論理和をとればいいらしい。
で、その定数の配列はこうやる。
-
#include <stdio.h>
-
#include <stdint.h>
-
-
int main(int argc,char** argv){
-
uint8_t chan=37;
-
uint8_t p_byte;
-
uint8_t x_byte;
-
uint8_t s_byte;
-
uint8_t p_6;
-
uint8_t i,j;
-
p_byte=(0x40|chan)&0x7F;
-
s_byte=p_byte&0x01;
-
for(j=0;j<64;j++){
-
for(i=0;i<8;i++){
-
p_6=p_byte&0x01;
-
s_byte=(s_byte<<1)|p_6;
-
x_byte=(p_6<<6)|(p_6<<2);
-
p_byte=(p_byte>>1)^x_byte;
-
}
-
printf("%02X\n",s_byte);
-
}
-
return 0;
-
}
received | bin2hex | whiten | whitened | swap | bin2hex | contents | value |
01010101 | 55 |
|
|
|
|
Preamble |
|
01101011 | 6B |
|
|
11010110 | D6 | Access Address |
|
01111101 | 7D |
|
|
10111110 | BE | Access Address |
|
10010001 | 91 |
|
|
10001001 | 89 | Access Address |
|
01110001 | 71 |
|
|
10001110 | 8E | Access Address |
|
10110111 | B7 | B1 | 00000110 | 01100000 | 60 | Header |
|
01101111 | 6F | 4B | 00100100 | 00100100 | 24 | Header | 36 |
10010001 | 91 | EA | 01111011 | 11011110 | DE | AdvA |
|
10001001 | 89 | 85 | 00001100 | 00110000 | 30 | AdvA |
|
00001111 | 0F | BC | 10110011 | 11001101 | CD | AdvA |
|
11111111 | FF | E5 | 00011010 | 01011000 | 58 | AdvA |
|
10110011 | B3 | 66 | 11010101 | 10101011 | AB | AdvA |
|
11110110 | F6 | 0D | 11111011 | 11011111 | DF | AdvA |
|
11101110 | EE | AE | 01000000 | 00000010 | 02 | iBeacon Prefix |
|
00001100 | 0C | 8C | 10000000 | 00000001 | 01 | iBeacon Prefix |
|
11101000 | E8 | 88 | 01100000 | 00000110 | 06 | iBeacon Prefix |
|
01001010 | 4A | 12 | 01011000 | 00011010 | 1A | iBeacon Prefix |
|
10010110 | 96 | 69 | 11111111 | 11111111 | FF | iBeacon Prefix |
|
01110100 | 74 | EE | 10011010 | 01011001 | 59 | iBeacon Prefix |
|
00011111 | 1F | 1F | 00000000 | 00000000 | 00 | iBeacon Prefix |
|
10000111 | 87 | C7 | 01000000 | 00000010 | 02 | iBeacon Prefix |
|
11001010 | CA | 62 | 10101000 | 00010101 | 15 | iBeacon Prefix |
|
00010111 | 17 | 97 | 10000000 | 00000001 | 01 | beacon uuid |
|
10011101 | 9D | D5 | 01001000 | 00010010 | 12 | beacon uuid |
|
11001111 | CF | 0B | 11000100 | 00100011 | 23 | beacon uuid |
|
01010101 | 55 | 79 | 00101100 | 00110100 | 34 | beacon uuid |
|
01101000 | 68 | CA | 10100010 | 01000101 | 45 | beacon uuid |
|
10100110 | A6 | CC | 01101010 | 01010110 | 56 | beacon uuid |
|
11111101 | FD | 1B | 11100110 | 01100111 | 67 | beacon uuid |
|
01000011 | 43 | 5D | 00011110 | 01111000 | 78 | beacon uuid |
|
10001000 | 88 | 19 | 10010001 | 10001001 | 89 | beacon uuid |
|
01001001 | 49 | 10 | 01011001 | 10011010 | 9A | beacon uuid |
|
11110001 | F1 | 24 | 11010101 | 10101011 | AB | beacon uuid |
|
11101110 | EE | D3 | 00111101 | 10111100 | BC | beacon uuid |
|
01101111 | 6F | DC | 10110011 | 11001101 | CD | beacon uuid |
|
01000100 | 44 | 3F | 01111011 | 11011110 | DE | beacon uuid |
|
01111001 | 79 | 8E | 11110111 | 11101111 | EF | beacon uuid |
|
11001010 | CA | C5 | 00001111 | 11110000 | F0 | beacon uuid |
|
10101111 | AF | 2F | 10000000 | 00000001 | 01 | maj |
|
11101010 | EA | AA | 01000000 | 00000010 | 02 | maj |
|
11010110 | D6 | 16 | 11000000 | 00000011 | 03 | min |
|
11010011 | D3 | F3 | 00100000 | 00000100 | 04 | min |
|
11000110 | C6 | 95 | 01010011 | 11001010 | CA | TxPower | -54 |
00011110 | 1E | 98 | 10000110 | 01100001 | 61 | CRC |
|
01100111 | 67 | 36 | 01010001 | 10001010 | 8A | CRC |
|
11011100 | DC | BA | 01100110 | 01100110 | 66 | CRC |
|
00000100 | 04 | 32 | 00110110 | 01101100 | 6C |
|
|
ところで、仕様書によると、このwhiten配列は127bitで1周するようなことが書いてあるんだけど、計算してみると、127bit目のところで0xC7=0xC6|0x01てなっていて、その後0b01100010,0b10010111って続く。127bit周期はそうっぽいけど、byteでみると1bitずれになってくるわけで、それはそれで扱いが面倒。bit単位で処理するなら有用なのかも。
いろんなWebページでアドバタイズやBeaconについてこういうデータが入っているんだよって記述はあっちこっちにあるんだけど、whitenに触れているページは見つからなかったので苦労した。仕様書読めばわかることなんだけど、結局、実際の電波を見て書いている人はいないってことやなと思う。なんともさみしくも困った世の中だわ。
コメントをお書きください