xref: /haiku/src/add-ons/print/transports/serial_port/SerialTransport.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2001-2017 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *   Michael Pfeiffer
7  *   Adrien Destugues <pulkomandy@pulkomandy.tk>
8  */
9 
10 
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <termios.h>
14 
15 #include <StorageKit.h>
16 #include <SupportKit.h>
17 
18 #include "PrintTransportAddOn.h"
19 
20 
21 class SerialTransport : public BDataIO {
22 public:
23 	SerialTransport(BDirectory* printer, BMessage* msg);
24 	~SerialTransport();
25 
26 	status_t InitCheck() { return fFile > -1 ? B_OK : B_ERROR; }
27 
28 	ssize_t Read(void* buffer, size_t size);
29 	ssize_t Write(const void* buffer, size_t size);
30 
31 private:
32 	int fFile;
33 };
34 
35 
36 // Impelmentation of SerialTransport
37 SerialTransport::SerialTransport(BDirectory* printer, BMessage* msg)
38 	: fFile(-1)
39 {
40 	char address[80];
41 	char device[B_PATH_NAME_LENGTH];
42 	bool bidirectional = true;
43 
44 	unsigned int size = printer->ReadAttr("transport_address", B_STRING_TYPE, 0,
45 		address, sizeof(address));
46 	if (size <= 0 || size >= sizeof(address)) return;
47 	address[size] = 0; // make sure string is 0-terminated
48 
49 	strcat(strcpy(device, "/dev/ports/"), address);
50 	fFile = open(device, O_RDWR | O_EXCL, 0);
51 	if (fFile < 0) {
52 		// Try unidirectional access mode
53 		bidirectional = false;
54 		fFile = open(device, O_WRONLY | O_EXCL, 0);
55 	}
56 
57 	if (fFile < 0)
58 		return;
59 
60 	int32 baudrate;
61 	size = printer->ReadAttr("transport_baudrate", B_INT32_TYPE, 0,
62 		&baudrate, sizeof(baudrate));
63 
64 	struct termios options;
65 	tcgetattr(fFile, &options);
66 
67 	cfmakeraw(&options);
68 	options.c_cc[VTIME] = 10; // wait for data at most for 1 second
69 	options.c_cc[VMIN] = 0; // allow to return 0 chars
70 
71 	if (size == sizeof(baudrate)) {
72 		// Printer driver asked for a specific baudrate, configure it
73 		cfsetispeed(&options, baudrate);
74 		cfsetospeed(&options, baudrate);
75 	}
76 
77 	tcsetattr(fFile, TCSANOW, &options);
78 
79 	if (msg == NULL) {
80 		// Caller don't care about transport init message output content...
81 		return;
82 	}
83 
84 	msg->what = 'okok';
85 	msg->AddBool("bidirectional", bidirectional);
86 	msg->AddString("_serial/DeviceName", device);
87 
88 }
89 
90 
91 SerialTransport::~SerialTransport()
92 {
93 	if (InitCheck() == B_OK)
94 		close(fFile);
95 }
96 
97 
98 ssize_t
99 SerialTransport::Read(void* buffer, size_t size)
100 {
101 	return read(fFile, buffer, size);
102 }
103 
104 
105 ssize_t
106 SerialTransport::Write(const void* buffer, size_t size)
107 {
108 	return write(fFile, buffer, size);
109 }
110 
111 
112 BDataIO*
113 instantiate_transport(BDirectory* printer, BMessage* msg)
114 {
115 	SerialTransport* transport = new SerialTransport(printer, msg);
116 	if (transport->InitCheck() == B_OK)
117 		return transport;
118 
119 	delete transport;
120 	return NULL;
121 }
122 
123 
124 status_t
125 list_transport_ports(BMessage* msg)
126 {
127 	BDirectory dir("/dev/ports");
128 	status_t rc;
129 
130 	if ((rc=dir.InitCheck()) != B_OK)
131 		return rc;
132 
133 	if ((rc=dir.Rewind()) != B_OK)
134 		return rc;
135 
136 	entry_ref ref;
137 	while (dir.GetNextRef(&ref) == B_OK)
138 		msg->AddString("port_id", ref.name);
139 
140 	return B_OK;
141 }
142