/* * Copyright 2001-2017 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Pfeiffer * Adrien Destugues */ #include #include #include #include #include #include "PrintTransportAddOn.h" class SerialTransport : public BDataIO { public: SerialTransport(BDirectory* printer, BMessage* msg); ~SerialTransport(); status_t InitCheck() { return fFile > -1 ? B_OK : B_ERROR; } ssize_t Read(void* buffer, size_t size); ssize_t Write(const void* buffer, size_t size); private: int fFile; }; // Impelmentation of SerialTransport SerialTransport::SerialTransport(BDirectory* printer, BMessage* msg) : fFile(-1) { char address[80]; char device[B_PATH_NAME_LENGTH]; bool bidirectional = true; unsigned int size = printer->ReadAttr("transport_address", B_STRING_TYPE, 0, address, sizeof(address)); if (size <= 0 || size >= sizeof(address)) return; address[size] = 0; // make sure string is 0-terminated strcat(strcpy(device, "/dev/ports/"), address); fFile = open(device, O_RDWR | O_EXCL, 0); if (fFile < 0) { // Try unidirectional access mode bidirectional = false; fFile = open(device, O_WRONLY | O_EXCL, 0); } if (fFile < 0) return; int32 baudrate; size = printer->ReadAttr("transport_baudrate", B_INT32_TYPE, 0, &baudrate, sizeof(baudrate)); struct termios options; tcgetattr(fFile, &options); cfmakeraw(&options); options.c_cc[VTIME] = 10; // wait for data at most for 1 second options.c_cc[VMIN] = 0; // allow to return 0 chars if (size == sizeof(baudrate)) { // Printer driver asked for a specific baudrate, configure it cfsetispeed(&options, baudrate); cfsetospeed(&options, baudrate); } tcsetattr(fFile, TCSANOW, &options); if (msg == NULL) { // Caller don't care about transport init message output content... return; } msg->what = 'okok'; msg->AddBool("bidirectional", bidirectional); msg->AddString("_serial/DeviceName", device); } SerialTransport::~SerialTransport() { if (InitCheck() == B_OK) close(fFile); } ssize_t SerialTransport::Read(void* buffer, size_t size) { return read(fFile, buffer, size); } ssize_t SerialTransport::Write(const void* buffer, size_t size) { return write(fFile, buffer, size); } BDataIO* instantiate_transport(BDirectory* printer, BMessage* msg) { SerialTransport* transport = new SerialTransport(printer, msg); if (transport->InitCheck() == B_OK) return transport; delete transport; return NULL; } status_t list_transport_ports(BMessage* msg) { BDirectory dir("/dev/ports"); status_t rc; if ((rc=dir.InitCheck()) != B_OK) return rc; if ((rc=dir.Rewind()) != B_OK) return rc; entry_ref ref; while (dir.GetNextRef(&ref) == B_OK) msg->AddString("port_id", ref.name); return B_OK; }