* Copyright 2001-2017 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
* Adrien Destugues <pulkomandy@pulkomandy.tk>
*/
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <StorageKit.h>
#include <SupportKit.h>
#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;
};
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;
strcat(strcpy(device, "/dev/ports/"), address);
fFile = open(device, O_RDWR | O_EXCL, 0);
if (fFile < 0) {
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;
options.c_cc[VMIN] = 0;
if (size == sizeof(baudrate)) {
cfsetispeed(&options, baudrate);
cfsetospeed(&options, baudrate);
}
tcsetattr(fFile, TCSANOW, &options);
if (msg == NULL) {
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;
}