Files
ptouch-prnt/src/P700Printer.cpp
Moritz Martinius 3431cc2225
Some checks failed
Build ptprnt / build (push) Failing after 31s
Some refactorings to incoporate CLI parsing
2023-10-13 00:02:59 +02:00

203 lines
5.4 KiB
C++

/*
ptrnt - print labels on linux
Copyright (C) 2023 Moritz Martinius
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "P700Printer.hpp"
#include <algorithm>
#include <spdlog/spdlog.h>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <ratio>
#include <thread>
#include <vector>
#include "graphics/Bitmap.hpp"
#include "graphics/Image.hpp"
#include "graphics/Monochrome.hpp"
#include "libusb.h"
#include "libusbwrap/LibUsbTypes.hpp"
#include "spdlog/fmt/bin_to_hex.h"
// as long as DRYRUN is defined, no data is actually send to the printer, we need to save some tape ;)
//#define DRYRUN
namespace ptprnt::printer {
P700Printer::~P700Printer() {
detachUsbDevice();
if (mUsbHndl) {
mUsbHndl->close();
}
}
const std::string_view P700Printer::getDriverName() {
return mInfo.driverName;
}
const std::string_view P700Printer::getName() {
return mInfo.name;
}
const std::string_view P700Printer::getVersion() {
return mInfo.version;
}
const PrinterInfo P700Printer::getPrinterInfo() {
return mInfo;
}
const PrinterStatus P700Printer::getPrinterStatus() {
using namespace std::chrono_literals;
std::vector<uint8_t> getStatusCmd({0x1b, 0x69, 0x53}); // status info request
send(getStatusCmd);
int tx = 0;
int tries = 0;
std::vector<uint8_t> recvBuf(32);
while (tries++ < MAX_TRIES_GET_STATUS) {
std::this_thread::sleep_for(100ms);
mUsbHndl->bulkTransfer(commands["printerinfo"][0], recvBuf, &tx, 0);
}
return PrinterStatus{.tapeWidthMm = recvBuf[10]};
}
const uint16_t P700Printer::getVid() {
return mInfo.vid;
}
const uint16_t P700Printer::getPid() {
return mInfo.pid;
}
bool P700Printer::attachUsbDevice(std::shared_ptr<libusbwrap::IUsbDevice> usbHndl) {
if (!usbHndl->open()) {
spdlog::error("Unable to open USB device: {}", usbHndl->getLastErrorString());
return false;
}
if (!usbHndl->detachKernelDriver(0)) {
spdlog::error("Device is already in use or couldn't be detached from kernel: {}",
usbHndl->getLastErrorString());
return false;
}
if (!usbHndl->claimInterface(0)) {
spdlog::error("Could not claim interface 0: {}", usbHndl->getLastErrorString());
return false;
}
mUsbHndl = std::move(usbHndl);
return true;
}
bool P700Printer::detachUsbDevice() {
if (!mUsbHndl) {
spdlog::warn("No device to detach...");
return true;
}
if (!mUsbHndl->releaseInterface(0)) {
spdlog::error("Could not release interface 0: {}", mUsbHndl->getLastErrorString());
return false;
}
return true;
}
bool P700Printer::printBitmap(const graphics::Bitmap<graphics::ALPHA8>& bitmap) {
auto bm = graphics::Bitmap<graphics::ALPHA8>(512, 128);
{
auto img = graphics::Image();
bm.setPixels(std::vector<uint8_t>(img.getRaw(), img.getRaw() + 512 * 128));
}
send(commands["rasterstart"]);
std::vector<uint8_t> rastercmd(4);
rastercmd[0] = 0x47;
rastercmd[1] = 0x00; // size +1
rastercmd[2] = 0x00;
rastercmd[3] = 0x00; // size -1
for (unsigned int i = 0; i < bm.getWidth(); i++) {
auto bmcol = bm.getCol(i);
if (!bmcol) {
spdlog::error("Out of bounds bitmap access");
break;
}
auto monocol = graphics::Monochrome(*bmcol);
auto col = monocol.get();
std::vector<uint8_t> buf(0);
buf.insert(buf.begin(), rastercmd.begin(), rastercmd.end());
buf.insert(std::next(buf.begin(), 4), col.begin(), col.end());
buf[1] = col.size() + 1;
buf[3] = col.size() - 1;
if (!send(buf)) {
break;
};
}
send(commands["eject"]);
return true;
}
bool P700Printer::printText(const std::string& text, uint16_t fontSize) {
send(commands["lf"]);
send(commands["ff"]);
send(commands["eject"]);
return true;
}
bool P700Printer::send(std::vector<uint8_t>& data) {
if (mUsbHndl == nullptr || data.size() > 128) {
spdlog::error("Invalid device handle or invalid data.");
return false;
}
int tx = 0;
#ifndef DRYRUN
if (!mUsbHndl->bulkTransfer(0x02, data, &tx, 0)) {
spdlog::error("Error writing command to Printer: {}", mUsbHndl->getLastErrorString());
return false;
}
#else
tx = data.size();
spdlog::debug("USB raw data(len {}): {}", data.size(), spdlog::to_hex(data));
#endif
if (tx != static_cast<int>(data.size())) {
spdlog::error("Could not transfer all data via USB bulk transfer. Only send {} of {} bytes",
tx, data.size());
return false;
}
return true;
}
bool P700Printer::init() {
std::vector<uint8_t> cmd(102);
cmd[100] = 0x1b; /* ESC */
cmd[101] = 0x40; /* @ */
return send(cmd);
}
} // namespace ptprnt::printer