Протокол Терра – підключаємо дозиметр через Bluetooth

Дозиметри Терра-Н, Стора, Gamma Sapiens львівської компанії мають можливість зчитувати інформацію і керувати режимами через Bluetooth. Потрібно зробити станцію моніторингу і передавати дані на сервер, тому розбираємося із протоколом.

Є офіційний додаток, але він немає потрібного функціоналу: логування показників без переміщення і передачі показників на зовнішній сервер.

Опис протокору розміщений на сайті виробника. Обмін даними відбувається через SPP (Serial Port Profile). Дозиметр виступає ініціатором з’єднання, і підключається до пристрою із назвою, у якого назва починається із CHECKPOINT, далі можуть бути інші символи.

Пакети даних містять переважно заголовок пакету (0x55, 0xAA), код команди, номер пристрою, дані, контрольну суму.

Із алгоритму підрахунку з документація неясно, як рахується.

Опис неповний, є деякі неясності. Тому ідемо у Google Play і завантажуємо GS Ecotest. Активовуємо режим розробника, і активовуємо Журнал відслідковування Bluetooth HCI.

Запускаємо додаток, підключаємо пристрій, робимо заміри, і відключаємося.

Вимикаємо режим запису, і залежно від версії ос і виробника забираємо журнал. У Samsung набираємо:

*#9900#

Тиснемо RUN DUMPSTATE/LOGCAT/MODEM LOG і COPY TO SDCARD і знаходимо у папці log файл такої назви btsnoop_hci_201907261710.cfa.

Тепер запускаємо Wireshark і відкриваємо файл дампу. Нас цікавить протокол SPP (фільтруємо btspp), який працює поверх RFCOMM, нижче L2CAP.

Назбирали контрольні суми з пакетів, но на CRCCALC жодна не збігається.  Запустив дебагер dex файлу і найшов код просто скопіював код. Звичайне сумування. Якщо десь один біт став з 0 на 1, а десь з 1 на 0, то контрольна співпаде.

byte crc(byte arrays[], int sizes){
  byte crc = 0;
  for (int i=0; i<sizes; i++){
    int calc = crc + ( arrays[i] & 0xFF);
    if (calc>255){
      crc = calc - 255;
    }else{
      crc = calc;
    };
  }; 
  return crc; 
}

Пишемо прошивку на ESP32. В процесі дослідження виявлено, що дозиметр шле до 50 пакетів початку обміну, якщо немає відповіді відображається Er06. Якщо не знайдено хоста, відображається помилка Er07. Якщо немає пакета підтвердження в визначений час, то відображається помилка Er04.

Пристрій запам’ятовує mac адресу останього пристрою, з якого прийшла команда “переключення режиму”(01) із пареметром виключення (01):

55 AA 01 00 00 00 00 01 ZZ

Тому при зміні пристроїв час підключення 20 секунд, а не пару секунд, оскільки запускається discovery і шукаються пристрої з назвою CHECKPOINT*.

MAC мого пристрою 33:17:AB:20:09:18 (ECOTEST). В базі вендорів префікс не знайдено.

Ловимо пакет “Початок обміну”, даємо на нього відповідь “Підтвердження початку обміну”. Як дозиметр відповість на пакет, шлемо пакет “Переключення режиму роботи” із параметром 02 – вимірювання фону.

55 AA 01 00 00 00 00 02 ZZ

Після цього періодично з періодом до 20 секунд надсилаємо пакет “Запит результатів виміру”:

55 AA 00 00 00 00 00 00 ZZ

на нього з буфера результатів приходить дані у пакеті розміром 22 байти. Його парсимо і виводимо результат вимірів.

Цифри фону, похибки, заряду батареї приходять у 4 байтах у форматі float, який використовується у процесорах TI (MSP430). Формат називається TMS320C30.

В документації написано про тип (зразу розпишемо біти):

В приборе используется 32-х битовый формат с плавающей точкой (назовем его float MSP430).
 MSB.31          .23                   LSB.0
┏╍╍╍╍╍╍╍┳╍╍╍╍┳╍╍╍╍╍╍╍╍╍╍╍╍┓
┃ e.7... e.0 ┃ знакm.22 ......... m.0 ┃
┗╍╍╍╍╍╍╍┻╍╍╍╍┻╍╍╍╍╍╍╍╍╍╍╍╍┛

В этом формате мантисса представлена 23-мя младшими битами. 24-й бит мантиссы в представлении числа отсутствует. По определению этот бит всегда равен 1 (нормализованное число).
Порядок представлен 8-ми старшими битами. Порядок «смещен» на 0x7F. 
Примеры представления чисел с плавающей запятой:
0    = 00 00 00 00 = 00000000 00000000 00000000 00000000
+0.5 = 7F 00 00 00 = 01111111 00000000 00000000 00000000
+1   = 80 00 00 00 = 10000000 00000000 00000000 00000000
-1   = 80 80 00 00 = 10000000 10000000 00000000 00000000
+2   = 81 00 00 00 = 10000001 00000000 00000000 00000000
+3   = 81 40 00 00 = 10000001 01000000 00000000 00000000
-3   = 81 C0 00 00 = 10000001 11000000 00000000 00000000

Для переведення у формат IEEE 754 перепакуємо байти, переставивши біти. Використаємо конструкцію

union u_tag{
  byte bin[4];
  float num;
} u;

Запишемо у u.num тестові цифри, і отримаємо у u.bin, байти йдуть у зворотньому порядку.

+0.50=00000000 00000000 00000000 00111111
+1.00=00000000 00000000 10000000 00111111
-1.00=00000000 00000000 10000000 10111111
+2.00=00000000 00000000 00000000 01000000
+3.00=00000000 00000000 01000000 01000000
-3.00=00000000 00000000 01000000 11000000

Також в протоколі байти приходять в порядку:

мантисса ст. байт (i+1)
порядок (i)
мантисса мл. байт (i+3)
мантисса ср. байт (i+2)

Вибираємо потрібні дані із пакету, парсимо і передаємо куди потрібно. Під час підключення:

[BT] Client Connected
[BT] dosimeter init: 1800000 type: 7
[br] radiation: 0.19 mkSv 141.42 % 2.41 V 50 % NOT VALID 
[br] radiation: 0.19 mkSv 100.00 % 2.39 V 50 % NOT VALID
[br] radiation: 0.13 mkSv 37.14 % 2.40 V 50 % NOT VALID 
[br] radiation: 0.14 mkSv 32.44 % 2.38 V 50 % NOT VALID 
[br] radiation: 0.13 mkSv 30.15 % 2.39 V 50 % NOT VALID
[br] radiation: 0.13 mkSv 29.81 % 2.39 V 50 %
[br] radiation: 0.12 mkSv 24.08 % 2.38 V 50 %
[br] radiation: 0.10 mkSv 24.39 % 2.39 V 50 %
[br] radiation: 0.11 mkSv 22.09 % 2.33 V 25 %
[br] radiation: 0.10 mkSv 23.45 % 2.35 V 25 %
[br] radiation: 0.10 mkSv 23.14 % 2.36 V 50 %

Біт недостовірності даних зникає десь через 2 хвилини.

При живленні від 3.3 вольта, в протоколі відображається рівень заряду 2.89V. На екрані відображається коректно заряд: всі 4 сегменти.

Тепер дані можна передавати на сервер і відображати на домашньому екрані.

Що я б зробив в такій комунікації:

  1. Додав підтримку BT4.0 BLE, зазультат виміру зчитував з регістра. Батареї вистарчало б надовше, ніж на 1 день.
  2. Дозиметр зробив би сервером, щоб телефон підключався до дозиметра. В меню просто додав би on/off Bluetooth.
  3. Використав би стандартизований протокол, типу modbus-rtu.
  4. Контрольну суму 2 байтну, з модбасу.
  5. Відмовитися на більшості змінних від float типу.
Коментарі