Skip to content

adding cat printer code #2737

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
271 changes: 271 additions & 0 deletions MEMENTO/Memento_Cat_Printer/CatGFX.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
// SPDX-FileCopyrightText: 2022 Claus Näveke
//
// SPDX-License-Identifier: Unlicense
// https://github.com/TheNitek/CatGFX

#include "CatGFX.h"

CatPrinter::CatPrinter(uint16_t h):
Adafruit_GFX(384, h),
WIDTH_BYTE((WIDTH + 7)/8),
SERVICE_UUID("0000AE30-0000-1000-8000-00805F9B34FB"),
CHAR_UUID_DATA("0000AE01-0000-1000-8000-00805F9B34FB")
{
if (this->NAME_ARRAY_SIZE >= 5)
{
strcpy(this->printerNames[0], "GT01");
strcpy(this->printerNames[1], "GB01");
strcpy(this->printerNames[2], "GB02");
strcpy(this->printerNames[3], "MX09");
strcpy(this->printerNames[4], "MX06");
for (int i = 4; i < this->NAME_ARRAY_SIZE; i ++)
strcpy(this->printerNames[i], "");
}
else if (this->NAME_ARRAY_SIZE >= 1)
strcpy(this->printerNames[0], "");
}

void CatPrinter::begin(byte *buffer, uint16_t size) {
pixelBuffer = buffer;
pixelBufferSize = size;

BLEDevice::init("ESP32");
bleScan->setAdvertisedDeviceCallbacks(this);
bleScan->setActiveScan(true);
}

void CatPrinter::fillBuffer(const byte value) {
if (pixelBuffer != nullptr)
memset(pixelBuffer, value, pixelBufferSize);
}

bool CatPrinter::connect(void) {
bleScan->start(5);
if(blePrinterAddress == nullptr) {
return false;
}
return connect(*blePrinterAddress);
}

bool CatPrinter::connect(BLEAddress &address) {
if(!bleClient->connect(address)) {
Serial.println("Connect failed");
return false;
}

BLERemoteService* pRemoteService = bleClient->getService(SERVICE_UUID);
if(pRemoteService != nullptr) {
pRemoteCharacteristicData = pRemoteService->getCharacteristic(CHAR_UUID_DATA);
if(pRemoteCharacteristicData != nullptr) {
Serial.println("Got data transfer characteristic!");
return true;
}
}
else {
bleClient->disconnect();
Serial.println("Data service not found");
}
return false;
}

void CatPrinter::disconnect(void) {
bleClient->disconnect();

if(blePrinterAddress != nullptr) {
delete blePrinterAddress;
blePrinterAddress = nullptr;
}
}

void CatPrinter::sendLine(const byte *data, const uint8_t len, const bool compressed) {
//Serial.println("send line..");
if(compressed) {
//Serial.println("compressed");
byte comp[WIDTH_BYTE] = {0};
uint8_t cb = 0;

// Get color of first pixel
comp[0] = data[0] & 0x80;

for (uint16_t i=0; i<len; i++) {
for(uint8_t j=0; j<8; j++) {
if(((data[i] >> (7-j)) & 0x01) != (comp[cb] >> 7) || ((comp[cb] & 0x7F) == 0x7F)) {
cb++;
if(cb >= WIDTH_BYTE) {
// Not a compressable line, so dont
sendLine(data, len, false);
return;
}
comp[cb] = ((data[i] >> (7-j)) & 0x01) << 7;
}
comp[cb]++;
}
}
cb++;
sendCmd(CatPrinter::Cmd::PRINT_COMPRESSED, comp, cb);
} else {
//Serial.println("not compressed");
byte buff[WIDTH_BYTE];
//delay(200);
for (uint8_t i=0; i<len; i++) {
buff[i] = MIRROR_TABLE[data[i]];
}
//Serial.println("sending command..");
sendCmd(CatPrinter::Cmd::PRINT, buff, len);
delay(10);
}
}

void CatPrinter::feed(uint8_t lines) {
byte data[] = {lines, 0};
sendCmd(CatPrinter::Cmd::PAPER_FEED, data, sizeof(data));
}

void CatPrinter::printBuffer(void) {
Serial.println("print buffer..");
startGraphics();

// Print the graphics
byte *s = pixelBuffer;
for (uint16_t y=0; y<HEIGHT; y++) {
//delay(10);
sendLine(s, WIDTH_BYTE, false);
s += WIDTH_BYTE;
// Stop if the rest of the buffer is empty
if(s[0] == 0 && !memcmp(s, s+1, (HEIGHT-y-1)*WIDTH_BYTE-1)) {
break;
}
}
//Serial.println("end of print buffer");
endGraphics();
}

void CatPrinter::onResult(BLEAdvertisedDevice advertisedDevice) {
//Serial.println("on result");
uint8_t i = 0;
delay(200);
while (i < this->NAME_ARRAY_SIZE && strcmp(this->printerNames[i], "") != 0){
if (strcmp(advertisedDevice.getName().c_str(), this->printerNames[i]) == 0) {
blePrinterAddress = new BLEAddress(advertisedDevice.getAddress());
Serial.print("Found Printer: ");
Serial.println(blePrinterAddress->toString().c_str());
bleScan->stop();
break ;
}
else
i ++;
}
}

void CatPrinter::sendCmd(const CatPrinter::Cmd cmd, const byte *data, const uint8_t len) {
//Serial.println("send cmd");
byte buffer[WIDTH_BYTE+8] = {0x51, 0x78};
buffer[2] = static_cast<byte>(cmd);
buffer[4] = len;
memcpy(buffer + 6, data, len);
buffer[6 + len] = crc(data, len);
buffer[6 + len + 1] = 0xFF;

writeData(buffer, len+8);
delay(10);
}

byte CatPrinter::crc(const byte *data, const uint8_t len) {
byte cs = 0;

for (uint8_t i=0; i<len; i++) {
cs = CRC_TABLE[(cs ^ data[i])];
}
return cs;
}

void CatPrinter::writeData(byte *data, uint8_t len) {
//Serial.println("write data");
if (!bleClient->isConnected()) {
return;
}

// Write in smaller packages, because bigger ones don't work for unkown reason
while (len > PACKET_SIZE) {
delay(2);
Serial.print(".");
pRemoteCharacteristicData->writeValue(data, PACKET_SIZE);
data += PACKET_SIZE;
len -= PACKET_SIZE;
//Serial.println("wrote packet, len > packet_size");
//delay(200);
}
if (len) {
delay(2);
pRemoteCharacteristicData->writeValue(data, len);
//delay(200);
Serial.println(".");
//Serial.println("wrote packet, len < packet_size");
}
}

void CatPrinter::startGraphics(void) {
Serial.println("starting graphics..");
byte data[2] = {0x80, 0x3E};
sendCmd(CatPrinter::Cmd::ENERGY, data, 2);
//delay(10);
data[0] = 0x33;
sendCmd(CatPrinter::Cmd::QUALITY, data, 1);
//delay(10);
data[0] = 0x00;
sendCmd(CatPrinter::Cmd::DRAWING_MODE, data, 1);
//delay(10);
sendCmd(CatPrinter::Cmd::LATTICE, LATTICE_START, sizeof(LATTICE_START));
//delay(10);
}

void CatPrinter::endGraphics(void) {
sendCmd(CatPrinter::Cmd::LATTICE, LATTICE_END, sizeof(LATTICE_END));
delay(200);
Serial.println("ended graphics");
}

void CatPrinter::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) {
// Out of bounds
return;
}
uint16_t byteNo = x/8 + (y * WIDTH_BYTE);
uint8_t bitNo = 7-(x%8);
pixelBuffer[byteNo] = (pixelBuffer[byteNo] & ~(1 << bitNo)) | ((!color ? 1 : 0) << bitNo);
}

void CatPrinter::fillScreen(uint16_t color) {
fillBuffer((!color ? 0xFF : 0x00));
}

void CatPrinter::resetNameArray(void)
{
for (uint8_t i = 0; i < this->NAME_ARRAY_SIZE; i ++)
strcpy(this->printerNames[i], "");
}

bool CatPrinter::addNameArray(char *newname)
{
uint8_t i = 0;

if (strlen(newname) >= NAME_STRING_SIZE)
return (false);
while (i < this->NAME_ARRAY_SIZE)
{
if (strcmp(this->printerNames[i], "") != 0)
i ++;
else
break ;
}
if (i >= this->NAME_ARRAY_SIZE - 1)
return (false);
strcpy(this->printerNames[i], newname);
return (true);
}

void CatPrinter::printNameArray(void)
{
for (uint8_t i = 0; i < NAME_ARRAY_SIZE; i ++)
Serial.println(this->printerNames[i]);
}
121 changes: 121 additions & 0 deletions MEMENTO/Memento_Cat_Printer/CatGFX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-FileCopyrightText: 2022 Claus Näveke
//
// SPDX-License-Identifier: Unlicense
// https://github.com/TheNitek/CatGFX

#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <BLEDevice.h>

class CatPrinter: public Adafruit_GFX, public BLEAdvertisedDeviceCallbacks {
public:
enum class Cmd {
REVERSE_FEED = 0xA0,
PAPER_FEED = 0xA1,
PRINT = 0xA2,
QUALITY = 0xA4,
LATTICE = 0xA6,
UPDATE = 0xA9,
ENERGY = 0xAF,
DRAWING_MODE = 0xBE,
PRINT_COMPRESSED = 0xBF
};
CatPrinter(uint16_t h);
~CatPrinter() {
delete bleClient;
}
void begin(byte *buffer, uint16_t size);
void fillBuffer(const byte value);
bool connect(void);
bool connect(BLEAddress &address);
void disconnect(void);
void sendLine(const byte *data, const uint8_t len, const bool compressed = true);
void feed(uint8_t lines);
void printBuffer(void);
void sendCmd(const CatPrinter::Cmd cmd, const byte *data, const uint8_t len);
// GFX overrides
void drawPixel(int16_t x, int16_t y, uint16_t color) override;
void fillScreen(uint16_t color) override;
void startGraphics(void);
void endGraphics(void);
void resetNameArray(void);
bool addNameArray(char *newname);
void printNameArray(void);

private:
byte *pixelBuffer = nullptr;
uint16_t pixelBufferSize = 0;
const uint8_t PACKET_SIZE = 20;
const uint8_t WIDTH_BYTE = 48; // 384 pixel / 8 bits => 48 byte

const BLEUUID SERVICE_UUID;
const BLEUUID CHAR_UUID_DATA;

BLEAddress *blePrinterAddress = nullptr;
BLERemoteCharacteristic* pRemoteCharacteristicData = nullptr;
BLEScan *bleScan = BLEDevice::getScan();
BLEClient *bleClient = BLEDevice::createClient();;

//Indicates the end of the array with an empty string instead of NULL.
const static uint8_t NAME_ARRAY_SIZE = 6;
const static uint8_t NAME_STRING_SIZE = 8;
char printerNames[NAME_ARRAY_SIZE][NAME_STRING_SIZE];

const byte LATTICE_START[11] = {0xAA, 0x55, 0x17, 0x38, 0x44, 0x5F, 0x5F, 0x5F, 0x44, 0x38, 0x2C};
const byte LATTICE_END[11] = {0xAA, 0x55, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17};
const byte FEED_LINE_DATA[2] = {0x01, 0x00};

const byte CRC_TABLE[256] = {
0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
0xfa, 0xfd, 0xf4, 0xf3
};

const byte MIRROR_TABLE[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
0x3F, 0xBF, 0x7F, 0xFF
};

void onResult(BLEAdvertisedDevice advertisedDevice) override;
uint8_t crc(const byte *data, const uint8_t len);
void writeData(byte *data, uint8_t len);
};
Loading