Contiki 2.6

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