ser_posix.c
Go to the documentation of this file.
00001
00040 #include "cfg/cfg_ser.h"
00041
00042 #include <cfg/debug.h>
00043 #include <cfg/compiler.h>
00044
00045 #include <drv/ser.h>
00046 #include <drv/ser_p.h>
00047 #include <drv/timer.h>
00048 #include <cpu/power.h>
00049
00050 #include <struct/fifobuf.h>
00051
00052 #include <sys/types.h>
00053 #include <sys/stat.h>
00054
00055 #include <fcntl.h> /* open() */
00056 #include <unistd.h> /* read(), write() */
00057 #include <stdlib.h>
00058 #include <termios.h>
00059
00060 static unsigned long BaudRate[] = {300,600,1200,1800,2400,4800,9600,19200,38400,57600,115200};
00061 static unsigned long BaudSetting[] = {B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400,B57600,B115200};
00062
00063
00064 /* From the high-level serial driver */
00065 extern struct Serial ser_handles[SER_CNT];
00066
00067 /* TX and RX buffers */
00068 static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
00069 static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
00070 static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
00071 static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
00072 static unsigned char uart2_txbuffer[CONFIG_UART2_TXBUFSIZE];
00073 static unsigned char uart2_rxbuffer[CONFIG_UART2_RXBUFSIZE];
00074
00075
00076 //Change these to map to the Serial port I use USB connected serial ports
00077 static char* devFile[SER_CNT] = {
00078         "/dev/ttyS0",
00079         "/dev/ttyUSB0",
00080         "/dev/ttyUSB1"
00081 };
00082
00083 //Make this big enough not criticul as it is running in emulated enviroment
00084 #define SERIAL_RX_STACK_SIZE (KERN_MINSTACKSIZE*3)
00085 PROC_DEFINE_STACK(serial_rx_stack0, SERIAL_RX_STACK_SIZE);
00086 PROC_DEFINE_STACK(serial_rx_stack1, SERIAL_RX_STACK_SIZE);
00087 PROC_DEFINE_STACK(serial_rx_stack2, SERIAL_RX_STACK_SIZE);
00088
00089 cpu_stack_t *serail_rx_stack[] = {serial_rx_stack0,serial_rx_stack1,serial_rx_stack2};
00090
00091
00095 struct EmulSerial
00096 {
00097     struct SerialHardware hw;
00098     struct Serial *ser;
00099     int fd;
00100     Process *ser_rcv_proc;
00101 };
00102
00103 static void poll_serial_rcv(void);
00104
00105 static struct termios oldtio,newtio;
00106
00107
00108 /*
00109  * Callbacks
00110  */
00111 static void uart_init(struct SerialHardware *_hw, struct Serial *ser)
00112 {
00113     struct EmulSerial *hw = (struct EmulSerial *)_hw;
00114     TRACEMSG("uart_init %d\n",ser->unit);
00115     hw->ser = ser;
00116     hw->fd = open(devFile[ser->unit], O_RDWR | O_NOCTTY | O_NDELAY);
00117     ASSERT(hw->fd);
00118     /* Make the file descriptor asynchronous (the manual page says only
00119        O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
00120     fcntl(hw->fd, F_SETFL, FNDELAY);
00121     tcflush(hw->fd, TCIFLUSH);
00122     tcgetattr(hw->fd,&oldtio); /* save current port settings */
00123     hw->ser_rcv_proc = proc_new(poll_serial_rcv,hw,SERIAL_RX_STACK_SIZE,serail_rx_stack[ser->unit]);
00124 }
00125
00126 static void uart_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
00127 {
00128     struct EmulSerial *hw = (struct EmulSerial *)_hw;
00129     tcsetattr(hw->fd,TCSANOW,&oldtio);
00130     close(hw->fd);
00131     hw->fd = -1;
00132 }
00133
00134 static void uart_txStart(struct SerialHardware * _hw)
00135 {
00136     struct EmulSerial *hw = (struct EmulSerial *)_hw;
00137
00138     while(!fifo_isempty(&hw->ser->txfifo))
00139     {
00140         char c = fifo_pop(&hw->ser->txfifo);
00141         write(hw->fd, &c, 1);
00142     }
00143 }
00144
00145 static bool uart_txSending(UNUSED_ARG(struct SerialHardware *, _hw))
00146 {
00147     return false;
00148 }
00149
00150
00151 static void uart_setBaudrate(struct SerialHardware * _hw, unsigned long rate)
00152 {
00153     int i;
00154     struct EmulSerial *hw = (struct EmulSerial *)_hw;
00155     TRACEMSG("rate=%d", rate);
00156     for (i=0;i<sizeof(BaudRate)/sizeof(unsigned long);i++)
00157         if (BaudRate[i]==rate)
00158             break;
00159     if (i<sizeof(BaudRate)/sizeof(unsigned long))
00160     {
00161         bzero(&newtio, sizeof(newtio));
00162         newtio.c_cflag = BaudSetting[i] | CS8 | CLOCAL | CREAD;
00163         newtio.c_iflag = IGNPAR ;
00164         newtio.c_oflag  &= ~OPOST;
00165
00166
00167         /* set input mode (non-canonical, no echo,...) */
00168         newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
00169
00170         tcsetattr(hw->fd,TCSANOW,&newtio);
00171     }
00172     else
00173     {
00174         TRACEMSG("invalid rate %d", rate);
00175         ASSERT(i<sizeof(BaudRate)/sizeof(unsigned long));
00176     }
00177
00178
00179 }
00180
00181 static void uart_setParity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
00182 {
00183     TRACEMSG("parity=%d", parity);
00184     // TODO
00185 }
00186
00187 // FIXME: move into compiler.h?  Ditch?
00188 #if COMPILER_C99
00189     #define C99INIT(name,val) .name = val
00190 #elif defined(__GNUC__)
00191     #define C99INIT(name,val) name: val
00192 #else
00193     #warning No designated initializers, double check your code
00194     #define C99INIT(name,val) (val)
00195 #endif
00196 
00197 /*
00198  * High-level interface data structures.
00199  */
00200 static const struct SerialHardwareVT uart_vtable =
00201 {
00202     C99INIT(init, uart_init),
00203     C99INIT(cleanup, uart_cleanup),
00204     C99INIT(setBaudrate, uart_setBaudrate),
00205     C99INIT(setParity, uart_setParity),
00206     C99INIT(txStart, uart_txStart),
00207     C99INIT(txSending, uart_txSending),
00208 };
00209
00210 static struct EmulSerial UARTDescs[SER_CNT] =
00211 {
00212     {
00213         C99INIT(hw, ) {
00214             C99INIT(table, &uart_vtable),
00215             C99INIT(txbuffer, uart0_txbuffer),
00216             C99INIT(rxbuffer, uart0_rxbuffer),
00217             C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
00218             C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
00219         },
00220         C99INIT(ser, NULL),
00221         C99INIT(fd, -1),
00222     },
00223     {
00224         C99INIT(hw, ) {
00225             C99INIT(table, &uart_vtable),
00226             C99INIT(txbuffer, uart1_txbuffer),
00227             C99INIT(rxbuffer, uart1_rxbuffer),
00228             C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
00229             C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
00230         },
00231         C99INIT(ser, NULL),
00232         C99INIT(fd, -1),
00233     },
00234     {
00235         C99INIT(hw, ) {
00236             C99INIT(table, &uart_vtable),
00237             C99INIT(txbuffer, uart2_txbuffer),
00238             C99INIT(rxbuffer, uart2_rxbuffer),
00239             C99INIT(txbuffer_size, sizeof(uart2_txbuffer)),
00240             C99INIT(rxbuffer_size, sizeof(uart2_rxbuffer)),
00241         },
00242         C99INIT(ser, NULL),
00243         C99INIT(fd, -1),
00244     },
00245 };
00246
00247 struct SerialHardware *ser_hw_getdesc(int unit)
00248 {
00249     ASSERT(unit < SER_CNT);
00250     return &UARTDescs[unit].hw;
00251 }
00252 static void poll_serial_rcv(void)
00253 {
00254     int res;
00255     int p;
00256     struct EmulSerial *hw = (struct EmulSerial *)proc_currentUserData();
00257     //TRACEMSG("poll_serial_rcv dev %d\n",hw->ser->unit);
00258     for(;;)
00259     {
00260         while(!fifo_isfull(&hw->ser->rxfifo))
00261         {
00262
00263             res = read(hw->fd,&p,1);
00264             //TRACEMSG("rcv %c res %d\n",(unsigned char)p,res);
00265             if (res>0)
00266             {
00267                 //TRACEMSG("rcv %02x ",p);
00268                 //printf("rcv %02x ", (unsigned char)p);
00269                 fifo_push_locked(&hw->ser->rxfifo, (unsigned char)p);
00270             }
00271             else if (res==0)
00272                 //Delay for 2 ticks if no characters are read
00273                 timer_delay(2);
00274             else
00275                 //exit if there is and error i.e. the port closes
00276                 goto exit_rcv;
00277         }
00278         cpu_relax();
00279     }
00280 exit_rcv:
00281     return;
00282 }