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