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
28static int32
29scan_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*/
58BSerialPort::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*/
77BSerialPort::~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*/
97status_t
98BSerialPort::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*/
137void
138BSerialPort::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*/
151ssize_t
152BSerialPort::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*/
164ssize_t
165BSerialPort::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*/
176void
177BSerialPort::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*/
191status_t
192BSerialPort::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*/
232status_t
233BSerialPort::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
245data_rate
246BSerialPort::DataRate(void)
247{
248	return fBaudRate;
249}
250
251
252/*! \brief Set the data bits (7 or 8)
253*/
254void
255BSerialPort::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*/
265data_bits
266BSerialPort::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*/
278void
279BSerialPort::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*/
289stop_bits
290BSerialPort::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*/
303void
304BSerialPort::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*/
314parity_mode
315BSerialPort::ParityMode(void)
316{
317	return fParityMode;
318}
319
320
321/*! \brief Clear the input buffer.
322*/
323void
324BSerialPort::ClearInput(void)
325{
326	tcflush(ffd, TCIFLUSH);
327}
328
329
330/*! \brief Clear the output buffer.
331*/
332void
333BSerialPort::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*/
346void
347BSerialPort::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*/
357uint32
358BSerialPort::FlowControl(void)
359{
360	return fFlow;
361}
362
363
364/* Set the DTR */
365status_t
366BSerialPort::SetDTR(bool asserted)
367{
368	status_t status = ioctl(ffd, TCSETDTR, &asserted);
369
370	return (status >= 0) ? status : errno;
371}
372
373
374/* Set the RTS status */
375status_t
376BSerialPort::SetRTS(bool asserted)
377{
378	status_t status = ioctl(ffd, TCSETRTS, &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*/
389status_t
390BSerialPort::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*/
406bool
407BSerialPort::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*/
421bool
422BSerialPort::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*/
436bool
437BSerialPort::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*/
451bool
452BSerialPort::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*/
469ssize_t
470BSerialPort::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*/
483int32
484BSerialPort::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*/
506status_t
507BSerialPort::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*/
530void
531BSerialPort::_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*/
549int
550BSerialPort::_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 | CBAUD | 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	options.c_cflag |= (fBaudRate & CBAUD);
593
594	//Set the timeout
595	options.c_cc[VTIME] = 0;
596	options.c_cc[VMIN] = 0;
597	if (fBlocking) {
598		if (fTimeout == B_INFINITE_TIMEOUT) {
599			options.c_cc[VMIN] = 1;
600		} else if (fTimeout != 0) {
601			int timeout = fTimeout / 100000;
602			options.c_cc[VTIME] = (timeout == 0) ? 1 : timeout;
603		}
604	}
605
606	//Ok, finished. Now tell the driver what we decided
607	err = tcsetattr(ffd, TCSANOW, &options);
608
609	return (err >= 0) ? err : errno;
610}
611
612
613/* These functions are here to maintain Binary Compatibility */
614void BSerialPort::_ReservedSerialPort1() {}
615void BSerialPort::_ReservedSerialPort2() {}
616void BSerialPort::_ReservedSerialPort3() {}
617void BSerialPort::_ReservedSerialPort4() {}
618