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