1 /* 2 * Author: Thomas Ingleby <thomas.c.ingleby (at) intel.com> 3 * Contributions: Jon Trulson <jtrulson (at) ics.com> 4 * Brendan le Foll <brendan.le.foll (at) intel.com> 5 * Copyright (c) 2014 - 2015 Intel Corporation. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 #include <stdlib.h> 28 #include <sys/stat.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <termios.h> 32 33 #include "uart.h" 34 #include "mraa_internal.h" 35 36 // This function takes an unsigned int and converts it to a B* speed_t 37 // that can be used with linux/posix termios 38 static speed_t 39 uint2speed(unsigned int speed) 40 { 41 switch (speed) { 42 case 0: 43 return B0; // hangup, not too useful otherwise 44 case 50: 45 return B50; 46 case 75: 47 return B75; 48 case 110: 49 return B110; 50 case 150: 51 return B150; 52 case 200: 53 return B200; 54 case 300: 55 return B300; 56 case 600: 57 return B600; 58 case 1200: 59 return B1200; 60 case 1800: 61 return B1800; 62 case 2400: 63 return B2400; 64 case 4800: 65 return B4800; 66 case 9600: 67 return B9600; 68 case 19200: 69 return B19200; 70 case 38400: 71 return B38400; 72 case 57600: 73 return B57600; 74 case 115200: 75 return B115200; 76 case 230400: 77 return B230400; 78 case 460800: 79 return B460800; 80 case 500000: 81 return B500000; 82 case 576000: 83 return B576000; 84 case 921600: 85 return B921600; 86 case 1000000: 87 return B1000000; 88 case 1152000: 89 return B1152000; 90 case 1500000: 91 return B1500000; 92 case 2000000: 93 return B2000000; 94 case 2500000: 95 return B2500000; 96 case 3000000: 97 return B3000000; 98 case 3500000: 99 return B3500000; 100 case 4000000: 101 return B4000000; 102 default: 103 // if we are here, then an unsupported baudrate was selected. 104 // Report it via syslog and return B9600, a common default. 105 syslog(LOG_ERR, "uart: unsupported baud rate, defaulting to 9600."); 106 return B9600; 107 } 108 } 109 110 static mraa_uart_context 111 mraa_uart_init_internal(mraa_adv_func_t* func_table) 112 { 113 mraa_uart_context dev = (mraa_uart_context) calloc(1, sizeof(struct _uart)); 114 if (dev == NULL) { 115 syslog(LOG_CRIT, "uart: Failed to allocate memory for context"); 116 return NULL; 117 } 118 dev->index = -1; 119 dev->fd = -1; 120 dev->advance_func = func_table; 121 122 return dev; 123 } 124 125 mraa_uart_context 126 mraa_uart_init(int index) 127 { 128 if (plat == NULL) { 129 syslog(LOG_ERR, "uart: platform not initialised"); 130 return NULL; 131 } 132 133 if (mraa_is_sub_platform_id(index)) { 134 syslog(LOG_NOTICE, "uart: Using sub platform is not supported"); 135 return NULL; 136 } 137 138 if (plat->adv_func->uart_init_pre != NULL) { 139 if (plat->adv_func->uart_init_pre(index) != MRAA_SUCCESS) { 140 syslog(LOG_ERR, "uart: failure in pre-init platform hook"); 141 return NULL; 142 } 143 } 144 145 if (plat->uart_dev_count == 0) { 146 syslog(LOG_ERR, "uart: platform has no UARTs defined"); 147 return NULL; 148 } 149 150 if (plat->uart_dev_count <= index) { 151 syslog(LOG_ERR, "uart: platform has only %i", plat->uart_dev_count); 152 return NULL; 153 } 154 155 if (!plat->no_bus_mux) { 156 int pos = plat->uart_dev[index].rx; 157 if (pos >= 0) { 158 if (plat->pins[pos].uart.mux_total > 0) { 159 if (mraa_setup_mux_mapped(plat->pins[pos].uart) != MRAA_SUCCESS) { 160 syslog(LOG_ERR, "uart: failed to setup muxes for RX pin"); 161 return NULL; 162 } 163 } 164 } 165 166 pos = plat->uart_dev[index].tx; 167 if (pos >= 0) { 168 if (plat->pins[pos].uart.mux_total > 0) { 169 if (mraa_setup_mux_mapped(plat->pins[pos].uart) != MRAA_SUCCESS) { 170 syslog(LOG_ERR, "uart: failed to setup muxes for TX pin"); 171 return NULL; 172 } 173 } 174 } 175 } 176 177 mraa_uart_context dev = mraa_uart_init_raw((char*)plat->uart_dev[index].device_path); 178 if (dev == NULL) { 179 return NULL; 180 } 181 dev->index = index; //Set the board Index. 182 183 if (IS_FUNC_DEFINED(dev, uart_init_post)) { 184 mraa_result_t ret = dev->advance_func->uart_init_post(dev); 185 if (ret != MRAA_SUCCESS) { 186 free(dev); 187 return NULL; 188 } 189 } 190 191 return dev; 192 } 193 194 mraa_uart_context 195 mraa_uart_init_raw(const char* path) 196 { 197 mraa_uart_context dev = mraa_uart_init_internal(plat == NULL ? NULL : plat->adv_func); 198 if (dev == NULL) { 199 syslog(LOG_ERR, "uart: Failed to allocate memory for context"); 200 return NULL; 201 } 202 dev->path = path; 203 204 if (!dev->path) { 205 syslog(LOG_ERR, "uart: device path undefined, open failed"); 206 free(dev); 207 return NULL; 208 } 209 210 // now open the device 211 if ((dev->fd = open(dev->path, O_RDWR)) == -1) { 212 syslog(LOG_ERR, "uart: open() failed"); 213 free(dev); 214 return NULL; 215 } 216 217 // now setup the tty and the selected baud rate 218 struct termios termio; 219 220 // get current modes 221 if (tcgetattr(dev->fd, &termio)) { 222 syslog(LOG_ERR, "uart: tcgetattr() failed"); 223 close(dev->fd); 224 free(dev); 225 return NULL; 226 } 227 228 // setup for a 'raw' mode. 8N1, no echo or special character 229 // handling, such as flow control or line editing semantics. 230 // cfmakeraw is not POSIX! 231 cfmakeraw(&termio); 232 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 233 syslog(LOG_ERR, "uart: tcsetattr() failed after cfmakeraw()"); 234 close(dev->fd); 235 free(dev); 236 return NULL; 237 } 238 239 if (mraa_uart_set_baudrate(dev, 9600) != MRAA_SUCCESS) { 240 close(dev->fd); 241 free(dev); 242 return NULL; 243 } 244 245 return dev; 246 } 247 248 mraa_result_t 249 mraa_uart_stop(mraa_uart_context dev) 250 { 251 if (!dev) { 252 syslog(LOG_ERR, "uart: stop: context is NULL"); 253 return MRAA_ERROR_INVALID_HANDLE; 254 } 255 256 // just close the device and reset our fd. 257 if (dev->fd >= 0) { 258 close(dev->fd); 259 } 260 261 free(dev); 262 263 return MRAA_SUCCESS; 264 } 265 266 mraa_result_t 267 mraa_uart_flush(mraa_uart_context dev) 268 { 269 if (!dev) { 270 syslog(LOG_ERR, "uart: stop: context is NULL"); 271 return MRAA_ERROR_INVALID_HANDLE; 272 } 273 274 if (tcdrain(dev->fd) == -1) { 275 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 276 } 277 278 return MRAA_SUCCESS; 279 } 280 281 mraa_result_t 282 mraa_uart_set_baudrate(mraa_uart_context dev, unsigned int baud) 283 { 284 if (!dev) { 285 syslog(LOG_ERR, "uart: stop: context is NULL"); 286 return MRAA_ERROR_INVALID_HANDLE; 287 } 288 289 struct termios termio; 290 if (tcgetattr(dev->fd, &termio)) { 291 syslog(LOG_ERR, "uart: tcgetattr() failed"); 292 return MRAA_ERROR_INVALID_HANDLE; 293 } 294 295 // set our baud rates 296 speed_t speed = uint2speed(baud); 297 cfsetispeed(&termio, speed); 298 cfsetospeed(&termio, speed); 299 300 // make it so 301 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 302 syslog(LOG_ERR, "uart: tcsetattr() failed"); 303 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 304 } 305 return MRAA_SUCCESS; 306 } 307 308 mraa_result_t 309 mraa_uart_set_mode(mraa_uart_context dev, int bytesize, mraa_uart_parity_t parity, int stopbits) 310 { 311 if (!dev) { 312 syslog(LOG_ERR, "uart: stop: context is NULL"); 313 return MRAA_ERROR_INVALID_HANDLE; 314 } 315 316 struct termios termio; 317 if (tcgetattr(dev->fd, &termio)) { 318 syslog(LOG_ERR, "uart: tcgetattr() failed"); 319 return MRAA_ERROR_INVALID_HANDLE; 320 } 321 322 termio.c_cflag &= ~CSIZE; 323 switch (bytesize) { 324 case 8: 325 termio.c_cflag |= CS8; 326 break; 327 case 7: 328 termio.c_cflag |= CS7; 329 break; 330 case 6: 331 termio.c_cflag |= CS6; 332 break; 333 case 5: 334 termio.c_cflag |= CS5; 335 break; 336 default: 337 termio.c_cflag |= CS8; 338 break; 339 } 340 341 // POSIX & linux doesn't support 1.5 and I've got bigger fish to fry 342 switch (stopbits) { 343 case 1: 344 termio.c_cflag &= ~CSTOPB; 345 break; 346 case 2: 347 termio.c_cflag |= CSTOPB; 348 default: 349 break; 350 } 351 352 switch (parity) { 353 case MRAA_UART_PARITY_NONE: 354 termio.c_cflag &= ~(PARENB | PARODD); 355 break; 356 case MRAA_UART_PARITY_EVEN: 357 termio.c_cflag |= PARENB; 358 termio.c_cflag &= ~PARODD; 359 break; 360 case MRAA_UART_PARITY_ODD: 361 termio.c_cflag |= PARENB | PARODD; 362 break; 363 case MRAA_UART_PARITY_MARK: // not POSIX 364 termio.c_cflag |= PARENB | CMSPAR | PARODD; 365 break; 366 case MRAA_UART_PARITY_SPACE: // not POSIX 367 termio.c_cflag |= PARENB | CMSPAR; 368 termio.c_cflag &= ~PARODD; 369 break; 370 } 371 372 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 373 syslog(LOG_ERR, "uart: tcsetattr() failed"); 374 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 375 } 376 377 return MRAA_SUCCESS; 378 } 379 380 mraa_result_t 381 mraa_uart_set_flowcontrol(mraa_uart_context dev, mraa_boolean_t xonxoff, mraa_boolean_t rtscts) 382 { 383 if (!dev) { 384 syslog(LOG_ERR, "uart: stop: context is NULL"); 385 return MRAA_ERROR_INVALID_HANDLE; 386 } 387 388 // hardware flow control 389 int action = TCIOFF; 390 if (xonxoff) { 391 action = TCION; 392 } 393 if (tcflow(dev->fd, action)) { 394 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 395 } 396 397 // rtscts 398 struct termios termio; 399 400 // get current modes 401 if (tcgetattr(dev->fd, &termio)) { 402 syslog(LOG_ERR, "uart: tcgetattr() failed"); 403 return MRAA_ERROR_INVALID_HANDLE; 404 } 405 406 if (rtscts) { 407 termio.c_cflag |= CRTSCTS; 408 } else { 409 termio.c_cflag &= ~CRTSCTS; 410 } 411 412 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 413 syslog(LOG_ERR, "uart: tcsetattr() failed"); 414 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 415 } 416 417 return MRAA_SUCCESS; 418 } 419 420 mraa_result_t 421 mraa_uart_set_timeout(mraa_uart_context dev, int read, int write, int interchar) 422 { 423 if (!dev) { 424 syslog(LOG_ERR, "uart: stop: context is NULL"); 425 return MRAA_ERROR_INVALID_HANDLE; 426 } 427 428 struct termios termio; 429 // get current modes 430 if (tcgetattr(dev->fd, &termio)) { 431 syslog(LOG_ERR, "uart: tcgetattr() failed"); 432 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 433 } 434 if (read > 0) { 435 read = read / 100; 436 if (read == 0) 437 read = 1; 438 } 439 termio.c_lflag &= ~ICANON; /* Set non-canonical mode */ 440 termio.c_cc[VTIME] = read; /* Set timeout in tenth seconds */ 441 if (tcsetattr(dev->fd, TCSANOW, &termio) < 0) { 442 syslog(LOG_ERR, "uart: tcsetattr() failed"); 443 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 444 } 445 446 return MRAA_SUCCESS; 447 } 448 449 const char* 450 mraa_uart_get_dev_path(mraa_uart_context dev) 451 { 452 if (!dev) { 453 syslog(LOG_ERR, "uart: get_device_path failed, context is NULL"); 454 return NULL; 455 } 456 if (dev->path == NULL) { 457 syslog(LOG_ERR, "uart: device path undefined"); 458 return NULL; 459 } 460 461 return dev->path; 462 } 463 464 int 465 mraa_uart_read(mraa_uart_context dev, char* buf, size_t len) 466 { 467 if (!dev) { 468 syslog(LOG_ERR, "uart: read: context is NULL"); 469 return MRAA_ERROR_INVALID_HANDLE; 470 } 471 472 if (dev->fd < 0) { 473 syslog(LOG_ERR, "uart: port is not open"); 474 return MRAA_ERROR_INVALID_RESOURCE; 475 } 476 477 return read(dev->fd, buf, len); 478 } 479 480 int 481 mraa_uart_write(mraa_uart_context dev, const char* buf, size_t len) 482 { 483 if (!dev) { 484 syslog(LOG_ERR, "uart: write: context is NULL"); 485 return MRAA_ERROR_INVALID_HANDLE; 486 } 487 488 if (dev->fd < 0) { 489 syslog(LOG_ERR, "uart: port is not open"); 490 return MRAA_ERROR_INVALID_RESOURCE; 491 } 492 493 return write(dev->fd, buf, len); 494 } 495 496 mraa_boolean_t 497 mraa_uart_data_available(mraa_uart_context dev, unsigned int millis) 498 { 499 if (!dev) { 500 syslog(LOG_ERR, "uart: data_available: write context is NULL"); 501 return 0; 502 } 503 504 if (dev->fd < 0) { 505 syslog(LOG_ERR, "uart: port is not open"); 506 return 0; 507 } 508 509 struct timeval timeout; 510 511 if (millis == 0) { 512 // no waiting 513 timeout.tv_sec = 0; 514 timeout.tv_usec = 0; 515 } else { 516 timeout.tv_sec = millis / 1000; 517 timeout.tv_usec = (millis % 1000) * 1000; 518 } 519 520 fd_set readfds; 521 522 FD_ZERO(&readfds); 523 FD_SET(dev->fd, &readfds); 524 525 if (select(dev->fd + 1, &readfds, NULL, NULL, &timeout) > 0) { 526 return 1; // data is ready 527 } else { 528 return 0; 529 } 530 } 531 532 533