123 lines
9.0 KiB
Markdown
123 lines
9.0 KiB
Markdown
---
|
||
title: Изучаем протокол принтеров Niimbot
|
||
description: Изучаем протокол принтеров Niimbot и печатаем этикетки, отправляя пакеты
|
||
date: 2024-06-29T21:10:28+03:00
|
||
draft: false
|
||
tags:
|
||
- bluetooth
|
||
- niimbot
|
||
- термопечать
|
||
- Niimbot B1
|
||
- Niimbot B110
|
||
- реверс-инжиниринг
|
||
- javascript
|
||
- typescript
|
||
- web
|
||
categories:
|
||
- reverse-engineering
|
||
featured_image: miniature.jpg
|
||
lastmod: 2024-07-26T07:55:58+03:00
|
||
telegram_entry_id: ""
|
||
type: default
|
||
---
|
||
|
||
После того, как поигрались с [niimprint](/niimbot-d110-pc), захотелось чего-то большего. У меня появилась идея написать полноценный веб-интерфейс для печати, в котором можно будет и рисовать этикетки, и печатать. Для этого я решил изучить протокол принтеров.
|
||
|
||
<!--more-->
|
||
|
||
## Структура пакета
|
||
|
||
Сейчас в моём владении два принтера D110 и B1.
|
||
Вооружившись Wireshark и android телефоном, снял дампы обмена данными с принтером по bluetooth. Для этого нужно было включить опцию "Bluetooth HCI Snoop Log" в настройках разработчика, а потом на компьютере после печати запустить `adb bugreport <filename>`.
|
||
|
||
Изучив пакеты и сверившись с другими открытыми источниками, получилась такая структура пакета:
|
||
|
||
![niimbot packet](packet.png)
|
||
|
||
* **Prefix** – префикс `0x03`, присутствующий только при одной команде - **Connect**.
|
||
* **Head** – всегда 2 байта `0x55` `0x55`.
|
||
* **Command** – ID команды (пакета).
|
||
* **Data length** – количество байтов данных, идущих далее.
|
||
* **Data** – непосредственно данные в количестве **Data length**.
|
||
* **Checksum** – вычисляется с помощью XOR всех байтов от **Command** до последнего байта **Data**.
|
||
* **Tail** – всегда 2 байта `0xAA` `0xAA`.
|
||
|
||
## Типы пакетов
|
||
|
||
На данный момент мне удалось идентифицировать следующие типы пакетов:
|
||
|
||
| ID команды | Наименование | Описание | ID ответа |
|
||
| ---------- | --------------------------- | -------- | --------------------------------------------------------------- |
|
||
| 0x01 | PrintStart | | 0x02 |
|
||
| 0x03 | PageStart | | 0x04 |
|
||
| 0x05 | PrinterLog | | 0x06 |
|
||
| 0x0b | AntiFake | | 0x0c |
|
||
| 0x13 | SetPageSize | | 0x14 |
|
||
| 0x15 | PrintQuantity | | 0x16 |
|
||
| 0x1a | RfidInfo | | 0x1b |
|
||
| 0x1c | RfidInfo2 | | 0x1d |
|
||
| 0x20 | PrintClear | | 0x30 |
|
||
| 0x21 | SetDensity | | 0x31 |
|
||
| 0x23 | SetLabelType | | 0x33 |
|
||
| 0x27 | SetAutoShutdownTime | | 0x37 |
|
||
| 0x40 | PrinterInfo | | 0x41, 0x43, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4f, ... |
|
||
| 0x54 | RfidSuccessTimes | | 0x64 |
|
||
| 0x58 | SoundSettings | | 0x68 |
|
||
| 0x70 | GetVolumeLevel / WriteRFID | | 0x71 |
|
||
| 0x83 | PrintBitmapRowIndexed | | ⚠ Без ответа |
|
||
| 0x84 | PrintEmptyRow | | ⚠ Без ответа |
|
||
| 0x85 | PrintBitmapRow | | ⚠ Без ответа |
|
||
| 0x8e | LabelPositioningCalibration | | 0x8f |
|
||
| 0xa3 | PrintStatus | | 0xb3 |
|
||
| 0xa5 | PrinterStatusData | | 0xb5 |
|
||
| 0xaf | PrinterConfig | | 0xbf |
|
||
| 0xc1 | Connect | | 0xc2 |
|
||
| 0xda | CancelPrint | | 0xd0 |
|
||
| 0xdc | Heartbeat (GetPrinterInfo) | | 0xde |
|
||
| 0xe3 | PageEnd | | 0xe4 |
|
||
| 0xf3 | PrintEnd | | 0xf4 |
|
||
|
||
|
||
## Важно знать
|
||
|
||
### Протокол обмена данным варьируется между разными моделями
|
||
|
||
В основном это касается набора пакетов при непосредственно печати. Изучив код приложения, можно сделать вывод, что есть пять вариаций протокола + вариации для самих моделей.
|
||
|
||
![proto files](proto_files.png)
|
||
|
||
### Вероятно, протокол обмена данными может варьироваться даже в пределах ревизий одной модели
|
||
|
||
Это можно увидеть в декомпилированном коде приложения:
|
||
|
||
![protocol tasks](protocol_tasks.png)
|
||
|
||
### Принтер искусственно занижает плотность печати при использовании неправильной или отсутствующей RFID метке
|
||
|
||
Вот тут довольно интересно. Принтеры и приложения ведут себя по разному.
|
||
|
||
**Метки нет вообще**:
|
||
|
||
* **Niimbot Android**
|
||
- Этикетку создать невозможно в принципе.
|
||
* **Niimbot Windows**
|
||
- D110 - не поддерживается, хоть и может печатать по usb.
|
||
- B1 - печатать можно, игнорируя предупреждения, плотность очень низкая.
|
||
* **Сторонние проекты**
|
||
- D110 - печатает без проблем с нужной плотностью.
|
||
- B1 - печатает с низкой плотностью.
|
||
|
||
**Метка есть, но от бумаги размером, который не поддерживается принтером**:
|
||
|
||
* **Niimbot Android**
|
||
- D110 - печатать можно, игнорируя предупреждения, плотность очень низкая (подлость самого приложения).
|
||
- B1 - аналогично с D110.
|
||
* **Niimbot Windows**
|
||
- D110 - печатать можно, игнорируя предупреждения, плотность очень низкая.
|
||
- B1 - печатать можно, игнорируя предупреждения, плотность очень низкая.
|
||
* **Сторонние проекты**
|
||
- D110 - печатает без проблем с нужной плотностью.
|
||
- B1 - аналогично с D110.
|
||
|
||
Что касаемо самой метки - считывание происходит при закрытии крышки.
|
||
Принтер видит метку даже если она снаружи корпуса. Так что можно просто приложить метку снаружи, закрыть корпус и печатать на чём попало. |