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
29static int32
30scan_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*/
59BSerialPort::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*/
78BSerialPort::~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*/
98status_t
99BSerialPort::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*/
138void
139BSerialPort::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*/
152ssize_t
153BSerialPort::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*/
165ssize_t
166BSerialPort::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*/
177void
178BSerialPort::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*/
192status_t
193BSerialPort::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*/
233status_t
234BSerialPort::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
246data_rate
247BSerialPort::DataRate(void)
248{
249	return fBaudRate;
250}
251
252
253/*! \brief Set the data bits (7 or 8)
254*/
255void
256BSerialPort::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*/
266data_bits
267BSerialPort::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*/
279void
280BSerialPort::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*/
290stop_bits
291BSerialPort::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*/
304void
305BSerialPort::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*/
315parity_mode
316BSerialPort::ParityMode(void)
317{
318	return fParityMode;
319}
320
321
322/*! \brief Clear the input buffer.
323*/
324void
325BSerialPort::ClearInput(void)
326{
327	tcflush(ffd, TCIFLUSH);
328}
329
330
331/*! \brief Clear the output buffer.
332*/
333void
334BSerialPort::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*/
347void
348BSerialPort::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*/
358uint32
359BSerialPort::FlowControl(void)
360{
361	return fFlow;
362}
363
364
365/* Set the DTR */
366status_t
367BSerialPort::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 */
376status_t
377BSerialPort::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*/
390status_t
391BSerialPort::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*/
407bool
408BSerialPort::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*/
422bool
423BSerialPort::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*/
437bool
438BSerialPort::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*/
452bool
453BSerialPort::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*/
470ssize_t
471BSerialPort::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*/
492int32
493BSerialPort::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*/
515status_t
516BSerialPort::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*/
539void
540BSerialPort::_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*/
558int
559BSerialPort::_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 */
624void BSerialPort::_ReservedSerialPort1() {}
625void BSerialPort::_ReservedSerialPort2() {}
626void BSerialPort::_ReservedSerialPort3() {}
627void BSerialPort::_ReservedSerialPort4() {}
628