xref: /haiku/src/kits/device/SerialPort.cpp (revision 071ff801eebdc5e7c0b4acfd861cceead5174336)
1 /*
2  * Copyright 2002-2004, Marcus Overhagen, Stefano Ceccherini.
3  * All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include <Debug.h>
8 #include <Directory.h>
9 #include <Entry.h>
10 #include <List.h>
11 #include <SerialPort.h>
12 
13 #include <new>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/ioctl.h>
21 #include <termios.h>
22 
23 
24 /* The directory where the serial driver publishes its devices */
25 #define SERIAL_DIR "/dev/ports"
26 
27 // Scans a directory and adds the entries it founds as strings to the
28 // given list
29 static int32
scan_directory(const char * directory,BList * list)30 scan_directory(const char *directory, BList *list)
31 {
32 	BEntry entry;
33 	BDirectory dir(SERIAL_DIR);
34 	char buf[B_OS_NAME_LENGTH];
35 
36 	ASSERT(list != NULL);
37 	while (dir.GetNextEntry(&entry) == B_OK) {
38 		entry.GetName(buf);
39 		list->AddItem(strdup(buf));
40 	};
41 
42 	return list->CountItems();
43 }
44 
45 
46 /*! \brief Creates and initializes a BSerialPort object.
47 
48 	Query the driver, and builds a list of the available
49 	serial ports.
50 	The BSerialPort object is initialized to these values:
51 	- \c B_19200_BPS
52 	- \c B_DATA_BITS_8
53 	- \c B_STOP_BIT_1
54 	- \c B_NO_PARITY
55 	- \c B_HARDWARE_CONTROL
56 	- \c B_INFINITE_TIMEOUT
57 	- Blocking mode
58 */
BSerialPort()59 BSerialPort::BSerialPort()
60 	:
61 	ffd(-1),
62 	fBaudRate(B_19200_BPS),
63 	fDataBits(B_DATA_BITS_8),
64 	fStopBits(B_STOP_BIT_1),
65 	fParityMode(B_NO_PARITY),
66 	fFlow(B_HARDWARE_CONTROL),
67 	fTimeout(B_INFINITE_TIMEOUT),
68 	fBlocking(true),
69 	fDevices(new(std::nothrow) BList)
70 {
71 	_ScanDevices();
72 }
73 
74 
75 /*! \brief Frees the resources associated with the object.
76 	Closes the port, if it's open, and deletes the devices list.
77 */
~BSerialPort()78 BSerialPort::~BSerialPort()
79 {
80 	if (ffd >= 0)
81 		close(ffd);
82 
83 	if (fDevices != NULL) {
84 		for (int32 count = fDevices->CountItems() - 1; count >= 0; count--)
85 			free(fDevices->RemoveItem(count));
86 		delete fDevices;
87 	}
88 }
89 
90 
91 /*! \brief Opens a serial port.
92 	\param portName A valid port name
93 		(i.e."/dev/ports/serial2", "serial2", ...)
94 	\return
95 	- A positive number if the serialport has been succesfully opened.
96 	- An errorcode (negative integer) if not.
97 */
98 status_t
Open(const char * portName)99 BSerialPort::Open(const char *portName)
100 {
101 	char buf[64];
102 
103 	if (portName == NULL)
104 		return B_BAD_VALUE; // Heheee, we won't crash
105 
106 	if (portName[0] != '/')
107 		snprintf(buf, 64, SERIAL_DIR"/%s", portName);
108 	else
109 		// A name like "/dev/ports/serial2" was passed
110 		snprintf(buf, 64, "%s", portName);
111 
112 	if (ffd >= 0) //If this port is already open, close it
113 		close(ffd);
114 
115 	// TODO: BeOS don't use O_EXCL, and this seems to lead
116 	// to some issues. I added this flag having read some comments
117 	// by Marco Nelissen on the annotated BeBook.
118 	// I think BeOS uses O_RDWR|O_NONBLOCK here.
119 	ffd = open(buf, O_RDWR | O_NONBLOCK | O_EXCL);
120 
121 	if (ffd >= 0) {
122 		// we used open() with O_NONBLOCK flag to let it return immediately,
123 		// but we want read/write operations to block if needed,
124 		// so we clear that bit here.
125 		int flags = fcntl(ffd, F_GETFL);
126 		fcntl(ffd, F_SETFL, flags & ~O_NONBLOCK);
127 
128 		_DriverControl();
129 	}
130 	// TODO: I wonder why the return type is a status_t,
131 	// since we (as BeOS does) return the descriptor number for the device...
132 	return (ffd >= 0) ? ffd : errno;
133 }
134 
135 
136 /*! \brief Closes the port.
137 */
138 void
Close(void)139 BSerialPort::Close(void)
140 {
141 	if (ffd >= 0)
142 		close(ffd);
143 	ffd = -1;
144 }
145 
146 
147 /*! \brief Reads some bytes from the serial port.
148 	\param buf The buffer where to copy the data.
149 	\param count The maximum amount of bytes to read.
150 	\return The amount of data read.
151 */
152 ssize_t
Read(void * buf,size_t count)153 BSerialPort::Read(void *buf, size_t count)
154 {
155 	ssize_t err = read(ffd, buf, count);
156 
157 	return (err >= 0) ? err : errno;
158 }
159 
160 
161 /*! \brief Writes some bytes to the serial port.
162 	\param buf The buffer which copy the data from.
163 	\param count The amount of bytes to write.
164 */
165 ssize_t
Write(const void * buf,size_t count)166 BSerialPort::Write(const void *buf, size_t count)
167 {
168 	ssize_t err = write(ffd, buf, count);
169 
170 	return (err >= 0) ? err : errno;
171 }
172 
173 
174 /*! \brief Set blocking mode
175 	\param Blocking If true, enables the blocking mode. If false, disables it.
176 */
177 void
SetBlocking(bool Blocking)178 BSerialPort::SetBlocking(bool Blocking)
179 {
180 	fBlocking = Blocking;
181 	_DriverControl();
182 }
183 
184 
185 /*! \brief Set the timeout for the port.
186 	\param microSeconds The timeout for the port.
187 	Valid values are:
188 	- \c B_INFINITE_TIMEOUT
189 	- Any value between 0 and 25,000,000, but remember that the granularity
190 		of the serial driver is 100,000 microseconds.
191 */
192 status_t
SetTimeout(bigtime_t microSeconds)193 BSerialPort::SetTimeout(bigtime_t microSeconds)
194 {
195 	status_t err = B_BAD_VALUE;
196 
197 	if (microSeconds == B_INFINITE_TIMEOUT || microSeconds <= 25000000) {
198 		fTimeout = microSeconds;
199 		_DriverControl();
200 		err = B_OK;
201 	}
202 	return err;
203 }
204 
205 
206 /*! \brief Set the Baud rate for the port.
207 	\param bitsPerSeconds The baud rate.
208 	Valid values:
209 	- \c B_0_BPS
210 	- \c B_50_BPS
211 	- \c B_75_BPS
212 	- \c B_110_BPS
213 	- \c B_134_BPS
214 	- \c B_150_BPS
215 	- \c B_200_BPS
216 	- \c B_300_BPS
217 	- \c B_600_BPS
218 	- \c B_1200_BPS
219 	- \c B_1800_BPS
220 	- \c B_2400_BPS
221 	- \c B_4800_BPS
222 	- \c B_9600_BPS
223 	- \c B_19200_BPS
224 	- \c B_38400_BPS
225 	- \c B_57600_BPS
226 	- \c B_115200_BPS
227 	- \c B_230400_BPS
228 	- \c B_31250_BPS
229 	\return
230 	- \c B_OK if all goes fine,
231 	- an error code if something goes wrong.
232 */
233 status_t
SetDataRate(data_rate bitsPerSecond)234 BSerialPort::SetDataRate(data_rate bitsPerSecond)
235 {
236 	fBaudRate = bitsPerSecond;
237 
238 	return _DriverControl();
239 }
240 
241 
242 /*! \brief Get the current Baud Rate.
243 	\return The current Baud Rate.
244 */
245 
246 data_rate
DataRate(void)247 BSerialPort::DataRate(void)
248 {
249 	return fBaudRate;
250 }
251 
252 
253 /*! \brief Set the data bits (7 or 8)
254 */
255 void
SetDataBits(data_bits numBits)256 BSerialPort::SetDataBits(data_bits numBits)
257 {
258 	fDataBits = numBits;
259 	_DriverControl();
260 }
261 
262 
263 /*! \brief Get the current data bits.
264  	\return The current data bits.
265 */
266 data_bits
DataBits(void)267 BSerialPort::DataBits(void)
268 {
269 	return fDataBits;
270 }
271 
272 
273 /*! \brief Set the stop bits.
274 	\param numBits The number of stop bits
275 	Valid values:
276 	- \c B_STOP_BITS_1 (or \c B_STOP_BIT_1)
277 	- \c B_STOP_BITS_2
278 */
279 void
SetStopBits(stop_bits numBits)280 BSerialPort::SetStopBits(stop_bits numBits)
281 {
282 	fStopBits = numBits;
283 	_DriverControl();
284 }
285 
286 
287 /*! \brief Get the current stop bits.
288 	\return The current stop bits.
289 */
290 stop_bits
StopBits(void)291 BSerialPort::StopBits(void)
292 {
293 	return fStopBits;
294 }
295 
296 
297 /*! \brief Set the parity mode.
298 	\param which The parity mode to set.
299 	Valid values:
300 	- \c B_ODD_PARITY
301 	- \c B_EVEN_PARITY
302 	- \c B_NO_PARITY
303 */
304 void
SetParityMode(parity_mode which)305 BSerialPort::SetParityMode(parity_mode which)
306 {
307 	fParityMode = which;
308 	_DriverControl();
309 }
310 
311 
312 /*! \brief Get the parity mode.
313 	\return The current parity mode.
314 */
315 parity_mode
ParityMode(void)316 BSerialPort::ParityMode(void)
317 {
318 	return fParityMode;
319 }
320 
321 
322 /*! \brief Clear the input buffer.
323 */
324 void
ClearInput(void)325 BSerialPort::ClearInput(void)
326 {
327 	tcflush(ffd, TCIFLUSH);
328 }
329 
330 
331 /*! \brief Clear the output buffer.
332 */
333 void
ClearOutput(void)334 BSerialPort::ClearOutput(void)
335 {
336 	tcflush(ffd, TCOFLUSH);
337 }
338 
339 
340 /*! \brief Set the flow control
341 	\param method The type of flow control.
342 	Valid values:
343 	- \c B_HARDWARE_CONTROL
344 	- \c B_SOFTWARE_CONTROL
345 	- \c B_NOFLOW_CONTROL
346 */
347 void
SetFlowControl(uint32 method)348 BSerialPort::SetFlowControl(uint32 method)
349 {
350 	fFlow = method;
351 	_DriverControl();
352 }
353 
354 
355 /*! \brief Returns the selected flow control.
356 	\return The flow control for the current open port.
357 */
358 uint32
FlowControl(void)359 BSerialPort::FlowControl(void)
360 {
361 	return fFlow;
362 }
363 
364 
365 /* Set the DTR */
366 status_t
SetDTR(bool asserted)367 BSerialPort::SetDTR(bool asserted)
368 {
369 	status_t status = ioctl(ffd, TCSETDTR, &asserted, sizeof(asserted));
370 
371 	return (status >= 0) ? status : errno;
372 }
373 
374 
375 /* Set the RTS status */
376 status_t
SetRTS(bool asserted)377 BSerialPort::SetRTS(bool asserted)
378 {
379 	status_t status = ioctl(ffd, TCSETRTS, &asserted, sizeof(asserted));
380 
381 	return (status >= 0) ? status : errno;
382 }
383 
384 
385 /*! \brief See how many chars are queued on the serial port.
386 	\param numChars A pointer to an int32 where you want
387 		that value stored.
388 	\return ?
389 */
390 status_t
NumCharsAvailable(int32 * numChars)391 BSerialPort::NumCharsAvailable(int32 *numChars)
392 {
393 	//No help from the BeBook...
394 	if (ffd < 0)
395 		return B_NO_INIT;
396 
397 	// TODO: Implement ?
398 	if (numChars)
399 		*numChars = 0;
400 	return B_OK;
401 }
402 
403 
404 /*! \brief See if the Clear to Send pin is asserted.
405 	\return true if CTS is asserted, false if not.
406 */
407 bool
IsCTS(void)408 BSerialPort::IsCTS(void)
409 {
410 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
411 
412 	if (bits & TCGB_CTS)
413 		return true;
414 
415 	return false;
416 }
417 
418 
419 /*! \brief See if the Data Set Ready pin is asserted.
420 	\return true if DSR is asserted, false if not.
421 */
422 bool
IsDSR(void)423 BSerialPort::IsDSR(void)
424 {
425 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
426 
427 	if (bits & TCGB_DSR)
428 		return true;
429 
430 	return false;
431 }
432 
433 
434 /*! \brief See if the Ring Indicator pin is asserted.
435 	\return true if RI is asserted, false if not.
436 */
437 bool
IsRI(void)438 BSerialPort::IsRI(void)
439 {
440 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
441 
442 	if (bits & TCGB_RI)
443 		return true;
444 
445 	return false;
446 }
447 
448 
449 /*! \brief See if the Data Carrier Detect pin is asserted.
450 	\return true if DCD is asserted, false if not.
451 */
452 bool
IsDCD(void)453 BSerialPort::IsDCD(void)
454 {
455 	unsigned int bits = ioctl(ffd, TCGETBITS, 0);
456 
457 	if (bits & TCGB_DCD)
458 		return true;
459 
460 	return false;
461 }
462 
463 
464 /*! \brief Wait until there's something to read from the serial port.
465 	If no data is ready, it will always block, ignoring the
466 	value of SetBlocking(); however, it respects the timeout
467 	set by SetTimeout().
468 	\return The number of bytes available to be read.
469 */
470 ssize_t
WaitForInput(void)471 BSerialPort::WaitForInput(void)
472 {
473 	object_wait_info info[1];
474 	info[0].type = B_OBJECT_TYPE_FD;
475 	info[0].object = ffd;
476 	info[0].events = B_EVENT_READ | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
477 	status_t status = wait_for_objects_etc(info, 1, B_RELATIVE_TIMEOUT, fTimeout);
478 	if (status < 0)
479 		return status;
480 
481 	int size;
482 	if (ioctl(ffd, FIONREAD, &size, sizeof(size)) < 0)
483 		return errno;
484 	return size;
485 }
486 
487 
488 /*! \brief Count the number of available Serial Ports.
489 	\return An integer which represents the number of available
490 		serial ports.
491 */
492 int32
CountDevices()493 BSerialPort::CountDevices()
494 {
495 	int32 count = 0;
496 
497 	// Refresh devices list
498 	_ScanDevices();
499 
500 	if (fDevices != NULL)
501 		count = fDevices->CountItems();
502 
503 	return count;
504 }
505 
506 
507 /*! \brief Get the device name for the given device.
508 	\param n Number of the device you want to know the name of.
509 	\param name The buffer where you want to store the name.
510 	\param bufSize The size of the buffer.
511 	\return
512 	- \c B_ERROR if something goes wrong
513 	- \c B_OK if all goes fine.
514 */
515 status_t
GetDeviceName(int32 n,char * name,size_t bufSize)516 BSerialPort::GetDeviceName(int32 n, char *name, size_t bufSize)
517 {
518 	status_t result = B_ERROR;
519 	const char *dev = NULL;
520 
521 	if (fDevices != NULL)
522 		dev = static_cast<char*>(fDevices->ItemAt(n));
523 
524 	if (dev != NULL && name != NULL) {
525 		strncpy(name, dev, bufSize);
526 		name[bufSize - 1] = '\0';
527 		result = B_OK;
528 	}
529 	return result;
530 }
531 
532 
533 /* Private or Reserved */
534 
535 /*! \brief Build a list of available serial ports.
536 	Query the serial driver about the available devices,
537 	and build a list of them.
538 */
539 void
_ScanDevices()540 BSerialPort::_ScanDevices()
541 {
542 	// First, we empty the list
543 	if (fDevices != NULL) {
544 		for (int32 count = fDevices->CountItems() - 1; count >= 0; count--)
545 			free(fDevices->RemoveItem(count));
546 
547 		// Add devices to the list
548 		scan_directory(SERIAL_DIR, fDevices);
549 	}
550 }
551 
552 
553 /*! \brief Send the selected options to the serial driver.
554 	\return
555 	- \c B_OK if all goes fine,
556 	- an error code if something goes wrong.
557 */
558 int
_DriverControl()559 BSerialPort::_DriverControl()
560 {
561 	struct termios options;
562 	int err;
563 
564 	if (ffd < 0)
565 		return B_NO_INIT;
566 
567 	//Load the current settings
568 	err = tcgetattr(ffd, &options);
569 	if (err < 0)
570 		return errno;
571 
572 	// Reset all flags
573 	options.c_iflag &= ~(IXON | IXOFF | IXANY | INPCK);
574 	options.c_cflag &= ~(CRTSCTS | CSIZE | CSTOPB | PARODD | PARENB);
575 	options.c_lflag &= ~(ECHO | ECHONL | ISIG | ICANON);
576 
577 	// Local line
578 	options.c_cflag |= CLOCAL;
579 
580 	//Set the flags to the wanted values
581 	if (fFlow & B_HARDWARE_CONTROL)
582 		options.c_cflag |= CRTSCTS;
583 
584 	if (fFlow & B_SOFTWARE_CONTROL)
585 		options.c_iflag |= (IXON | IXOFF);
586 
587 	if (fStopBits & B_STOP_BITS_2)
588 		options.c_cflag |= CSTOPB; // Set 2 stop bits
589 
590 	if (fDataBits & B_DATA_BITS_8)
591 		options.c_cflag |= CS8; // Set 8 data bits
592 
593 	//Ok, set the parity now
594 	if (fParityMode != B_NO_PARITY) {
595 		options.c_cflag |= PARENB; //Enable parity
596 		if (fParityMode == B_ODD_PARITY)
597 			options.c_cflag |= PARODD; //Select odd parity
598 	}
599 
600 	//Set the baud rate
601 	cfsetispeed(&options, fBaudRate);
602 	cfsetospeed(&options, fBaudRate);
603 
604 	//Set the timeout
605 	options.c_cc[VTIME] = 0;
606 	options.c_cc[VMIN] = 0;
607 	if (fBlocking) {
608 		if (fTimeout == B_INFINITE_TIMEOUT) {
609 			options.c_cc[VMIN] = 1;
610 		} else if (fTimeout != 0) {
611 			int timeout = fTimeout / 100000;
612 			options.c_cc[VTIME] = (timeout == 0) ? 1 : timeout;
613 		}
614 	}
615 
616 	//Ok, finished. Now tell the driver what we decided
617 	err = tcsetattr(ffd, TCSANOW, &options);
618 
619 	return (err >= 0) ? err : errno;
620 }
621 
622 
623 /* These functions are here to maintain Binary Compatibility */
_ReservedSerialPort1()624 void BSerialPort::_ReservedSerialPort1() {}
_ReservedSerialPort2()625 void BSerialPort::_ReservedSerialPort2() {}
_ReservedSerialPort3()626 void BSerialPort::_ReservedSerialPort3() {}
_ReservedSerialPort4()627 void BSerialPort::_ReservedSerialPort4() {}
628