uart.c revision 7d3978fad94b70b4cb0dba9231b30870022f8563
1/* 2 * Author: Thomas Ingleby <thomas.c.ingleby@intel.com> 3 * Contributions: Jon Trulson <jtrulson@ics.com> 4 * Brendan le Foll <brendan.le.foll@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 38static speed_t 39uint2speed(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 110static mraa_uart_context 111mraa_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 125mraa_uart_context 126mraa_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 int pos = plat->uart_dev[index].rx; 156 if (pos >= 0) { 157 if (plat->pins[pos].uart.mux_total > 0) { 158 if (mraa_setup_mux_mapped(plat->pins[pos].uart) != MRAA_SUCCESS) { 159 syslog(LOG_ERR, "uart: failed to setup muxes for RX pin"); 160 return NULL; 161 } 162 } 163 } 164 165 pos = plat->uart_dev[index].tx; 166 if (pos >= 0) { 167 if (plat->pins[pos].uart.mux_total > 0) { 168 if (mraa_setup_mux_mapped(plat->pins[pos].uart) != MRAA_SUCCESS) { 169 syslog(LOG_ERR, "uart: failed to setup muxes for TX pin"); 170 return NULL; 171 } 172 } 173 } 174 175 mraa_uart_context dev = mraa_uart_init_raw((char*)plat->uart_dev[index].device_path); 176 if (dev == NULL) { 177 return NULL; 178 } 179 dev->index = index; //Set the board Index. 180 181 if (IS_FUNC_DEFINED(dev, uart_init_post)) { 182 mraa_result_t ret = dev->advance_func->uart_init_post(dev); 183 if (ret != MRAA_SUCCESS) { 184 free(dev); 185 return NULL; 186 } 187 } 188 189 return dev; 190} 191 192mraa_uart_context 193mraa_uart_init_raw(const char* path) 194{ 195 mraa_uart_context dev = mraa_uart_init_internal(plat == NULL ? NULL : plat->adv_func); 196 if (dev == NULL) { 197 syslog(LOG_ERR, "uart: Failed to allocate memory for context"); 198 return NULL; 199 } 200 dev->path = path; 201 202 if (!dev->path) { 203 syslog(LOG_ERR, "uart: device path undefined, open failed"); 204 free(dev); 205 return NULL; 206 } 207 208 // now open the device 209 if ((dev->fd = open(dev->path, O_RDWR)) == -1) { 210 syslog(LOG_ERR, "uart: open() failed"); 211 free(dev); 212 return NULL; 213 } 214 215 // now setup the tty and the selected baud rate 216 struct termios termio; 217 218 // get current modes 219 if (tcgetattr(dev->fd, &termio)) { 220 syslog(LOG_ERR, "uart: tcgetattr() failed"); 221 close(dev->fd); 222 free(dev); 223 return NULL; 224 } 225 226 // setup for a 'raw' mode. 8N1, no echo or special character 227 // handling, such as flow control or line editing semantics. 228 // cfmakeraw is not POSIX! 229 cfmakeraw(&termio); 230 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 231 syslog(LOG_ERR, "uart: tcsetattr() failed after cfmakeraw()"); 232 close(dev->fd); 233 free(dev); 234 return NULL; 235 } 236 237 if (mraa_uart_set_baudrate(dev, 9600) != MRAA_SUCCESS) { 238 close(dev->fd); 239 free(dev); 240 return NULL; 241 } 242 243 return dev; 244} 245 246mraa_result_t 247mraa_uart_stop(mraa_uart_context dev) 248{ 249 if (!dev) { 250 syslog(LOG_ERR, "uart: stop: context is NULL"); 251 return MRAA_ERROR_INVALID_HANDLE; 252 } 253 254 // just close the device and reset our fd. 255 if (dev->fd >= 0) { 256 close(dev->fd); 257 } 258 259 free(dev); 260 261 return MRAA_SUCCESS; 262} 263 264mraa_result_t 265mraa_uart_flush(mraa_uart_context dev) 266{ 267 if (!dev) { 268 syslog(LOG_ERR, "uart: stop: context is NULL"); 269 return MRAA_ERROR_INVALID_HANDLE; 270 } 271 272 if (tcdrain(dev->fd) == -1) { 273 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 274 } 275 276 return MRAA_SUCCESS; 277} 278 279mraa_result_t 280mraa_uart_set_baudrate(mraa_uart_context dev, unsigned int baud) 281{ 282 if (!dev) { 283 syslog(LOG_ERR, "uart: stop: context is NULL"); 284 return MRAA_ERROR_INVALID_HANDLE; 285 } 286 287 struct termios termio; 288 if (tcgetattr(dev->fd, &termio)) { 289 syslog(LOG_ERR, "uart: tcgetattr() failed"); 290 return MRAA_ERROR_INVALID_HANDLE; 291 } 292 293 // set our baud rates 294 speed_t speed = uint2speed(baud); 295 cfsetispeed(&termio, speed); 296 cfsetospeed(&termio, speed); 297 298 // make it so 299 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 300 syslog(LOG_ERR, "uart: tcsetattr() failed"); 301 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 302 } 303 return MRAA_SUCCESS; 304} 305 306mraa_result_t 307mraa_uart_set_mode(mraa_uart_context dev, int bytesize, mraa_uart_parity_t parity, int stopbits) 308{ 309 if (!dev) { 310 syslog(LOG_ERR, "uart: stop: context is NULL"); 311 return MRAA_ERROR_INVALID_HANDLE; 312 } 313 314 struct termios termio; 315 if (tcgetattr(dev->fd, &termio)) { 316 syslog(LOG_ERR, "uart: tcgetattr() failed"); 317 return MRAA_ERROR_INVALID_HANDLE; 318 } 319 320 termio.c_cflag &= ~CSIZE; 321 switch (bytesize) { 322 case 8: 323 termio.c_cflag |= CS8; 324 break; 325 case 7: 326 termio.c_cflag |= CS7; 327 break; 328 case 6: 329 termio.c_cflag |= CS6; 330 break; 331 case 5: 332 termio.c_cflag |= CS5; 333 break; 334 default: 335 termio.c_cflag |= CS8; 336 break; 337 } 338 339 // POSIX & linux doesn't support 1.5 and I've got bigger fish to fry 340 switch (stopbits) { 341 case 1: 342 termio.c_cflag &= ~CSTOPB; 343 break; 344 case 2: 345 termio.c_cflag |= CSTOPB; 346 default: 347 break; 348 } 349 350 switch (parity) { 351 case MRAA_UART_PARITY_NONE: 352 termio.c_cflag &= ~(PARENB | PARODD); 353 break; 354 case MRAA_UART_PARITY_EVEN: 355 termio.c_cflag |= PARENB; 356 termio.c_cflag &= ~PARODD; 357 break; 358 case MRAA_UART_PARITY_ODD: 359 termio.c_cflag |= PARENB | PARODD; 360 break; 361 case MRAA_UART_PARITY_MARK: // not POSIX 362 termio.c_cflag |= PARENB | CMSPAR | PARODD; 363 break; 364 case MRAA_UART_PARITY_SPACE: // not POSIX 365 termio.c_cflag |= PARENB | CMSPAR; 366 termio.c_cflag &= ~PARODD; 367 break; 368 } 369 370 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 371 syslog(LOG_ERR, "uart: tcsetattr() failed"); 372 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 373 } 374 375 return MRAA_SUCCESS; 376} 377 378mraa_result_t 379mraa_uart_set_flowcontrol(mraa_uart_context dev, mraa_boolean_t xonxoff, mraa_boolean_t rtscts) 380{ 381 if (!dev) { 382 syslog(LOG_ERR, "uart: stop: context is NULL"); 383 return MRAA_ERROR_INVALID_HANDLE; 384 } 385 386 // hardware flow control 387 int action = TCIOFF; 388 if (xonxoff) { 389 action = TCION; 390 } 391 if (tcflow(dev->fd, action)) { 392 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 393 } 394 395 // rtscts 396 struct termios termio; 397 398 // get current modes 399 if (tcgetattr(dev->fd, &termio)) { 400 syslog(LOG_ERR, "uart: tcgetattr() failed"); 401 return MRAA_ERROR_INVALID_HANDLE; 402 } 403 404 if (rtscts) { 405 termio.c_cflag |= CRTSCTS; 406 } else { 407 termio.c_cflag &= ~CRTSCTS; 408 } 409 410 if (tcsetattr(dev->fd, TCSAFLUSH, &termio) < 0) { 411 syslog(LOG_ERR, "uart: tcsetattr() failed"); 412 return MRAA_ERROR_FEATURE_NOT_SUPPORTED; 413 } 414 415 return MRAA_SUCCESS; 416} 417 418mraa_result_t 419mraa_uart_set_timeout(mraa_uart_context dev, int read, int write, int interchar) 420{ 421 if (!dev) { 422 syslog(LOG_ERR, "uart: stop: context is NULL"); 423 return MRAA_ERROR_INVALID_HANDLE; 424 } 425 426 return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; 427} 428 429const char* 430mraa_uart_get_dev_path(mraa_uart_context dev) 431{ 432 if (!dev) { 433 syslog(LOG_ERR, "uart: get_device_path failed, context is NULL"); 434 return NULL; 435 } 436 if (dev->path == NULL) { 437 syslog(LOG_ERR, "uart: device path undefined"); 438 return NULL; 439 } 440 441 return dev->path; 442} 443 444int 445mraa_uart_read(mraa_uart_context dev, char* buf, size_t len) 446{ 447 if (!dev) { 448 syslog(LOG_ERR, "uart: read: context is NULL"); 449 return MRAA_ERROR_INVALID_HANDLE; 450 } 451 452 if (dev->fd < 0) { 453 syslog(LOG_ERR, "uart: port is not open"); 454 return MRAA_ERROR_INVALID_RESOURCE; 455 } 456 457 return read(dev->fd, buf, len); 458} 459 460int 461mraa_uart_write(mraa_uart_context dev, const char* buf, size_t len) 462{ 463 if (!dev) { 464 syslog(LOG_ERR, "uart: write: context is NULL"); 465 return MRAA_ERROR_INVALID_HANDLE; 466 } 467 468 if (dev->fd < 0) { 469 syslog(LOG_ERR, "uart: port is not open"); 470 return MRAA_ERROR_INVALID_RESOURCE; 471 } 472 473 return write(dev->fd, buf, len); 474} 475 476mraa_boolean_t 477mraa_uart_data_available(mraa_uart_context dev, unsigned int millis) 478{ 479 if (!dev) { 480 syslog(LOG_ERR, "uart: data_available: write context is NULL"); 481 return 0; 482 } 483 484 if (dev->fd < 0) { 485 syslog(LOG_ERR, "uart: port is not open"); 486 return 0; 487 } 488 489 struct timeval timeout; 490 491 if (millis == 0) { 492 // no waiting 493 timeout.tv_sec = 0; 494 timeout.tv_usec = 0; 495 } else { 496 timeout.tv_sec = millis / 1000; 497 timeout.tv_usec = (millis % 1000) * 1000; 498 } 499 500 fd_set readfds; 501 502 FD_ZERO(&readfds); 503 FD_SET(dev->fd, &readfds); 504 505 if (select(dev->fd + 1, &readfds, NULL, NULL, &timeout) > 0) { 506 return 1; // data is ready 507 } else { 508 return 0; 509 } 510} 511 512 513