Contiki 2.6

uart.c

Go to the documentation of this file.
00001 /*
00002  *  Copyright (c) 2008  Swedish Institute of Computer Science
00003  *  All rights reserved.
00004  *
00005  *  Redistribution and use in source and binary forms, with or without
00006  *  modification, are permitted provided that the following conditions are met:
00007  *
00008  *  * Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  *  * Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in
00012  *    the documentation and/or other materials provided with the
00013  *    distribution.
00014  *  * Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 /**
00031  * \file
00032  *
00033  * \brief
00034  *      Handles the control of the USART for communication with the ATmega1284p
00035  *      for sending commands.
00036  *
00037  * \author
00038  *      Mike Vidales mavida404@gmail.com
00039  *
00040  */
00041 
00042 #include "uart.h"
00043 #include "lcd.h"
00044 #include "main.h"
00045 #include "menu.h"
00046 #include "beep.h"
00047 
00048 /**
00049  *  \addtogroup lcd
00050  *  \{
00051 */
00052 
00053 #define TIMEOUT (0xff)
00054 
00055 /** \brief The RX circular buffer, for storing characters from serial port. */
00056 tcirc_buf rxbuf;
00057 
00058 /*---------------------------------------------------------------------------*/
00059 
00060 /**
00061  *   \brief This will intialize the circular buffer head and tail of tcirc_buf struct.
00062  *
00063  *   \param cbuf Pointer to buffer to initialize.
00064 */
00065 void
00066 uart_init_circ_buf(tcirc_buf *cbuf)
00067 {
00068     cbuf->head = cbuf->tail = 0;
00069 }
00070 
00071 /*---------------------------------------------------------------------------*/
00072 
00073 /**
00074  *   \brief This will add a new character to the circular buffer.
00075  *
00076  *   \param cbuf Pointer to buffer where character will be stored.
00077  *   \param ch Character to store into buffer.
00078 */
00079 void
00080 uart_add_to_circ_buf(tcirc_buf *cbuf, uint8_t ch)
00081 {
00082     /* Add char to buffer */
00083     uint8_t newhead = cbuf->head;
00084     newhead++;
00085     if (newhead >= BUFSIZE){
00086         newhead = 0;
00087     }
00088     if (newhead == cbuf->tail){
00089         /* Buffer full, quit it */
00090         return;
00091     }
00092 
00093     cbuf->buf[cbuf->head] = ch;
00094     cbuf->head = newhead;
00095 }
00096 
00097 /*---------------------------------------------------------------------------*/
00098 
00099 /**
00100  *   \brief This will get a character from the buffer requested.
00101  *
00102  *   \param cbuf Pointer to buffer to get character from.
00103  *
00104  *   \return retval Return character from buffer.
00105 */
00106 uint8_t
00107 uart_get_from_circ_buf(tcirc_buf *cbuf)
00108 {
00109     /* Get char from buffer. */
00110     /* Be sure to check first that there is a char in buffer. */
00111     uint8_t newtail = cbuf->tail;
00112     uint8_t retval = cbuf->buf[newtail];
00113 
00114     newtail++;
00115     if (newtail >= BUFSIZE){
00116         /* Rollover */
00117         newtail = 0;
00118     }
00119     cbuf->tail = newtail;
00120 
00121     return retval;
00122 }
00123 
00124 /*---------------------------------------------------------------------------*/
00125 
00126 /**
00127  *   \brief This will clear the RX buffer.
00128 */
00129 void
00130 uart_clear_rx_buf(void)
00131 {
00132     rxbuf.tail = rxbuf.head = 0;
00133 }
00134 
00135 /**
00136  *   \brief This will check for a character in the requested buffer.
00137  *
00138  *   \param cbuf Pointer to buffer to check for any characters.
00139  *
00140  *   \return True if buffer empty.
00141 */
00142 uint8_t
00143 uart_circ_buf_has_char(tcirc_buf *cbuf)
00144 {
00145     /* Return true if buffer empty */
00146     return (cbuf->head != cbuf->tail);
00147 }
00148 
00149 /*---------------------------------------------------------------------------*/
00150 
00151 /**
00152  *   \brief This will convert a nibble to a hex value.
00153  *
00154  *   \param val Value to convert to hex.
00155  *
00156  *   \return val Converted hex value
00157 */
00158 uint8_t
00159 uip_ntohex(uint8_t val)
00160 {
00161     /* Convert nibble to hex */
00162     if (val > 9){
00163         return val + 'A' - 10;
00164     }
00165     else{
00166         return val + '0';
00167     }
00168 }
00169 
00170 /*---------------------------------------------------------------------------*/
00171 
00172 /**
00173  *   \brief Convert integer to hex value.
00174  *
00175  *   \param val Value to convert to hex.
00176  *   \param str Location to store converted value.
00177 */
00178 void
00179 itohex(uint8_t val,char *str)
00180 {
00181     *str++ = uip_ntohex(val >> 8);
00182     *str = uip_ntohex(val & 0x0f);
00183 }
00184 
00185 /*---------------------------------------------------------------------------*/
00186 
00187 /**
00188  *   \brief This will wait for a new character from the ATmega1284p and timeout
00189  *   if no new character is received.
00190  *
00191  *   \retval TIMEOUT Returns if timeout has occured.
00192  *   \return retval Character returned upon seeing rx_char_ready()
00193 */
00194 uint8_t
00195 uart_get_char_rx(void)
00196 {
00197     /* Gets a serial char, and waits for timeout */
00198     uint32_t timex = 5000000;
00199     uint8_t retval;
00200 
00201     while (!rx_char_ready()){
00202         if (!timex--){
00203             /* Timeout, return timeout */
00204             return TIMEOUT;
00205         }
00206     }
00207 
00208     retval = uart_get_from_circ_buf(&rxbuf);
00209     return retval;
00210 }
00211 
00212 /*---------------------------------------------------------------------------*/
00213 
00214 /**
00215  *   \brief Initialize UART to 38400 Baud Rate and only
00216  *   enable UART for transmission.
00217 */
00218 void
00219 uart_init(void)
00220 {
00221     /* For Mega3290P, enable the uart peripheral */
00222     PRR &= ~(1 << PRUSART0);
00223 
00224     uart_clear_rx_buf();
00225     /* 38400 baud @ 8 MHz internal RC oscillator (error = 0.2%) */
00226     UBRR0 = BAUD_RATE_38400;
00227 
00228     /* 8 bit character size, 1 stop bit and no parity mode */
00229     UCSR0C = ( 3 << UCSZ00);
00230 
00231     /* Enable RX,TX and RX interrupt on USART */
00232     UCSR0B = (1 << RXEN0)|(1 << TXEN0)|(1 << RXCIE0);
00233 }
00234 
00235 /*---------------------------------------------------------------------------*/
00236 
00237 /**
00238  *   \brief Turn off UART for sleep mode.
00239 */
00240 void
00241 uart_deinit(void)
00242 {
00243     /* Disable RX,TX and RX interrupt on USART */
00244     UCSR0B = 0;
00245 
00246     /* for Mega3290P, disable the uart peripheral */
00247     PRR |= (1 << PRUSART0);
00248 }
00249 
00250 /*---------------------------------------------------------------------------*/
00251 
00252 /**
00253  *   \brief Send one byte over the uart. This is called to send binary commands.
00254  *
00255  *   \param byte The byte of data to send out the uart.
00256 */
00257 void
00258 uart_send_byte(uint8_t byte)
00259 {
00260     /* Wait for last char to be gone... */
00261     while(!(UCSR0A & (1 << UDRE0)))
00262         ;
00263     UDR0 = byte;
00264 
00265     /* Clear the TXC bit to allow transmit complete test before sleep*/
00266     UCSR0A |=(1 << TXC0);
00267 }
00268 
00269 /*---------------------------------------------------------------------------*/
00270 
00271 /**
00272  *   \brief This is the USART RX complete interrupt.
00273 */
00274 ISR
00275 (USART_RX_vect)
00276 {
00277     /* Get byte from serial port, put in Rx Buffer. */
00278     uint8_t retval;
00279 
00280     retval = UDR0;
00281     uart_add_to_circ_buf(&rxbuf, retval);
00282 }
00283 
00284 /*---------------------------------------------------------------------------*/
00285 
00286 /**
00287  *   \brief This function builds and sends a binary command frame to the
00288  *   ATmega1284p.
00289  *
00290  *   \param cmd Command to send.
00291  *   \param payload_length Length of data to be sent with command.
00292  *   \param payload Pointer to data to send.
00293 */
00294 void
00295 uart_serial_send_frame(uint8_t cmd, uint8_t payload_length, uint8_t *payload)
00296 {
00297     /* Send a frame to 1284p */
00298     int8_t i;
00299 
00300     uart_send_byte(SOF_CHAR);
00301     uart_send_byte(payload_length);
00302     uart_send_byte(cmd);
00303     for (i=0;i<=payload_length-1;i++){
00304             uart_send_byte(payload[i]);
00305         }
00306     uart_send_byte(EOF_CHAR);
00307 }
00308 
00309 /*---------------------------------------------------------------------------*/
00310 
00311 /**
00312  *   \brief This displays a time out message to the user based on the parameter
00313  *   reason x.
00314  *
00315  *   \param x Reason for USART time out.
00316 */
00317 void
00318 uart_timeout_msg(uint8_t x)
00319 {
00320     char str[20] = "TO     ";
00321 
00322     dectoascii(x, str+3);
00323     lcd_puts(str);
00324 }
00325 
00326 /*---------------------------------------------------------------------------*/
00327 
00328 /**
00329  *   \brief This will receive a frame from the ATmega1284p and parse the incoming
00330  *   data.
00331  *
00332  *   If the incoming data is a binary command acknowledgement, then this will not
00333  *   parse any data. If the incoming data is test reports, the menu will store the
00334  *   data for end of test metrics.
00335  *
00336  *   \param wait_for_ack Flag used to wait for acknowledgement when receving a serial
00337  *   frame.
00338 */
00339 void
00340 uart_serial_rcv_frame(uint8_t wait_for_ack)
00341 {
00342     /* Gets a serial frame, if any, and displays data appropriately */
00343     /* If wait_for_ack is true, this funtion will wait for serial chars. */
00344     volatile uint8_t ch;
00345     volatile uint8_t length;
00346     volatile uint8_t cmd;
00347     volatile uint8_t payload[20];
00348     uint16_t i;
00349 
00350     if (!wait_for_ack && !rx_char_ready()){
00351         return;
00352     }
00353 
00354     /* Check for SOF */
00355     ch = uart_get_char_rx();
00356     if (ch != SOF_CHAR){
00357         return uart_timeout_msg(1);
00358     }
00359 
00360     /* Turn on nose LED for activity indicator */
00361     led_on();
00362 
00363     /* Get length byte */
00364     ch = uart_get_char_rx();
00365     if (ch == TIMEOUT){
00366         return uart_timeout_msg(2);
00367     }
00368     /* Check for ACK Frame */
00369     if (ch >= 0x80){
00370         /* This is an ack frame, just get it and go away. */
00371         ch = uart_get_char_rx();
00372         if (ch != EOF_CHAR){
00373             uart_timeout_msg(3);
00374         }
00375         led_off();
00376         return;
00377     }
00378 
00379     length = ch;
00380     if (length > sizeof(payload)){
00381         /* invalid length */
00382         return;
00383     }
00384 
00385     /* Get cmd byte */
00386     ch = uart_get_char_rx();
00387     if (ch == TIMEOUT){
00388         return uart_timeout_msg(5);
00389     }
00390     cmd = ch;
00391 
00392     /* Get payload */
00393     for (i=0;i<length;i++){
00394         ch = uart_get_char_rx();
00395         if (ch == TIMEOUT){
00396             return uart_timeout_msg(i);
00397         }
00398         /* Save payload */
00399         payload[i] = ch;
00400     }
00401 
00402     /* Get EOF */
00403     ch = uart_get_char_rx();
00404     if (ch != EOF_CHAR){
00405         return uart_timeout_msg(7);
00406     }
00407 
00408     /* Process the received command */
00409     switch (cmd){
00410         case REPORT_PING:
00411             /*
00412              * This will update the lcd with the current ping status.
00413              * Store the sequence number away.
00414              */
00415             ping_response = payload[0];
00416 
00417             if(ping_response == 1){
00418                 lcd_single_print_dig(ping_response, 3);
00419             }
00420             else if(ping_response == 2){
00421                 lcd_single_print_dig(ping_response, 2);
00422             }
00423             else if(ping_response == 3){
00424                 lcd_single_print_dig(ping_response, 1);
00425             }
00426             else if(ping_response == 4){
00427                 lcd_single_print_dig(ping_response, 0);
00428             }
00429 
00430             timeout_flag = false;
00431 
00432             /* Beep on successful ping response. */
00433             lcd_symbol_set(LCD_SYMBOL_BELL);
00434             beep();
00435             lcd_symbol_clr(LCD_SYMBOL_BELL);
00436             break;
00437         case REPORT_TEXT_MSG:
00438             /* Copy text message to menu buffer and play ringtone */
00439             /* Prezero in case no string terminator in command */
00440             for (i=0;i<sizeof(top_menu_text);i++) top_menu_text[i]=0;
00441             memcpy(&top_menu_text,(char *)payload,sizeof(top_menu_text)-1);  //leave zero byte at end
00442             play_ringtone();
00443             break;
00444         case REPORT_PING_BEEP:
00445             lcd_symbol_set(LCD_SYMBOL_BELL);
00446             beep();
00447             lcd_symbol_clr(LCD_SYMBOL_BELL);
00448             break;
00449         case REPORT_WAKE:
00450             /* Indicates 1284 is awake*/
00451             break;
00452         default:
00453             break;
00454     }
00455     led_off();
00456 }
00457 
00458 /** \}   */