diff --git a/src/P700Printer.cpp b/src/P700Printer.cpp index 41b1bf0..4e5cba0 100644 --- a/src/P700Printer.cpp +++ b/src/P700Printer.cpp @@ -1,8 +1,29 @@ #include "P700Printer.hpp" +#include + +#include +#include #include +#include +#include +#include + +#include "libusb.h" +#include "libusbwrap/LibUsbTypes.hpp" +#include "spdlog/fmt/bin_to_hex.h" namespace ptprnt::printer { + +P700Printer::P700Printer() {} + +P700Printer::~P700Printer() { + detachUsbDevice(); + if (mUsbHndl) { + mUsbHndl->close(); + } +} + const std::string_view P700Printer::getDriverName() { return mInfo.driverName; } @@ -19,6 +40,25 @@ const PrinterInfo P700Printer::getPrinterInfo() { return mInfo; } +const PrinterStatus P700Printer::getPrinterStatus() { + using namespace std::chrono_literals; + std::vector getStatusCmd({0x1b, 0x69, 0x53}); // status info request + send(getStatusCmd); + + int tx = 0; + int tries = 0; + std::vector recvBuf(32); + do { + std::this_thread::sleep_for(100ms); + mUsbHndl->bulkTransfer(0x81, recvBuf, &tx, 0); + if (tries++ > 10) { + break; + } + } while (tx == 0); + + return PrinterStatus{.tapeWidthMm = recvBuf[10]}; +} + const uint16_t P700Printer::getVid() { return mInfo.vid; } @@ -28,10 +68,35 @@ const uint16_t P700Printer::getPid() { } bool P700Printer::attachUsbDevice(std::shared_ptr 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; } @@ -42,4 +107,18 @@ bool P700Printer::printBitmap(const Bitmap& bitmap) { bool P700Printer::printText(const std::string& text, uint16_t fontSize) { return true; } + +bool P700Printer::send(std::vector& data) { + + if (mUsbHndl == nullptr || data.size() > 128) { + spdlog::error("Invalid device handle or invalid data."); + return false; + } + if (!mUsbHndl->bulkTransfer(0x02, data, nullptr, 0)) { + spdlog::error("Error writing command to Printer: {}", mUsbHndl->getLastErrorString()); + return false; + } + + return true; +} } // namespace ptprnt::printer \ No newline at end of file diff --git a/src/P700Printer.hpp b/src/P700Printer.hpp index e18497d..66222dc 100644 --- a/src/P700Printer.hpp +++ b/src/P700Printer.hpp @@ -1,3 +1,5 @@ +#include + #include #include "interface/IPrinterDriver.hpp" @@ -10,8 +12,8 @@ namespace ptprnt::printer { class P700Printer : public ::ptprnt::IPrinterDriver { public: - P700Printer() = default; - ~P700Printer() = default; + P700Printer(); + ~P700Printer(); // delete copy ctor and assignment P700Printer(const P700Printer&) = delete; @@ -24,12 +26,15 @@ class P700Printer : public ::ptprnt::IPrinterDriver { const uint16_t getVid() override; const std::string_view getVersion() override; const PrinterInfo getPrinterInfo() override; + const PrinterStatus getPrinterStatus() override; bool attachUsbDevice(std::shared_ptr usbHndl) override; bool detachUsbDevice() override; bool printBitmap(const Bitmap& bitmap) override; bool printText(const std::string& text, uint16_t fontSize) override; private: + bool send(std::vector& data); + std::shared_ptr mUsbHndl{nullptr}; PrinterInfo mInfo{.driverName = "P700", diff --git a/src/PtouchPrint.cpp b/src/PtouchPrint.cpp index 037e444..a69a103 100644 --- a/src/PtouchPrint.cpp +++ b/src/PtouchPrint.cpp @@ -15,10 +15,26 @@ void PtouchPrint::init() { } void PtouchPrint::run() { - if (getCompatiblePrinters() == 0) { + auto numFoundPrinters = getCompatiblePrinters(); + if (numFoundPrinters == 0) { spdlog::error( "No compatible printers found, please make sure if they are turned on and connected"); + return; + } else if (numFoundPrinters > 1) { + spdlog::warn("Found more than one compatible printer. Currently not supported."); + return; } + + auto printer = mCompatiblePrinters[0]; + auto devices = mUsbDeviceFactory.findDevices(printer->getVid(), printer->getPid()); + if (devices.size() != 1) { + spdlog::warn( + "Found more than one device of the same printer on bus. Currently not supported"); + return; + } + printer->attachUsbDevice(devices[0]); + auto status = printer->getPrinterStatus(); + spdlog::info("Detected tape width is {}mm", status.tapeWidthMm); } unsigned int PtouchPrint::getCompatiblePrinters() { diff --git a/src/interface/IPrinterDriver.hpp b/src/interface/IPrinterDriver.hpp index b91c8b2..33838de 100644 --- a/src/interface/IPrinterDriver.hpp +++ b/src/interface/IPrinterDriver.hpp @@ -17,6 +17,7 @@ class IPrinterDriver { virtual const uint16_t getVid() = 0; virtual const uint16_t getPid() = 0; virtual const PrinterInfo getPrinterInfo() = 0; + virtual const PrinterStatus getPrinterStatus() = 0; virtual bool attachUsbDevice(std::shared_ptr usbHndl) = 0; virtual bool detachUsbDevice() = 0; virtual bool printBitmap(const Bitmap& bitmap) = 0; diff --git a/src/interface/IPrinterTypes.hpp b/src/interface/IPrinterTypes.hpp index e4d184a..216cdc8 100644 --- a/src/interface/IPrinterTypes.hpp +++ b/src/interface/IPrinterTypes.hpp @@ -14,4 +14,9 @@ struct PrinterInfo { uint16_t pid = 0x00; }; +struct PrinterStatus { + unsigned int tapeWidthPixel = 0; + unsigned int tapeWidthMm = 0.0; +}; + } // namespace ptprnt \ No newline at end of file diff --git a/src/libusbwrap/UsbDevice.cpp b/src/libusbwrap/UsbDevice.cpp index 3cc2965..daeb994 100644 --- a/src/libusbwrap/UsbDevice.cpp +++ b/src/libusbwrap/UsbDevice.cpp @@ -1,8 +1,10 @@ #include "libusbwrap/UsbDevice.hpp" +#include #include #include "libusb.h" +#include "libusbwrap/LibUsbTypes.hpp" #include "libusbwrap/interface/IUsbDevice.hpp" namespace libusbwrap { @@ -22,14 +24,67 @@ UsbDevice::~UsbDevice() { } } -Error UsbDevice::open() { - return static_cast(libusb_open(mLibusbDev, &mLibusbDevHandle)); +bool UsbDevice::open() { + int openStatus = libusb_open(mLibusbDev, &mLibusbDevHandle); + if (openStatus != 0) { + mLastError = static_cast(openStatus); + return false; + } + + return true; } void UsbDevice::close() { libusb_close(mLibusbDevHandle); } +bool UsbDevice::detachKernelDriver(int interfaceNo) { + // TODO: cover the other status codes that can be returned + int kernelDriverStatus = libusb_kernel_driver_active(mLibusbDevHandle, interfaceNo); + if (kernelDriverStatus == 1) { // kernel driver is active, we have to detach to continue... + int detachStatus = libusb_detach_kernel_driver(mLibusbDevHandle, interfaceNo); + if (detachStatus != 0) { + mLastError = static_cast(detachStatus); + return false; + } + } + + return true; +} + +bool UsbDevice::claimInterface(int interfaceNo) { + // TODO: cover the other status codes that can be returned + int claimInterfaceStatus = libusb_claim_interface(mLibusbDevHandle, interfaceNo); + if (claimInterfaceStatus != 0) { + mLastError = static_cast(claimInterfaceStatus); + return false; + } + return true; +} + +bool UsbDevice::releaseInterface(int interfaceNo) { + int releaseInterfaceStatus = libusb_release_interface(mLibusbDevHandle, interfaceNo); + if (releaseInterfaceStatus != 0) { + mLastError = static_cast(releaseInterfaceStatus); + return false; + } + return true; +} + +bool UsbDevice::bulkTransfer(uint8_t endpoint, std::vector& data, int* tx, + unsigned int timeout) { + // TODO: implement error handling for incomplete transactions (tx length != data length) + int bulkTransferStatus = 0; + + bulkTransferStatus = + libusb_bulk_transfer(mLibusbDevHandle, endpoint, data.data(), data.size(), tx, timeout); + if (bulkTransferStatus != 0) { + mLastError = static_cast(bulkTransferStatus); + return false; + } + return true; +} + const uint16_t UsbDevice::getVid() { return mLibusbDevDesc.idVendor; } @@ -49,4 +104,12 @@ const uint8_t UsbDevice::getBusNumber() { const uint8_t UsbDevice::getPortNumber() { return libusb_get_port_number(mLibusbDev); } + +const Error UsbDevice::getLastError() { + return mLastError; +} + +const std::string UsbDevice::getLastErrorString() { + return std::string(libusb_error_name(static_cast(mLastError))); +} } // namespace libusbwrap \ No newline at end of file diff --git a/src/libusbwrap/UsbDevice.hpp b/src/libusbwrap/UsbDevice.hpp index a26cd7d..972bfa7 100644 --- a/src/libusbwrap/UsbDevice.hpp +++ b/src/libusbwrap/UsbDevice.hpp @@ -4,6 +4,7 @@ #include #include "libusb.h" +#include "libusbwrap/LibUsbTypes.hpp" #include "libusbwrap/interface/IUsbDevice.hpp" namespace libusbwrap { @@ -16,9 +17,16 @@ class UsbDevice : public IUsbDevice { UsbDevice(const UsbDevice&) = delete; UsbDevice& operator=(UsbDevice&) = delete; - Error open() override; + bool open() override; void close() override; + // libusb wrappers + bool detachKernelDriver(int interfaceNo) override; + bool claimInterface(int interfaceNo) override; + bool releaseInterface(int interfaceNo) override; + bool bulkTransfer(uint8_t endpoint, std::vector& data, int* tx, + unsigned int timeout) override; + // getters const uint16_t getVid() override; const uint16_t getPid() override; @@ -26,11 +34,16 @@ class UsbDevice : public IUsbDevice { const uint8_t getBusNumber() override; const uint8_t getPortNumber() override; + // errors + const Error getLastError() override; + const std::string getLastErrorString() override; + private: libusb_context* mLibusbCtx{nullptr}; libusb_device* mLibusbDev{nullptr}; libusb_device_handle* mLibusbDevHandle{nullptr}; libusb_device_descriptor mLibusbDevDesc; std::atomic mIsOpen = false; + Error mLastError = Error::SUCCESS; }; } // namespace libusbwrap \ No newline at end of file diff --git a/src/libusbwrap/UsbDeviceFactory.cpp b/src/libusbwrap/UsbDeviceFactory.cpp index 63f7002..ea5dc83 100644 --- a/src/libusbwrap/UsbDeviceFactory.cpp +++ b/src/libusbwrap/UsbDeviceFactory.cpp @@ -33,8 +33,6 @@ int UsbDeviceFactory::refreshDeviceList() { spdlog::error("Error enumarating USB devices"); } else if (ret == 0) { spdlog::warn("No USB devices found"); - } else { - spdlog::debug("Found {} USB devices", ret); } return ret; diff --git a/src/libusbwrap/interface/IUsbDevice.hpp b/src/libusbwrap/interface/IUsbDevice.hpp index 0291cd5..9fec3f1 100644 --- a/src/libusbwrap/interface/IUsbDevice.hpp +++ b/src/libusbwrap/interface/IUsbDevice.hpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include "libusb.h" #include "libusbwrap/LibUsbTypes.hpp" @@ -22,14 +24,25 @@ enum class Speed { class IUsbDevice { public: - virtual Error open() = 0; + virtual bool open() = 0; virtual void close() = 0; + // libusb wrappers + virtual bool detachKernelDriver(int interfaceNo) = 0; + virtual bool claimInterface(int interfaceNo) = 0; + virtual bool releaseInterface(int interfaceNo) = 0; + virtual bool bulkTransfer(uint8_t endpoint, std::vector& data, int* tx, + unsigned int timeout) = 0; + // getters virtual const uint16_t getVid() = 0; virtual const uint16_t getPid() = 0; virtual const device::Speed getSpeed() = 0; virtual const uint8_t getBusNumber() = 0; virtual const uint8_t getPortNumber() = 0; + + // errors + virtual const Error getLastError() = 0; + virtual const std::string getLastErrorString() = 0; }; } // namespace libusbwrap \ No newline at end of file