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