From e03b30c9dcafeaf3b353594872aad579d60984f6 Mon Sep 17 00:00:00 2001 From: GiggioG Date: Mon, 8 Sep 2025 00:17:10 +0300 Subject: [PATCH] "write up" sounds bad -> "article" --- WRITE_UP.md => ARTICLE.md | 2 +- README.md | 74 ++++++++++++++++++++++++------------ reverse_engineering/NOTES.md | 4 +- 3 files changed, 53 insertions(+), 27 deletions(-) rename WRITE_UP.md => ARTICLE.md (99%) diff --git a/WRITE_UP.md b/ARTICLE.md similarity index 99% rename from WRITE_UP.md rename to ARTICLE.md index 1f9f1d7..0242a37 100644 --- a/WRITE_UP.md +++ b/ARTICLE.md @@ -6,7 +6,7 @@ app (TinyPrint) seemed weird. Recently I came across [WerWolv's 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 -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 At first I attempted to just look at the data directly. Using the `nRF Connect` diff --git a/README.md b/README.md index e652e00..82af861 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,17 @@ # 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) -, but I avoided looking at their code and peaking at the blogpost as much as i could. +This project was inspired by +[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 ### Command structure @@ -18,23 +27,33 @@ Consists of commands. Each command has the following structure: `0xFF` - End magic ### Printing an image -And the app sends the following commands to print an image (refer to the [commands](#getcommandcodecmdname)): -1. Blackening (quality) - always 51 (3) for my printer. It is from 1 to 5 (49 to 53). -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. +And the app sends the following commands to print an image (refer to the +[commands](#getcommandcodecmdname)): +1. Blackening (quality) - always 51 (3) for my printer. It is from 1 to 5 (49 to +53). +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 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 -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 Here you can find functions to create the bytes to command the printer. #### 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) 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` | #### 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) 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 #### 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) Returns byte code for the print type. Supports @@ -75,19 +96,22 @@ Returns byte code for the print type. Supports | LABEL | `0x03` | #### 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) Reads image from the path specified. #### 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) Saves a list of commands to a binary file and/or a human-readable hex file. #### 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)_ ) 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. #### 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 -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 async with Connection("AA:BB:CC:DD:EE:FF") as conn: ... ``` #### 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 #### 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. #### 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(text, ... _(see source code)_ ) -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). \ No newline at end of file +Generates a PIL image from the given text. \ No newline at end of file diff --git a/reverse_engineering/NOTES.md b/reverse_engineering/NOTES.md index 365aaa2..4f388e0 100644 --- a/reverse_engineering/NOTES.md +++ b/reverse_engineering/NOTES.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 # todo -- [X] writeup -- [ ] grammar check writeup \ No newline at end of file +- [X] article +- [ ] grammar check article \ No newline at end of file