だいぶ一般的になっている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に触れているページは見つからなかったので苦労した。仕様書読めばわかることなんだけど、結局、実際の電波を見て書いている人はいないってことやなと思う。なんともさみしくも困った世の中だわ。
0 件のコメント:
コメントを投稿