"write up" sounds bad -> "article"
This commit is contained in:
parent
a06b4dedf9
commit
e03b30c9dc
|
@ -6,7 +6,7 @@ app (TinyPrint) seemed weird.
|
||||||
Recently I came across [WerWolv's
|
Recently I came across [WerWolv's
|
||||||
blogpost](https://werwolv.net/blog/cat_printer) about reverse engineering his
|
blogpost](https://werwolv.net/blog/cat_printer) about reverse engineering his
|
||||||
thermal printer's protocol and I was inspired to try with my own. Furthermore, I
|
thermal printer's protocol and I was inspired to try with my own. Furthermore, I
|
||||||
decided on attempting this with as little looking at their write up as possible.
|
decided on attempting this with as little looking at their article rias possible.
|
||||||
|
|
||||||
## 1. Sniffing BLE traffic with ESP32
|
## 1. Sniffing BLE traffic with ESP32
|
||||||
At first I attempted to just look at the data directly. Using the `nRF Connect`
|
At first I attempted to just look at the data directly. Using the `nRF Connect`
|
74
README.md
74
README.md
|
@ -1,8 +1,17 @@
|
||||||
# thermal-printer
|
# thermal-printer
|
||||||
A project to reverse engineer the protocol of my thermal printer - Vyzio B15 (X6) and [implement it myself](#Usage), so I can print from my laptop.
|
A project to reverse engineer the protocol of my thermal printer - Vyzio B15
|
||||||
|
(X6) and [implement it myself](#Usage), so I can print from my laptop.
|
||||||
|
|
||||||
This project was inspired by [WerWolv's Cat printer blogpost](https://werwolv.net/blog/cat_printer)
|
This project was inspired by
|
||||||
, but I avoided looking at their code and peaking at the blogpost as much as i could.
|
[WerWolv's Cat printer blogpost](https://werwolv.net/blog/cat_printer), but I
|
||||||
|
avoided looking at their code and peaking at the blogpost as much as i could.
|
||||||
|
|
||||||
|
In the end I made small python library, located in [/src](/src). You can see its
|
||||||
|
documentation [here](#usage).
|
||||||
|
|
||||||
|
## Article
|
||||||
|
You can read about my process of reverse engineering the protocol
|
||||||
|
[here](ARTICLE.md).
|
||||||
|
|
||||||
## Protocol
|
## Protocol
|
||||||
### Command structure
|
### Command structure
|
||||||
|
@ -18,23 +27,33 @@ Consists of commands. Each command has the following structure:
|
||||||
`0xFF` - End magic
|
`0xFF` - End magic
|
||||||
|
|
||||||
### Printing an image
|
### Printing an image
|
||||||
And the app sends the following commands to print an image (refer to the [commands](#getcommandcodecmdname)):
|
And the app sends the following commands to print an image (refer to the
|
||||||
1. Blackening (quality) - always 51 (3) for my printer. It is from 1 to 5 (49 to 53).
|
[commands](#getcommandcodecmdname)):
|
||||||
2. Energy - only if the print type isn't TEXT: corresponds to the _Print depth_ set in the app, with the formula `energy = 7500 + (PD - 4)*0.15*7500`. The Print depth is from 1 to 7.
|
1. Blackening (quality) - always 51 (3) for my printer. It is from 1 to 5 (49 to
|
||||||
3. PrintType - Image(`0x00`), Text(`0x01`) of Label(`0x03`). Still can't find the differences between them, but I think that Image allows for darker images, but I'm not sure.
|
53).
|
||||||
4. FeedPaper(speed) - I don't know what it does, but the speed is 10 for text and 30 for images and labels.
|
2. Energy - only if the print type isn't TEXT: corresponds to the _Print depth_
|
||||||
|
set in the app, with the formula `energy = 7500 + (PD - 4)*0.15*7500`. The Print
|
||||||
|
depth is from 1 to 7.
|
||||||
|
3. PrintType - Image(`0x00`), Text(`0x01`) of Label(`0x03`). Still can't find
|
||||||
|
the differences between them, but I think that Image allows for darker images,
|
||||||
|
but I'm not sure.
|
||||||
|
4. FeedPaper(speed) - I don't know what it does, but the speed is 10 for text
|
||||||
|
and 30 for images and labels.
|
||||||
5. Drawing - commands with either run-length encoded or bit-packed lines
|
5. Drawing - commands with either run-length encoded or bit-packed lines
|
||||||
6. FeedPaper(25), Paper(0x30), Paper(0x30), FeedPaper(25)
|
6. FeedPaper(25), Paper(0x30), Paper(0x30), FeedPaper(25)
|
||||||
I don't know what the FeedPaper calls do, but the Paper command feeds the paper so the printed image emerges.
|
I don't know what the FeedPaper calls do, but the Paper command feeds the paper
|
||||||
|
so the printed image emerges.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
In the `./src` directory you can find python files with functions to use the protocol and example usage in `./src/main.py`.
|
In the `./src` directory you can find python files with functions to use the
|
||||||
|
protocol and example usage in `./src/main.py`.
|
||||||
|
|
||||||
### commands.py
|
### commands.py
|
||||||
Here you can find functions to create the bytes to command the printer.
|
Here you can find functions to create the bytes to command the printer.
|
||||||
|
|
||||||
#### checkImage(imgPath)
|
#### checkImage(imgPath)
|
||||||
Checks if the image at this path is usable for the printer (384 px wide and 1bpp)
|
Checks if the image at this path is usable for the printer (384 px wide and
|
||||||
|
1bpp)
|
||||||
|
|
||||||
#### calcCrc8(data)
|
#### calcCrc8(data)
|
||||||
Calculates the crc8 checksum
|
Calculates the crc8 checksum
|
||||||
|
@ -55,7 +74,8 @@ Returns the byte corresponding to the command. Accepts:
|
||||||
| PAPER | Actually feeds the paper. Takes number of lines to move, with data size 2 (potentially 16 bite, little endian). | `0xA1` |
|
| PAPER | Actually feeds the paper. Takes number of lines to move, with data size 2 (potentially 16 bite, little endian). | `0xA1` |
|
||||||
|
|
||||||
#### runLenght(line)
|
#### runLenght(line)
|
||||||
Creates a byte array with the line compresses as explained above (see DRAW_COMPRESSED).
|
Creates a byte array with the line compresses as explained above (see
|
||||||
|
DRAW_COMPRESSED).
|
||||||
|
|
||||||
#### bitPack(line)
|
#### bitPack(line)
|
||||||
Creates a byte array with each pixel corresponding to a bit.
|
Creates a byte array with each pixel corresponding to a bit.
|
||||||
|
@ -64,7 +84,8 @@ Creates a byte array with each pixel corresponding to a bit.
|
||||||
Converts 16-bit number to little-endian
|
Converts 16-bit number to little-endian
|
||||||
|
|
||||||
#### getEnergy(printDepth)
|
#### getEnergy(printDepth)
|
||||||
Calculates the energy corresponding to a certain value of "Print depth" in the app
|
Calculates the energy corresponding to a certain value of "Print depth" in the
|
||||||
|
app
|
||||||
|
|
||||||
#### getTypeByte(typeStr)
|
#### getTypeByte(typeStr)
|
||||||
Returns byte code for the print type. Supports
|
Returns byte code for the print type. Supports
|
||||||
|
@ -75,19 +96,22 @@ Returns byte code for the print type. Supports
|
||||||
| LABEL | `0x03` |
|
| LABEL | `0x03` |
|
||||||
|
|
||||||
#### getSpeed(typeStr)
|
#### getSpeed(typeStr)
|
||||||
Returns the app's default "printSpeed" for types. Supports "IMAGE" (30) and "TEXT" (10). This is used with FEED_PAPER, idk how.
|
Returns the app's default "printSpeed" for types. Supports "IMAGE" (30) and
|
||||||
|
"TEXT" (10). This is used with FEED_PAPER, idk how.
|
||||||
|
|
||||||
#### readImage(imgPath)
|
#### readImage(imgPath)
|
||||||
Reads image from the path specified.
|
Reads image from the path specified.
|
||||||
|
|
||||||
#### compressImageToCmds(img)
|
#### compressImageToCmds(img)
|
||||||
For each line applies both run-length encoding and bit packing and chooses the shorter. Packages each line's compressed data into the appropriate command.
|
For each line applies both run-length encoding and bit packing and chooses the
|
||||||
|
shorter. Packages each line's compressed data into the appropriate command.
|
||||||
|
|
||||||
#### saveCommandsToFile(commands, saveToFile=None, saveToFileHuman=None)
|
#### saveCommandsToFile(commands, saveToFile=None, saveToFileHuman=None)
|
||||||
Saves a list of commands to a binary file and/or a human-readable hex file.
|
Saves a list of commands to a binary file and/or a human-readable hex file.
|
||||||
|
|
||||||
#### genMoveUp(lines=0x60)
|
#### genMoveUp(lines=0x60)
|
||||||
Generates the paper feeding commands at the end of the app's routine for printing an image.
|
Generates the paper feeding commands at the end of the app's routine for
|
||||||
|
printing an image.
|
||||||
|
|
||||||
#### genCommands( img, ... _(see source code)_ )
|
#### genCommands( img, ... _(see source code)_ )
|
||||||
Generates the commands for printing an image with the specified parameters.
|
Generates the commands for printing an image with the specified parameters.
|
||||||
|
@ -103,17 +127,21 @@ Disconnects from the device.
|
||||||
Sets up the Connection for the .connect method.
|
Sets up the Connection for the .connect method.
|
||||||
|
|
||||||
#### send(commands, delay=0)
|
#### send(commands, delay=0)
|
||||||
Writes each command individually to the appropriate characteristic, waiting _delay_ seconds between each one. In the end asks device for status and awaits OKAY.
|
Writes each command individually to the appropriate characteristic, waiting
|
||||||
|
_delay_ seconds between each one. In the end asks device for status and awaits
|
||||||
|
OKAY.
|
||||||
|
|
||||||
#### Context managers
|
#### Context managers
|
||||||
The Connection class supports the context manager protocol. It automatically connects and disconnects to the device.
|
The Connection class supports the context manager protocol. It automatically
|
||||||
|
connects and disconnects to the device.
|
||||||
```python
|
```python
|
||||||
async with Connection("AA:BB:CC:DD:EE:FF") as conn:
|
async with Connection("AA:BB:CC:DD:EE:FF") as conn:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
#### FakeConnection
|
#### FakeConnection
|
||||||
This class mirrors the methods of Connection, but its constructor takes paths to log files, where the sent data gets dumped.
|
This class mirrors the methods of Connection, but its constructor takes paths to
|
||||||
|
log files, where the sent data gets dumped.
|
||||||
|
|
||||||
### decode.py
|
### decode.py
|
||||||
#### readHumanFile(fileName)
|
#### readHumanFile(fileName)
|
||||||
|
@ -123,11 +151,9 @@ Reads a human-readable file of hex values into an array of bytes.
|
||||||
Reads a binary file into an array of bytes.
|
Reads a binary file into an array of bytes.
|
||||||
|
|
||||||
#### decodeCommands(cmdBytes, saveFilename=None)
|
#### decodeCommands(cmdBytes, saveFilename=None)
|
||||||
Decodes the bytes given into the image they convey and returns it. If _saveFilename_ is set, then it saves the image there.
|
Decodes the bytes given into the image they convey and returns it. If
|
||||||
|
_saveFilename_ is set, then it saves the image there.
|
||||||
|
|
||||||
### textToImage.py
|
### textToImage.py
|
||||||
#### textToImage(text, ... _(see source code)_ )
|
#### textToImage(text, ... _(see source code)_ )
|
||||||
Generates a PIL image from the given text.
|
Generates a PIL image from the given text.
|
||||||
|
|
||||||
## Write up
|
|
||||||
You can read about my process of reverse engineering the protocol [here](WRITE_UP.md).
|
|
|
@ -131,5 +131,5 @@ no nqmashe da imam compressiq, da znam za type-ove, za energy i t.n.
|
||||||
i tuk i pri dvata `paper`-a se durji, sqkash X6 ne e isCanPrintLabel
|
i tuk i pri dvata `paper`-a se durji, sqkash X6 ne e isCanPrintLabel
|
||||||
|
|
||||||
# todo
|
# todo
|
||||||
- [X] writeup
|
- [X] article
|
||||||
- [ ] grammar check writeup
|
- [ ] grammar check article
|
Loading…
Reference in New Issue