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 * This file operates the menu flow chart described in the readme 00035 * notes. This will create the proper commands needed to control the 1284p. 00036 * 00037 * \author 00038 * Mike Vidales mavida404@gmail.com 00039 * 00040 */ 00041 00042 #include <avr/eeprom.h> 00043 #include <util/delay.h> 00044 #include "menu.h" 00045 #include "main.h" 00046 #include "lcd.h" 00047 #include "key.h" 00048 #include "uart.h" 00049 #include "sleep.h" 00050 #include "temp.h" 00051 #include "beep.h" 00052 00053 uint8_t sleep_count; 00054 uint8_t ping_count; 00055 uint8_t ping_response; 00056 bool ping_mode; 00057 bool timeout_flag; 00058 bool temp_flag; 00059 bool temp_mode; 00060 bool auto_temp=true; 00061 00062 /** 00063 * \addtogroup lcd 00064 * \{ 00065 */ 00066 00067 /*---------------------------------------------------------------------------*/ 00068 00069 /** 00070 * \brief This function will convert decimal to ascii. 00071 * 00072 * \param val Decimal value to convert. 00073 * \param str Address location to store converted value. 00074 */ 00075 void 00076 dectoascii(uint8_t val, char *str) 00077 { 00078 *(str+1) = (val % 10) + '0'; 00079 *str = (val / 10) + '0'; 00080 } 00081 00082 /*---------------------------------------------------------------------------*/ 00083 00084 /** 00085 * \brief This will convert a signed decimal number to ASCII. 00086 * 00087 * \param n Signed number 00088 * \param str Pointer to store converted value. 00089 * 00090 * \return *p Address of stored conversion. 00091 */ 00092 uint8_t 00093 *signed_dectoascii(int16_t n, uint8_t *str) 00094 { 00095 uint8_t * p = str; 00096 uint8_t neg = 0; 00097 00098 if(n < 0){ 00099 neg = 1; 00100 n = -n; 00101 } 00102 00103 *p-- = 0x00; 00104 00105 /* Determine the unit of conversion. */ 00106 if(temp_mode == TEMP_UNIT_CELCIUS){ 00107 /* Add ASCII C to string. */ 00108 *p-- = 'C'; 00109 } 00110 else{ 00111 /* Add ASCII F to string. */ 00112 *p-- = 'F'; 00113 } 00114 00115 /* Add a space before unit symbol. */ 00116 *p-- = ' '; 00117 00118 /* For zero, just print zero. */ 00119 if (!n){ 00120 *p = '0'; 00121 return p; 00122 } 00123 00124 while (n){ 00125 *p-- = (n%10) + '0'; 00126 n/= 10; 00127 } 00128 00129 if (neg){ 00130 *p-- = '-'; 00131 } 00132 00133 return ++p; 00134 } 00135 00136 /*---------------------------------------------------------------------------*/ 00137 00138 /** 00139 * \brief This will check for DEBUG mode after power up. 00140 */ 00141 void 00142 eeprom_init(void) 00143 { 00144 uint8_t val; 00145 if(0xFF == eeprom_read_byte(EEPROM_DEBUG_ADDR)){ 00146 /* Disable - Reverse logic. */ 00147 val = 1; 00148 menu_debug_mode(&val); 00149 } 00150 else{ 00151 /* Enable - Reverse logic. */ 00152 val = 0; 00153 menu_debug_mode(&val); 00154 } 00155 } 00156 00157 /*---------------------------------------------------------------------------*/ 00158 00159 /** 00160 * \brief This will start a sleep operation. 00161 * 00162 * \param val Used for remembering the new menu to display after a wakeup. 00163 */ 00164 void 00165 menu_run_sleep(uint8_t *val) 00166 { 00167 /* Turn off LED, LCD, ADC, Timer 1, SPI */ 00168 led_off(); 00169 lcd_deinit(); 00170 key_deinit(); 00171 PRR |= (1 << PRTIM1) | (1 << PRSPI); 00172 00173 /* Tell the 1284P to turn off the radio and sleep */ 00174 sleep_count=0; 00175 uart_serial_send_frame(SEND_SLEEP, 1, (uint8_t *)&sleep_count); 00176 00177 /* Turn off UART when transmission is complete */ 00178 while(!(UCSR0A & (1 << TXC0))); 00179 _delay_us(10000); //deinit trash clears done flag on 1284p 00180 uart_deinit(); 00181 00182 /* Go to sleep until button is pushed */ 00183 sleep_now(0); 00184 00185 /* Yawn, waking up, turn on LCD with Raven Logo */ 00186 lcd_init(); 00187 lcd_symbol_set(LCD_SYMBOL_RAVEN); 00188 00189 /* Disable interrupts before powering everything up */ 00190 cli(); 00191 key_init(); 00192 PRR &= ~((1 << PRTIM1) | (1 << PRSPI)); 00193 uart_init(); 00194 00195 /* Enable interrupts, Wake up 1284p and radio */ 00196 sei(); 00197 sleep_wakeup(); 00198 // uart_init();//flush receive buffer 00199 00200 /* Wait for buttons up */ 00201 while (key_state_get() != KEY_NO_KEY) 00202 ; 00203 if (is_button()){ 00204 get_button(); 00205 } 00206 } 00207 /*---------------------------------------------------------------------------*/ 00208 00209 /** 00210 * \brief This will start a sleep with wakes for temperature measurement and web requests. 00211 * 00212 * \param val Used for remembering the new menu to display after a wakeup. 00213 */ 00214 void 00215 menu_run_doze(uint8_t *val) 00216 { 00217 /* Turn off LED, LCD */ 00218 led_off(); 00219 lcd_deinit(); 00220 00221 /* Debounce */ 00222 while (key_state_get() != KEY_NO_KEY) ; 00223 00224 /* Stay in doze loop until button is pressed*/ 00225 while (ENTER_PORT & (1<<ENTER_PIN)) { 00226 00227 /* Tell 1284p to sleep for 4 seconds */ 00228 /* It will ignore the request if TCP/IP sessions are active */ 00229 /* Alter these timings as desired, or comment out to sleep only the 3290p */ 00230 sleep_count=4; 00231 uart_serial_send_frame(SEND_SLEEP, 1, (uint8_t *)&sleep_count); 00232 00233 /* Wait for transmission complete, then sleep 3290p for 5 seconds */ 00234 while(!(UCSR0A & (1 << TXC0))); 00235 // uart_deinit(); 00236 sleep_now(sleep_count+1); 00237 // uart_init(); 00238 00239 /* 1284p should be awake by now, update temperature and give it time to process */ 00240 menu_send_temp(); 00241 _delay_us(20000); 00242 } 00243 00244 /* Wake LCD, turn on Raven logo */ 00245 lcd_init(); 00246 lcd_symbol_set(LCD_SYMBOL_RAVEN); 00247 sleep_wakeup(); 00248 /* Wait for buttons up */ 00249 while (key_state_get() != KEY_NO_KEY) 00250 ; 00251 if (is_button()){ 00252 get_button(); 00253 } 00254 } 00255 00256 /*---------------------------------------------------------------------------*/ 00257 00258 /** 00259 * \brief This will setup a ping request command to the 1284p and reset the ping counter. 00260 * 00261 * \param val place holder 00262 */ 00263 void 00264 menu_ping_request(uint8_t * val) 00265 { 00266 uint8_t i; 00267 ping_mode = true; 00268 ping_count = 0; 00269 ping_response = 0; 00270 00271 /* Initialize the numerical display with dashes */ 00272 for(i=0; i<4; i++){ 00273 lcd_single_print_dig(LCD_SEV_SEG_INDEX_MINUS, i); 00274 } 00275 00276 menu_send_ping(); 00277 00278 /* Reset the timer for 1 sec resolution between pings. */ 00279 TCNT1 = 0; 00280 } 00281 00282 /*---------------------------------------------------------------------------*/ 00283 00284 /** 00285 * \brief This will send the ping request to the 1284p via the serial port. 00286 * 00287 * \return ping_count The number of ping attempts. 00288 */ 00289 uint8_t 00290 menu_send_ping(void) 00291 { 00292 /* 00293 * Check for previous ping timeout. If menu_send_ping() was called before receiving 00294 * a response, update the LCD. 00295 */ 00296 timeout_flag = true; 00297 ping_count++; 00298 /* Send the ping command with one byte payload of the current sequence number. */ 00299 uart_serial_send_frame(SEND_PING, 1, (uint8_t *)&ping_count); 00300 return ping_count; 00301 } 00302 00303 /*---------------------------------------------------------------------------*/ 00304 00305 /** 00306 * \brief This will stop the ping request. 00307 */ 00308 void 00309 menu_stop_ping(void) 00310 { 00311 ping_mode = false; 00312 } 00313 00314 /*---------------------------------------------------------------------------*/ 00315 00316 /** 00317 * \brief This will enable or disable the JTAG debug interface to allow for 00318 * proper temperature sensor readings. 00319 * 00320 * \param val Flag to trigger the proper debug mode. 00321 */ 00322 void 00323 menu_debug_mode(uint8_t *val) 00324 { 00325 uint8_t sreg = SREG; 00326 cli(); 00327 if(*val){ 00328 /* Disable - Could use inline ASM to meet timing requirements. */ 00329 MCUCR |= (1 << JTD); 00330 MCUCR |= (1 << JTD); 00331 /* Needed for timing critical JTD disable. */ 00332 temp_init(); 00333 /* Store setting in EEPROM. */ 00334 eeprom_write_byte(EEPROM_DEBUG_ADDR, 0xFF); 00335 } 00336 else{ 00337 /* Enable - Could use inline ASM to meet timing requirements. */ 00338 MCUCR &= ~(1 << JTD); 00339 MCUCR &= ~(1 << JTD); 00340 /* Store setting in EEPROM. */ 00341 eeprom_write_byte(EEPROM_DEBUG_ADDR, 0x01); 00342 } 00343 SREG = sreg; 00344 } 00345 00346 /*---------------------------------------------------------------------------*/ 00347 00348 /** 00349 * \brief This will display the temperature in degrees F or C. 00350 * 00351 * \param val Flag to trigger F or C temperature conversion. 00352 */ 00353 void 00354 menu_read_temp(uint8_t *val) 00355 { 00356 if(*val){ 00357 temp_mode = TEMP_UNIT_CELCIUS; 00358 } 00359 else{ 00360 temp_mode = TEMP_UNIT_FAHRENHEIT; 00361 } 00362 00363 temp_flag = true; 00364 00365 menu_display_temp(); 00366 } 00367 00368 /*---------------------------------------------------------------------------*/ 00369 00370 /** 00371 * \brief This will display the temperature in degrees F or C. 00372 */ 00373 void 00374 menu_display_temp(void) 00375 { 00376 int16_t result = temp_get(temp_mode); 00377 00378 /* Display the temp result on the lower 4 digit display with the proper symbol. */ 00379 if(temp_mode == TEMP_UNIT_CELCIUS){ 00380 lcd_symbol_clr(LCD_SYMBOL_F); 00381 lcd_symbol_set(LCD_SYMBOL_C); 00382 } 00383 else{ 00384 lcd_symbol_clr(LCD_SYMBOL_C); 00385 lcd_symbol_set(LCD_SYMBOL_F); 00386 } 00387 00388 /* Check for the DEBUG JTAG enable bit and display a CAUTION symbol to the user. */ 00389 /* CAUTION represents false value. */ 00390 if(MCUCR & 0x80){ 00391 lcd_symbol_clr(LCD_SYMBOL_ATT); 00392 } 00393 else{ 00394 lcd_symbol_set(LCD_SYMBOL_ATT); 00395 } 00396 00397 lcd_num_putdec(result, LCD_NUM_PADDING_SPACE); 00398 } 00399 00400 /*---------------------------------------------------------------------------*/ 00401 00402 /** 00403 * \brief This will clear the temperature displayed in the 4 digit LCD segments. 00404 */ 00405 void 00406 menu_clear_temp(void) 00407 { 00408 temp_flag = false; 00409 lcd_symbol_clr(LCD_SYMBOL_F); 00410 lcd_symbol_clr(LCD_SYMBOL_C); 00411 lcd_symbol_clr(LCD_SYMBOL_ATT); 00412 lcd_num_clr(); 00413 } 00414 00415 /*---------------------------------------------------------------------------*/ 00416 00417 /** 00418 * \brief This will setup the current temperature for transfer to the ATmega1284p via a binary 00419 * command transfer. 00420 * 00421 * \param val This is used to determine sending once or auto based on the timer. 00422 */ 00423 void 00424 menu_prepare_temp(uint8_t *val) 00425 { 00426 if(*val){ 00427 /* Only send the temp value once. */ 00428 auto_temp = false; 00429 } 00430 else{ 00431 /* Auto send the temp value based on TIMER1 interval. */ 00432 auto_temp = true; 00433 } 00434 00435 menu_send_temp(); 00436 } 00437 00438 /*---------------------------------------------------------------------------*/ 00439 00440 /** 00441 * \brief This will stop the auto sending of temperature data. 00442 */ 00443 void 00444 menu_stop_temp(void) 00445 { 00446 auto_temp = false; 00447 } 00448 00449 /*---------------------------------------------------------------------------*/ 00450 00451 /** 00452 * \brief This will send the data via the serial port. 00453 */ 00454 #if MEASURE_ADC2 00455 extern uint16_t ADC2_reading; 00456 #endif 00457 void 00458 menu_send_temp(void) 00459 { 00460 int16_t result; 00461 uint8_t str[12]; 00462 uint8_t * p = 0; 00463 00464 /* Turn on nose LED for activity indicator */ 00465 led_on(); 00466 00467 /* Get the latest temp value. */ 00468 result = temp_get(temp_mode); 00469 00470 /* Convert signed decimal number to ASCII. */ 00471 p = signed_dectoascii(result, (str + 10)); 00472 00473 /* Send frame via serial port. */ 00474 uart_serial_send_frame(SEND_TEMP, 1+strlen((char *)p), p); 00475 00476 #if MEASURE_ADC2 00477 /* Send ADC2 via serial port. */ 00478 p = signed_dectoascii(ADC2_reading, (str + 10)); 00479 str[9]='m';str[10]='V';str[11]=0; //convert degrees to millivolts ;) 00480 uart_serial_send_frame(SEND_ADC2, 1+strlen((char *)p), p); 00481 #endif 00482 00483 led_off(); 00484 } 00485 00486 /** \} */