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 /** \} */