blob: dab746be47bb072d60933de752b7947e680b2ce1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <inttypes.h>
#include <termios.h>
#include "os/mynewt.h"
#include "native_uart_cfg_priv.h"
/* uint64 is used here to accommodate speed_t, whatever that is. */
static const uint64_t uart_baud_table[][2] = {
#ifdef B50
{ 50, B50 },
#endif
#ifdef B75
{ 75, B75 },
#endif
#ifdef B110
{ 110, B110 },
#endif
#ifdef B134
{ 134, B134 },
#endif
#ifdef B150
{ 150, B150 },
#endif
#ifdef B200
{ 200, B200 },
#endif
#ifdef B300
{ 300, B300 },
#endif
#ifdef B600
{ 600, B600 },
#endif
#ifdef B1200
{ 1200, B1200 },
#endif
#ifdef B1800
{ 1800, B1800 },
#endif
#ifdef B2400
{ 2400, B2400 },
#endif
#ifdef B4800
{ 4800, B4800 },
#endif
#ifdef B9600
{ 9600, B9600 },
#endif
#ifdef B19200
{ 19200, B19200 },
#endif
#ifdef B38400
{ 38400, B38400 },
#endif
#ifdef B57600
{ 57600, B57600 },
#endif
#ifdef B115200
{ 115200, B115200 },
#endif
#ifdef B230400
{ 230400, B230400 },
#endif
#ifdef B460800
{ 460800, B460800 },
#endif
#ifdef B500000
{ 500000, B500000 },
#endif
#ifdef B576000
{ 576000, B576000 },
#endif
#ifdef B921600
{ 921600, B921600 },
#endif
#ifdef B1000000
{ 1000000, B1000000 },
#endif
#ifdef B1152000
{ 1152000, B1152000 },
#endif
#ifdef B1500000
{ 1500000, B1500000 },
#endif
#ifdef B2000000
{ 2000000, B2000000 },
#endif
#ifdef B2500000
{ 2500000, B2500000 },
#endif
#ifdef B3000000
{ 3000000, B3000000 },
#endif
#ifdef B3500000
{ 3500000, B3500000 },
#endif
#ifdef B3710000
{ 3710000, B3710000 },
#endif
#ifdef B4000000
{ 4000000, B4000000 },
#endif
};
#define UART_BAUD_TABLE_SZ (sizeof uart_baud_table / sizeof uart_baud_table[0])
/**
* Returns 0 on failure.
*/
speed_t
uart_baud_to_speed(int_least32_t baud)
{
int i;
for (i = 0; i < UART_BAUD_TABLE_SZ; i++) {
if (uart_baud_table[i][0] == baud) {
return uart_baud_table[i][1];
}
}
return 0;
}
/**
* Configures an external device terminal (/dev/cu.<...>).
*/
int
uart_dev_set_attr(int fd, int32_t baudrate, uint8_t databits,
uint8_t stopbits, enum hal_uart_parity parity,
enum hal_uart_flow_ctl flow_ctl)
{
struct termios tty;
speed_t speed;
int rc;
assert(fd >= 0);
memset(&tty, 0, sizeof(tty));
cfmakeraw(&tty);
speed = uart_baud_to_speed(baudrate);
if (speed == 0) {
fprintf(stderr, "invalid baud rate: %d\n", (int)baudrate);
assert(0);
}
tty.c_cflag |= (speed | CLOCAL | CREAD);
/* Set flow control. */
switch (flow_ctl) {
case HAL_UART_FLOW_CTL_NONE:
tty.c_cflag &= ~CRTSCTS;
break;
case HAL_UART_FLOW_CTL_RTS_CTS:
tty.c_cflag |= CRTSCTS;
break;
default:
fprintf(stderr, "invalid flow control setting: %d\n", flow_ctl);
return -1;
}
errno = 0;
rc = cfsetospeed(&tty, speed);
if (rc != 0) {
fprintf(stderr, "cfsetospeed failed; %d (%s) baudrate=%d\n",
errno, strerror(errno), (int)baudrate);
return -1;
}
errno = 0;
rc = cfsetispeed(&tty, speed);
if (rc != 0) {
fprintf(stderr, "cfsetispeed failed; %d (%s) baudrate=%d\n",
errno, strerror(errno), (int)baudrate);
return -1;
}
switch (databits) {
case 7:
tty.c_cflag |= CS7;
switch (parity) {
case HAL_UART_PARITY_ODD:
tty.c_cflag |= PARENB;
tty.c_cflag |= PARODD;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
break;
case HAL_UART_PARITY_EVEN:
tty.c_cflag |= PARENB;
tty.c_cflag &= ~PARODD;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
break;
default:
return SYS_EINVAL;
}
case 8:
if (parity != HAL_UART_PARITY_NONE) {
return SYS_EINVAL;
}
tty.c_cflag |= CS8;
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
break;
default:
return SYS_EINVAL;
}
rc = tcsetattr(fd, TCSANOW, &tty);
if (rc != 0) {
fprintf(stderr, "tcsetattr failed; %d (%s)\n", errno, strerror(errno));
return -1;
}
return 0;
}