#include
#include
#include
#include "Arduino.h"
#include "wiring_private.h"
#include
#include "Serial.h"
HwSerial Serial;
void serialEvent() __attribute__((weak));
#define serialEvent_implemented
void serialEvent()
{
Serial.process_recv();
}
void serialEventRun(void)
{
#ifdef serialEvent_implemented
serialEvent();
#endif
}
static const char* serial_name = "/dev/ttyS1";
static inline char get_databit(byte config)
{
switch (config)
{
case SERIAL_5N1:
case SERIAL_5N2:
case SERIAL_5E1:
case SERIAL_5E2:
case SERIAL_5O1:
case SERIAL_5O2:
return CS5;
case SERIAL_6N1:
case SERIAL_6N2:
case SERIAL_6E1:
case SERIAL_6E2:
case SERIAL_6O1:
case SERIAL_6O2:
return CS6;
case SERIAL_7N1:
case SERIAL_7N2:
case SERIAL_7E1:
case SERIAL_7E2:
case SERIAL_7O1:
case SERIAL_7O2:
return CS7;
case SERIAL_8N1:
case SERIAL_8N2:
case SERIAL_8E1:
case SERIAL_8E2:
case SERIAL_8O1:
case SERIAL_8O2:
default:
return CS8;
}
}
static inline char get_stopbit(byte config)
{
switch (config)
{
case SERIAL_5N2:
case SERIAL_6N2:
case SERIAL_7N2:
case SERIAL_8N2:
case SERIAL_5E2:
case SERIAL_6E2:
case SERIAL_7E2:
case SERIAL_8E2:
case SERIAL_5O2:
case SERIAL_6O2:
case SERIAL_7O2:
case SERIAL_8O2:
return 2;
case SERIAL_5N1:
case SERIAL_6N1:
case SERIAL_7N1:
case SERIAL_8N1:
case SERIAL_5E1:
case SERIAL_6E1:
case SERIAL_7E1:
case SERIAL_8E1:
case SERIAL_5O1:
case SERIAL_6O1:
case SERIAL_7O1:
case SERIAL_8O1:
default:
return 1;
}
}
static inline char get_parity(byte config)
{
switch (config)
{
case SERIAL_5N1:
case SERIAL_5N2:
case SERIAL_6N1:
case SERIAL_6N2:
case SERIAL_7N1:
case SERIAL_7N2:
case SERIAL_8N1:
case SERIAL_8N2:
default:
return 'N';
case SERIAL_5O1:
case SERIAL_5O2:
case SERIAL_6O1:
case SERIAL_6O2:
case SERIAL_7O1:
case SERIAL_7O2:
case SERIAL_8O1:
case SERIAL_8O2:
return 'O';
case SERIAL_5E1:
case SERIAL_5E2:
case SERIAL_6E1:
case SERIAL_6E2:
case SERIAL_7E1:
case SERIAL_7E2:
case SERIAL_8E1:
case SERIAL_8E2:
return 'E';
}
}
static inline int get_valid_baud(unsigned long speed)
{
switch (speed)
{
case 300:
return B300;
case 600:
return B600;
case 1200:
return B1200;
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 14400:
return 0;
case 19200:
return B19200;
case 28800:
return 0;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
default:
return 0;
}
}
//static void signal_handler_IO ()
//{
// serial.process_recv();
// serial.process_send();
//}
//under construct
HwSerial::HwSerial()
{
_rx_buffer.head = _rx_buffer.tail = 0;
_tx_buffer.head = _tx_buffer.tail = 0;
_fd = -1;
}
HwSerial::~HwSerial()
{
end();
}
void HwSerial::begin(unsigned long baud, byte config)
{
int ret;
struct termios Opt;
//struct sigaction saio;
hw_pinMode(GPIO0, IO_UART_FUNC); //uart_rx
hw_pinMode(GPIO1, IO_UART_FUNC); //uart_tx
_fd = open(serial_name, O_RDWR| O_NOCTTY | O_NONBLOCK );
if (_fd < 0 )
{
pabort("can't open tty");
}
tcgetattr(_fd, &Opt);
tcflush(_fd, TCIOFLUSH);
int rate = get_valid_baud(baud);
if(rate > 0)
{
cfsetispeed(&Opt, rate);
cfsetospeed(&Opt, rate);
}
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= get_databit(config);
switch (get_parity(config))
{
case 'N':
default:
Opt.c_cflag &= ~PARENB;
Opt.c_iflag &= ~INPCK;
break;
case 'O':
Opt.c_cflag |= (PARODD | PARENB);
Opt.c_iflag |= INPCK;
break;
case 'E':
Opt.c_cflag |= PARENB;
Opt.c_cflag &= ~PARODD;
Opt.c_iflag |= INPCK;
break;
}
switch (get_stopbit(config))
{
case 1:
default:
Opt.c_cflag &= ~CSTOPB;
break;
case 2:
Opt.c_cflag |= CSTOPB;
break;
}
//Opt.c_cflag |= (CLOCAL | CREAD);
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//Opt.c_lflag &= ~(ECHO);
//Opt.c_cc[VTIME] = 0;
//Opt.c_cc[VMIN] = 0;
//saio.sa_handler = signal_handler_IO;
//sigemptyset (&(saio.sa_mask));
//saio.sa_flags = 0;
//saio.sa_restorer = NULL;
//sigaction (SIGIO, &saio, NULL);
//if (-1 == fcntl (_fd, F_SETFL, O_ASYNC))
// pabort("SETFL SIGIO");
//if (-1 == fcntl (_fd, F_SETOWN, getpid ()))
// pabort("F_SETOWN SIGIO");
ret = tcsetattr(_fd, TCSANOW, &Opt);
if (ret != 0)
pabort("can't set tty baut");
tcflush(_fd,TCIOFLUSH);
}
void HwSerial::end()
{
if(_fd)
close(_fd);
_fd = -1;
}
int HwSerial::available(void)
{
if(_rx_buffer.head <= _rx_buffer.tail)
return (_rx_buffer.tail - _rx_buffer.head);
else
return (SERIAL_BUFFER_SIZE - _rx_buffer.head + _rx_buffer.tail);
}
int HwSerial::peek(void)
{
if (_rx_buffer.head == _rx_buffer.tail) {
return -1;
} else {
return _rx_buffer.buffer[_rx_buffer.head];
}
}
int HwSerial::read(void)
{
if (_rx_buffer.head == _rx_buffer.tail) {
return -1;
} else {
unsigned char c = _rx_buffer.buffer[_rx_buffer.head];
_rx_buffer.head = (unsigned int)(_rx_buffer.head + 1) % SERIAL_BUFFER_SIZE;
return c;
}
}
void HwSerial::flush()
{
_rx_buffer.head = _rx_buffer.tail = 0;
_tx_buffer.head = _tx_buffer.tail = 0;
//::flush(_fd);
tcflush(_fd, TCIOFLUSH);
}
int HwSerial::write(byte c)
{
return (::write(_fd, &c ,1));
}
int HwSerial::process_recv()
{
int len = SERIAL_BUFFER_SIZE - available();
int retval = 0;
if ( _fd < 0 )
return -1;
if(len > 0)
{
//fd_set fs_read;
//struct timeval tv_timeout={_timeout/1000,(_timeout%1000)*1000};
//FD_ZERO (&fs_read);
//FD_SET (_fd, &fs_read);
//retval = select (_fd+1, &fs_read, NULL, NULL, &tv_timeout);
//if (retval>0)
{
//if(FD_ISSET(_fd,&fs_read))
{
char buf[SERIAL_BUFFER_SIZE];
retval = ::read(_fd, buf, len);
if(retval > 0)
{
if(retval >= SERIAL_BUFFER_SIZE -_rx_buffer.tail)
{
memcpy(_rx_buffer.buffer + _rx_buffer.tail, buf, SERIAL_BUFFER_SIZE - _rx_buffer.tail);
memcpy(_rx_buffer.buffer, buf + SERIAL_BUFFER_SIZE - _rx_buffer.tail, retval - (SERIAL_BUFFER_SIZE - _rx_buffer.tail));
_rx_buffer.tail = retval - ( SERIAL_BUFFER_SIZE - _rx_buffer.tail);
}
else
{
memcpy(_rx_buffer.buffer + _rx_buffer.tail, buf, retval);
_rx_buffer.tail += retval;
}
}
}
}
}
return retval;
}
HwSerial::operator bool() {
return true;
}