xref: /haiku/src/kits/device/SerialPort.cpp (revision 7cf3b2f4b10ac0c304e6fc71af3b1c9506fa6a00)
1 /*
2  * Copyright 2002, Jack Burton.
3  * Copyright 2002, Marcus Overhagen.
4  * All rights reserved.
5  * Distributed under the terms of the MIT License.
6  */
7 
8 #include <Directory.h>
9 #include <Entry.h>
10 #include <List.h>
11 #include <SerialPort.h>
12 
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <malloc.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <termios.h>
20 
21 /* The directory where the serial driver publishes its devices */
22 #define SERIAL_DIR "/dev/ports"
23 
24 
25 /* Creates and initializes a BSerialPort object,	*/
26 /* query the driver, and builds a list of available */
27 /* serial ports.									*/
28 
29 /* The BSerialPort object is initialized to these   */
30 /* values: */
31 /* 19200 BPS,	*/
32 /* 8 Data Bits, */
33 /* 1 Stop Bit,	*/
34 /* No Parity,	*/
35 /* Hardware Flow Control, */
36 /* Infinite Timeout	*/
37 /* and Blocking mode. */
38 BSerialPort::BSerialPort()
39 	:	ffd(-1),
40 		fBaudRate(B_19200_BPS),
41 		fDataBits(B_DATA_BITS_8),
42 		fStopBits(B_STOP_BIT_1),
43 		fParityMode(B_NO_PARITY),
44 		fFlow(B_HARDWARE_CONTROL),
45 		fTimeout(B_INFINITE_TIMEOUT),
46 		fBlocking(true),
47 		_fDevices(new BList)
48 {
49 	ScanDevices();
50 }
51 
52 
53 /* Closes the port, if it's open, and deletes the devices list */
54 BSerialPort::~BSerialPort()
55 {
56 	if (ffd > 0)
57 		close(ffd);
58 
59 	for (int32 count = _fDevices->CountItems() - 1; count >= 0; count--)
60 		free(_fDevices->RemoveItem(count));
61 
62 	delete _fDevices;
63 }
64 
65 
66 /* Opens a serial port. @param a valid port name */
67 status_t
68 BSerialPort::Open(const char *portName)
69 {
70 	char buf[64];
71 
72 	//TODO: Check if portName is a valid name
73 	sprintf(buf, SERIAL_DIR"/%s", portName);
74 
75 	if (ffd > 0) //If this port is already open, close it
76 		close(ffd);
77 
78 	ffd = open(buf, O_RDWR|O_NONBLOCK); //R5 seem to use this mask
79 
80 	if (ffd > 0)
81 		DriverControl(); //Setup the port
82 
83 	return (ffd < 0) ? ffd : B_OK;
84 }
85 
86 
87 /* Closes the port */
88 void
89 BSerialPort::Close(void)
90 {
91 	if (ffd > 0)
92 		close(ffd);
93 	ffd = -1;
94 }
95 
96 
97 /* Read some data from the serial port. */
98 /* @param the buffer where to transfer the data */
99 /* @param how many bytes to read	*/
100 ssize_t
101 BSerialPort::Read(void *buf, size_t count)
102 {
103 	if (ffd < 0) // We have no open port
104 		return B_FILE_ERROR;
105 
106 	return read(ffd, buf, count);
107 }
108 
109 
110 /* Write some data to the serial port. */
111 /* @param the buffer from which transfer the data */
112 /* @param how many bytes to write	*/
113 ssize_t
114 BSerialPort::Write(const void *buf, size_t count)
115 {
116 	if (ffd < 0) // We have no open port
117 		return B_FILE_ERROR;
118 
119 	return write(ffd, buf, count);
120 }
121 
122 
123 /* Set blocking mode */
124 void
125 BSerialPort::SetBlocking(bool Blocking)
126 {
127 	fBlocking = Blocking;
128 	DriverControl();
129 }
130 
131 
132 /* Set the timeout for the port */
133 /* Valid values: B_INFINITE_TIMEOUT or any value between 0 and 25000000 */
134 status_t
135 BSerialPort::SetTimeout(bigtime_t microSeconds)
136 {
137 	status_t err = B_BAD_VALUE;
138 
139 	if (microSeconds == B_INFINITE_TIMEOUT || microSeconds <= 25000000)
140 	{
141 		fTimeout = microSeconds;
142 		DriverControl();
143 		err = B_OK;
144 	}
145 	return err;
146 }
147 
148 
149 /* Set the data rate (Baud rate) for the port */
150 status_t
151 BSerialPort::SetDataRate(data_rate bitsPerSecond)
152 {
153 	fBaudRate = bitsPerSecond;
154 
155 	return DriverControl();
156 }
157 
158 
159 /* Get the data rate (Baud Rate) */
160 data_rate
161 BSerialPort::DataRate(void)
162 {
163 	return fBaudRate;
164 }
165 
166 
167 /* Set the data bits (7 or 8) */
168 void
169 BSerialPort::SetDataBits(data_bits numBits)
170 {
171 	fDataBits = numBits;
172 	DriverControl();
173 }
174 
175 
176 /* Get the data bits */
177 data_bits
178 BSerialPort::DataBits(void)
179 {
180 	return fDataBits;
181 }
182 
183 
184 /* Set the stop bits (1 or 2) */
185 void
186 BSerialPort::SetStopBits(stop_bits numBits)
187 {
188 	fStopBits = numBits;
189 	DriverControl();
190 }
191 
192 
193 /* Get the stop bits */
194 stop_bits
195 BSerialPort::StopBits(void)
196 {
197 	return fStopBits;
198 }
199 
200 
201 /* Set the parity mode (ODD, PAIR, or NONE) */
202 void
203 BSerialPort::SetParityMode(parity_mode which)
204 {
205 	fParityMode = which;
206 	DriverControl();
207 }
208 
209 
210 /* Get the parity mode */
211 parity_mode
212 BSerialPort::ParityMode(void)
213 {
214 	return fParityMode;
215 }
216 
217 
218 /* Clear the input buffer */
219 void
220 BSerialPort::ClearInput(void)
221 {
222 	tcflush(ffd, TCIFLUSH);
223 }
224 
225 
226 /* Clear the output buffer */
227 void
228 BSerialPort::ClearOutput(void)
229 {
230 	tcflush(ffd, TCOFLUSH);
231 }
232 
233 
234 /* Set the flow control (HARDWARE, SOFTWARE, or NONE) */
235 void
236 BSerialPort::SetFlowControl(uint32 method)
237 {
238 	fFlow = method;
239 	DriverControl();
240 }
241 
242 
243 /* Get the flow control */
244 uint32
245 BSerialPort::FlowControl(void)
246 {
247 	return fFlow;
248 }
249 
250 
251 /* Set the DTR */
252 status_t
253 BSerialPort::SetDTR(bool asserted)
254 {
255 	status_t status = ioctl(ffd, TCSETDTR, &asserted);
256 
257 	return (status > 0) ? status : errno;
258 }
259 
260 
261 /* Set the RTS status */
262 status_t
263 BSerialPort::SetRTS(bool asserted)
264 {
265 	status_t status = ioctl(ffd, TCSETRTS, &asserted);
266 
267 	return (status > 0) ? status : errno;
268 }
269 
270 
271 /* See how many chars are queued on the serial port, */
272 /* waiting to be read */
273 status_t
274 BSerialPort::NumCharsAvailable(int32 *wait_until_this_many)
275 {
276 	//No help from the BeBook...
277 	if (ffd < 0)
278 		return B_ERROR;
279 
280 	//TODO: Implement
281 	return B_OK;
282 }
283 
284 
285 /* See if CTS is set */
286 bool
287 BSerialPort::IsCTS(void)
288 {
289 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
290 
291 	if (bits & TCGB_CTS)
292 		return true;
293 
294 	return false;
295 }
296 
297 
298 /* See if DSR is set */
299 bool
300 BSerialPort::IsDSR(void)
301 {
302 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
303 
304 	if (bits & TCGB_DSR)
305 		return true;
306 
307 	return false;
308 }
309 
310 
311 /* See if RI is set */
312 bool
313 BSerialPort::IsRI(void)
314 {
315 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
316 
317 	if (bits & TCGB_RI)
318 		return true;
319 
320 	return false;
321 }
322 
323 
324 /* See if DCD is set */
325 bool
326 BSerialPort::IsDCD(void)
327 {
328 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
329 
330 	if (bits & TCGB_DCD)
331 		return true;
332 
333 	return false;
334 }
335 
336 
337 /* Wait until there's something to read from the serial port. */
338 /* If no data is ready, it will always block, ignoring the    */
339 /* value of SetBlocking(); however, it respects the timeout   */
340 /* set by SetTimeout(). */
341 ssize_t
342 BSerialPort::WaitForInput(void)
343 {
344 	ssize_t size;
345 	int err = ioctl(ffd, TCWAITEVENT, &size, sizeof size);
346 
347 	return (err < B_OK) ? errno : size;
348 }
349 
350 
351 /* Returns the number of available Serial Ports. */
352 int32
353 BSerialPort::CountDevices()
354 {
355 	int32 count = 0;
356 
357 	if (_fDevices != NULL)
358 		count = _fDevices->CountItems();
359 
360 	return count;
361 }
362 
363 
364 /* Get the device name for the given device.*/
365 /* The first parameter is the number of the device */
366 /* you want to know the name, the second is the buffer */
367 /* where you want to store the name, and the third is  */
368 /* the length of that buffer. */
369 status_t
370 BSerialPort::GetDeviceName(int32 n, char *name, size_t bufSize)
371 {
372 	status_t result = B_ERROR;
373 	char *dev = NULL;
374 
375 	if (_fDevices != NULL)
376 		dev = static_cast<char*>(_fDevices->ItemAt(n));
377 
378 	if (dev != NULL && name != NULL) {
379 		strncpy(name, dev, bufSize);
380 		result = B_OK;
381 	}
382 	return result;
383 }
384 
385 
386 /* Private or Reserved */
387 
388 /* Query the serial driver about the available devices, */
389 /* and build a list of them. */
390 void
391 BSerialPort::ScanDevices()
392 {
393 	BEntry entry;
394 	BDirectory dir(SERIAL_DIR);
395 	char buf[B_OS_NAME_LENGTH];
396 
397 	//First, we empty the list
398 	for (int32 count = _fDevices->CountItems() - 1; count >= 0; count--)
399 		free(_fDevices->RemoveItem(count));
400 
401 	//Then, add the devices to the list
402 	while (dir.GetNextEntry(&entry) == B_OK)
403 	{
404 		entry.GetName(buf);
405 		_fDevices->AddItem(strdup(buf));
406 	};
407 }
408 
409 
410 /* Send the options to the serial driver. */
411 /* Returns B_OK if all goes fine, an error code */
412 /* if something goes wrong. */
413 int
414 BSerialPort::DriverControl()
415 {
416 	struct termio termioControl;
417 	int err;
418 
419 	if (ffd < 0)
420 		return B_NO_INIT;
421 
422 	//Load the current settings
423 	err = ioctl(ffd, TCGETA, &termioControl);
424 	if (err < 0)
425 		return errno;
426 
427 	// Reset all flags
428 	termioControl.c_cflag &= ~(CRTSCTS | CSIZE | CBAUD | CSTOPB | PARODD | PARENB);
429 	termioControl.c_iflag &= ~(IXON | IXOFF | IXANY | INPCK);
430 	termioControl.c_lflag &= ~(ECHO | ECHONL | ISIG | ICANON);
431 
432 	//Set the flags to the wanted values
433 	if (fFlow & B_HARDWARE_CONTROL)
434 		termioControl.c_cflag |= CRTSCTS;
435 
436 	if (fFlow & B_SOFTWARE_CONTROL)
437 		termioControl.c_iflag |= (IXON | IXOFF);
438 
439 	if (fStopBits & B_STOP_BITS_2)
440 		termioControl.c_cflag |= CSTOPB; // We want 2 stop bits
441 
442 	if (fDataBits == B_DATA_BITS_8)
443 		termioControl.c_cflag |= CS8; // We want 8 data bits
444 
445 	//Ok, set the parity now
446 	if (fParityMode != B_NO_PARITY)
447 	{
448 		termioControl.c_cflag |= PARENB; //Enable parity
449 		if (fParityMode == B_ODD_PARITY)
450 			termioControl.c_cflag |= PARODD; //Select odd parity
451 	}
452 
453 	//Set the baud rate
454 	termioControl.c_cflag |= (fBaudRate & CBAUD);
455 
456 	//Set the timeout
457 	if (fBlocking)
458 	{
459 		if (fTimeout == B_INFINITE_TIMEOUT)
460 		{
461 			termioControl.c_cc[VTIME] = 0;
462 			termioControl.c_cc[VMIN] = 1;
463 		}
464 		else if (fTimeout == 0)
465 			termioControl.c_cc[VMIN] = 0;
466 		else
467 		{
468 			int t = fTimeout / 100000;
469 			termioControl.c_cc[VTIME] = (t == 0) ? 1 : t;
470 			termioControl.c_cc[VMIN] = 1;
471 		}
472 	} else
473 		termioControl.c_cc[VMIN] = 0;
474 
475 	//Ok, finished. Now tell the driver what we decided
476 	err = ioctl(ffd, TCSETA, &termioControl);
477 
478 	return err > 0 ? err : errno;
479 }
480 
481 
482 /* These functions are here to maintain Binary Compatibility */
483 void BSerialPort::_ReservedSerialPort1() {}
484 void BSerialPort::_ReservedSerialPort2() {}
485 void BSerialPort::_ReservedSerialPort3() {}
486 void BSerialPort::_ReservedSerialPort4() {}
487