Contiki 2.6

lcd.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 provides Raven LCD support.
00035  *
00036  * \author
00037  *      Mike Vidales mavida404@gmail.com
00038  *
00039  */
00040 
00041 #include "lcd.h"
00042 
00043 /**
00044  * \addtogroup lcd
00045  * \{
00046 */
00047 
00048 typedef enum {
00049     LCD_DUTY_STATIC = 0,
00050     LCD_DUTY_HALF   = 1,
00051     LCD_DUTY_THIRD  = 2,
00052     LCD_DUTY_QUART  = 3
00053 } lcd_duty_t;
00054 
00055 typedef enum {
00056     LCD_PM_0_12 = 0x0,
00057     LCD_PM_0_14 = 0x1,
00058     LCD_PM_0_16 = 0x2,
00059     LCD_PM_0_18 = 0x3,
00060     LCD_PM_0_20 = 0x4,
00061     LCD_PM_0_22 = 0x5,
00062     LCD_PM_0_23 = 0x6,
00063     LCD_PM_0_24 = 0x7,
00064     LCD_PM_0_26 = 0x8,
00065     LCD_PM_0_28 = 0x9,
00066     LCD_PM_0_30 = 0xA,
00067     LCD_PM_0_32 = 0xB,
00068     LCD_PM_0_34 = 0xC,
00069     LCD_PM_0_36 = 0xD,
00070     LCD_PM_0_38 = 0xE,
00071     LCD_PM_0_39 = 0xF
00072 } lcd_pm_t;
00073 
00074 #if defined( DOXYGEN )
00075 static const seg_map[];
00076 static const LCD_character_table[];
00077 static const seg_inf[];
00078 static const lcd_symbol_chart[LCD_SYMBOL_COUNT];
00079 #else  /* !DOXYGEN */
00080 /** \name Mapping of segments for different characters */
00081 /** \{ */
00082 static const unsigned char seg_map[] PROGMEM = {
00083         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F                 , /* 0 */
00084                          NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C                                                                    , /* 1 */
00085         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|                 NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|                 NUM_LCD_SYMBOL_G, /* 2 */
00086         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|                                  NUM_LCD_SYMBOL_G, /* 3 */
00087                          NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|                                  NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 4 */
00088         NUM_LCD_SYMBOL_A|                 NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|                 NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 5 */
00089         NUM_LCD_SYMBOL_A|                 NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 6 */
00090         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C                                                                    , /* 7 */
00091         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 8 */
00092         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|                 NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* 9 */
00093         NUM_LCD_SYMBOL_A|NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|                 NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* A */
00094                                           NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* B */
00095         NUM_LCD_SYMBOL_A|                                  NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F                 , /* C */
00096                          NUM_LCD_SYMBOL_B|NUM_LCD_SYMBOL_C|NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|                 NUM_LCD_SYMBOL_G, /* D */
00097         NUM_LCD_SYMBOL_A|                                  NUM_LCD_SYMBOL_D|NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* E */
00098         NUM_LCD_SYMBOL_A|                                                   NUM_LCD_SYMBOL_E|NUM_LCD_SYMBOL_F|NUM_LCD_SYMBOL_G, /* F */
00099                                                                                                                              0, /* ' ' (space) */
00100                                                                                                               NUM_LCD_SYMBOL_G  /*  - (minus) */
00101 };
00102 /** \} */
00103 
00104 /* Look-up tables for 14-segment characters */
00105 static const unsigned int LCD_character_table[] PROGMEM = /* Character definitions table. */
00106 {
00107         0x0000,         /* '*' (?) */
00108         0x2830,         /* '+' */
00109         0x0000,         /* ',' (Not defined) */
00110         0x0810,         /* '-' */
00111         0x0200,         /* '.' */
00112         0x0240,         /* '/' */
00113         0x93C5,         /* '0' */
00114         0x80C0,         /* '1' */
00115         0x1994,         /* '2' */
00116         0x9894,         /* '3' */
00117         0x8891,         /* '4' */
00118         0x9815,         /* '5' */
00119         0x9915,         /* '6' */
00120         0x8084,         /* '7' */
00121         0x9995,         /* '8' */
00122         0x9895,         /* '9' */
00123         0x0000,         /* ':' (Not defined) */
00124         0x0000,         /* ';' (Not defined) */
00125         0x0000,         /* '<' (Not defined) */
00126         0x0000,         /* '=' (Not defined) */
00127         0x0202,         /* '>' */
00128         0x0000,         /* '?' (Not defined) */
00129         0x8E53,         /* '@' (redefined as '%') */
00130         0x8995,         /* 'A' (+ 'a') */
00131         0xB8A4,         /* 'B' (+ 'b') */
00132         0x1105,         /* 'C' (+ 'c') */
00133         0xB0A4,         /* 'D' (+ 'd') */
00134         0x1915,         /* 'E' (+ 'e') */
00135         0x0915,         /* 'F' (+ 'f') */
00136         0x9905,         /* 'G' (+ 'g') */
00137         0x8991,         /* 'H' (+ 'h') */
00138         0x2020,         /* 'I' (+ 'i') */
00139         0x9180,         /* 'J' (+ 'j') */
00140         0x0551,         /* 'K' (+ 'k') */
00141         0x1101,         /* 'L' (+ 'l') */
00142         0x81C3,         /* 'M' (+ 'm') */
00143         0x8583,         /* 'N' (+ 'n') */
00144         0x9185,         /* 'O' (+ 'o') */
00145         0x0995,         /* 'P' (+ 'p') */
00146         0x9585,         /* 'Q' (+ 'q') */
00147         0x0D95,         /* 'R' (+ 'r') */
00148         0x1406,         /* 'S' (+ 's') */
00149         0x2024,         /* 'T' (+ 't') */
00150         0x9181,         /* 'U' (+ 'u') */
00151         0x0341,         /* 'V' (+ 'v') */
00152         0x8781,         /* 'W' (+ 'w') */
00153         0x0642,         /* 'X' (+ 'x') */
00154         0x2042,         /* 'Y' (+ 'y') */
00155         0x1244,         /* 'Z' (+ 'z') */
00156         0x0000,         /* '[' (Not defined) */
00157         0x0000,         /* '\' (Not defined) */
00158         0x0000,         /* ']' (Not defined) */
00159         0x0000,         /* '^' (Not defined) */
00160         0x0000,         /* '_' (Not defined) */
00161   0x0004,   /* A */
00162   0x0080,   /* B */
00163   0x8000,   /* C */
00164   0x1000,   /* D */
00165   0x0100,   /* E */
00166   0x0001,   /* F */
00167   0x0002,   /* G */
00168   0x0020,   /* H */
00169   0x0040,   /* J */
00170   0x0800,   /* K */
00171   0x0400,   /* L */
00172   0x2000,   /* M */
00173   0x0200,   /* N */
00174   0x0010,   /* O */
00175   0x0000,
00176   0x0000,
00177   0x0000
00178 };
00179 
00180 /** \brief Seven segment reference guide in flash. */
00181 static const unsigned char seg_inf[] PROGMEM = {
00182         2<<5|19, /* A */
00183         1<<5|19, /* B */
00184         1<<5|9,  /* C */
00185         2<<5|4,  /* D */
00186         2<<5|9,  /* E */
00187         2<<5|14, /* F */
00188         1<<5|14  /* G */
00189 };
00190 
00191 /** \brief LCD symbol chart located in flash. */
00192 static const lcd_symbol_t lcd_symbol_chart[LCD_SYMBOL_COUNT] PROGMEM= {
00193     /* Raven */
00194     LCD_SYMBOL_RAVEN   ,
00195 
00196     /* Audio */
00197     LCD_SYMBOL_BELL    ,
00198     LCD_SYMBOL_TONE    ,
00199     LCD_SYMBOL_MIC     ,
00200     LCD_SYMBOL_SPEAKER ,
00201 
00202     /* Status */
00203     LCD_SYMBOL_KEY     ,
00204     LCD_SYMBOL_ATT     ,
00205 
00206     /* Time */
00207     LCD_SYMBOL_SUN     ,
00208     LCD_SYMBOL_MOON    ,
00209     LCD_SYMBOL_AM      ,
00210     LCD_SYMBOL_PM      ,
00211 
00212     /* Radio comus */
00213     LCD_SYMBOL_RX      ,
00214     LCD_SYMBOL_TX      ,
00215     LCD_SYMBOL_IP      ,
00216     LCD_SYMBOL_PAN     ,
00217     LCD_SYMBOL_ZLINK   ,
00218     LCD_SYMBOL_ZIGBEE  ,
00219 
00220     /* Antenna status */
00221     LCD_SYMBOL_ANT_FOOT,
00222     LCD_SYMBOL_ANT_SIG1,
00223     LCD_SYMBOL_ANT_SIG2,
00224     LCD_SYMBOL_ANT_SIG3,
00225     LCD_SYMBOL_ANT_DIS ,
00226 
00227     /* Battery status */
00228     LCD_SYMBOL_BAT_CONT,
00229     LCD_SYMBOL_BAT_CAP1,
00230     LCD_SYMBOL_BAT_CAP2,
00231     LCD_SYMBOL_BAT_CAP3,
00232 
00233     /* Envelope status */
00234     LCD_SYMBOL_ENV_OP  ,
00235     LCD_SYMBOL_ENV_CL  ,
00236     LCD_SYMBOL_ENV_MAIN,
00237 
00238     /* Temperature */
00239     LCD_SYMBOL_C       ,
00240     LCD_SYMBOL_F       ,
00241 
00242     /* Numeric */
00243     LCD_SYMBOL_MINUS   ,
00244     LCD_SYMBOL_DOT     ,
00245     LCD_SYMBOL_COL
00246 };
00247 #endif /* !DOXYGEN */
00248 
00249 /** LCD text buffer */
00250 static unsigned char lcd_text[20];
00251 
00252 /** Textd buffer read pointer for text field in LCD display. When ptr>0 characters in front will be cleared (space) */
00253 static int lcd_text_rd_ptr = 0;
00254 
00255 /** Text pointer for writing new chars to text buffer */
00256 static int lcd_text_wr_ptr = 0;
00257 
00258 static bool lcd_scroll_enable;
00259 static int  lcd_scroll_prescale;
00260 static int  lcd_scroll_prescale_value;
00261 static int  lcd_num_print(uint16_t numb, bool negative, lcd_padding_t padding);
00262 static void lcd_nmb_print_dig(uint8_t val, int dig);
00263 static int  lcd_text_sl(void);
00264 static int  lcd_text_put(const char* s, int pos);
00265 static int  lcd_char_put(unsigned char c, int pos);
00266 
00267 /*---------------------------------------------------------------------------*/
00268 
00269 /**
00270  *  \brief This function will initialize the proper settings for the LCD driver.
00271  *
00272  *  This ATmega3290p can directly support an LCD through register mapping.
00273  *
00274  *  \return 0
00275 */
00276 int
00277 lcd_init(void)
00278 {
00279     /*
00280      * Configuring LCD with Extern clock (TOSC, 32.768kHz)
00281      *                      32786 Hz          32786 Hz
00282      *  frame_rate = ------------------ = ------------- = 32 Hz
00283      *               8 * .prescl * .div     8 * 16 * 8
00284      */
00285 
00286     lcd_config_t lcd_config ;
00287     lcd_config.blanking   = LCD_BLANKING_OFF;
00288     lcd_config.buffer     = LCD_BUFFER_ON;
00289     lcd_config.wave       = LCD_WAVE_LOW_POWER;
00290     lcd_config.clock      = LCD_CLOCK_EXTERN;
00291     lcd_config.bias       = LCD_BIAS_HALF;
00292     lcd_config.prescl     = LCD_PRESCL_16;
00293     lcd_config.div        = LCD_DIV_8;
00294     lcd_config.drive      = LCD_DRIVE_450;
00295     lcd_config.contrast   = LCD_CONTRAST_3_30;
00296 
00297     /* Enable module */
00298     PRR &= ~(1 << PRLCD);
00299 
00300     /* Configure and enable LCD controller */
00301     LCDCRB = lcd_config.lcdcrb|(LCD_PM_0_39<<LCDPM0)|(LCD_DUTY_QUART<<LCDMUX0); /* Add port mask/mux */
00302     LCDFRR = lcd_config.lcdfrr;
00303     LCDCCR = lcd_config.lcdccr;
00304     LCDCRA = lcd_config.lcdcra|(1<<LCDEN)|(1<<LCDIE); /* Add interrupt- and LCD- enable */
00305 
00306     /* clear screen */
00307     lcd_symbol_clr_all();
00308 
00309     /* Calculate scrolling value */
00310     lcd_scroll_prescale_value = LCD_CLCK_FRQ/128;
00311     lcd_scroll_prescale_value >>= (lcd_config.prescl == 0) ? 4 : (5+lcd_config.prescl);
00312     lcd_scroll_prescale_value /= (lcd_config.div+1);
00313     lcd_scroll_prescale_value = (lcd_scroll_prescale_value==0) ? 1 : lcd_scroll_prescale_value;
00314     lcd_scroll_prescale = lcd_scroll_prescale_value;
00315 
00316     return 0;
00317 }
00318 
00319 /*---------------------------------------------------------------------------*/
00320 
00321 /**
00322  *  \brief This will disable the LCD operation.
00323 */
00324 void
00325 lcd_deinit(void)
00326 {
00327     while (!(LCDCRA & (1<<LCDIF)))
00328         ;
00329     /*
00330      * Set LCD Blanking and clear interrupt flag
00331      * by writing a logical one to the flag.
00332      */
00333 
00334     LCDCRA = (1<<LCDEN)|(1<<LCDIF)|(1<<LCDBL);
00335     /* Wait until LCD Blanking is effective. */
00336     while ( !(LCDCRA & (1<<LCDIF)) )
00337         ;
00338 
00339     /* Disable LCD */
00340     LCDCRA = (0<<LCDEN) | (0<<LCDIE);
00341 
00342     /* power LCD down */
00343     PRR |= (1 << PRLCD);
00344 }
00345 
00346 /*---------------------------------------------------------------------------*/
00347 
00348 /**
00349  *  \brief This will convert the incoming decimal number to BCD.
00350  *
00351  *  \param inNumber Decimal number to convert
00352  *
00353  *  \return newByte The converted deicmal number as byte.
00354 */
00355 uint8_t
00356 itobcd(uint8_t inNumber)
00357 {
00358         int newByte;
00359 
00360         newByte = 0;
00361 
00362         while (inNumber >= 10){
00363                 inNumber -= 10;
00364                 newByte++;
00365         }
00366 
00367         newByte = newByte << 4;
00368         newByte = (newByte | inNumber);
00369 
00370         return newByte;
00371 }
00372 
00373 /*---------------------------------------------------------------------------*/
00374 
00375 /**
00376  *  \brief This will put a HEX value on the LCD that represents the input
00377  *  parameter.
00378  *
00379  *  \param numb Number to display as HEX.
00380  *  \param padding This pads the location to place the value on the LCD.
00381  *
00382  *  \return lcd_num_print()
00383 */
00384 int
00385 lcd_num_puthex(uint16_t numb, lcd_padding_t padding)
00386 {
00387     return lcd_num_print(numb, false, padding);
00388 }
00389 
00390 /*---------------------------------------------------------------------------*/
00391 
00392 /**
00393  *  \brief This will put a DEC value on the LCD that represents the input
00394  *  parameter.
00395  *
00396  *  \param numb Number to display as DEC.
00397  *  \param padding This pads the location to place the value on the LCD.
00398  *
00399  *  \return lcd_num_print()
00400 */
00401 int
00402 lcd_num_putdec(int numb, lcd_padding_t padding)
00403 {
00404     uint16_t bcd;
00405 
00406     /* Check for overflow */
00407     if (numb > 9999) {
00408         numb = 9999;
00409     } else if (numb < -9999) {
00410         numb = -9999;
00411     }
00412 
00413     /* Convert to BCD */
00414     bcd = itobcd(abs(numb));
00415 
00416     /* Print */
00417     return lcd_num_print(bcd, (bool)(numb<0), padding);
00418 }
00419 
00420 /*---------------------------------------------------------------------------*/
00421 
00422 /**
00423  *  \brief This will clear numbers displayed on the LCD.
00424  *
00425  *  \return 0
00426 */
00427 int
00428 lcd_num_clr(void)
00429 {
00430     volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
00431     int i,j;
00432 
00433     for (i=0;i<4;++i){
00434         for (j=0;j<7;++j){
00435             lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] &= ~((pgm_read_byte(&seg_inf[j])>>5)<<(i*2));
00436         }
00437     }
00438     return 0;
00439 }
00440 
00441 /*---------------------------------------------------------------------------*/
00442 
00443 /**
00444  *  \brief This will put a string of characters out to the LCD.
00445  *
00446  *  \param s First character pointer of string.
00447  *
00448  *  \return 0
00449 */
00450 int
00451 lcd_puts(const char* s)
00452 {
00453     strcpy((char*)lcd_text, s);
00454     lcd_text_wr_ptr = strlen(s);
00455     lcd_text_rd_ptr = 0;
00456 
00457     lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
00458 
00459     lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
00460 
00461     return 0;
00462 }
00463 
00464 /*---------------------------------------------------------------------------*/
00465 
00466 /**
00467  *  \brief This will put a string of characters of a certain length out to the LCD.
00468  *
00469  *  \param length Length of string to print.
00470  *  \param s First character pointer of string.
00471  *
00472  *  \return 0
00473 */
00474 int
00475 lcd_puta(size_t length, const uint8_t *s)
00476 {
00477     memcpy((void*)lcd_text, (void const*)s, length);
00478     lcd_text_wr_ptr = length;
00479     lcd_text_rd_ptr = 0;
00480 
00481     lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
00482 
00483     lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
00484 
00485     return 0;
00486 }
00487 
00488 /*---------------------------------------------------------------------------*/
00489 
00490 /**
00491  *  \brief This will put a string out to the LCD from Flash.
00492  *
00493  *  \param s First character pointer of the string located in Flash
00494  *
00495  *  \return 0
00496 */
00497 int
00498 lcd_puts_P(const char *s)
00499 {
00500     strcpy_P((char*)lcd_text, s);
00501     lcd_text_wr_ptr = strlen_P(s);
00502     lcd_text_rd_ptr = 0;
00503 
00504     lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
00505 
00506     lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
00507 
00508     return 0;
00509 }
00510 
00511 /*---------------------------------------------------------------------------*/
00512 
00513 /**
00514  *  \brief This will put a single character out to the LCD.
00515  *
00516  *  \param c Character to display on LCD.
00517  *
00518  *  \return 0
00519 */
00520 int
00521 lcd_putchar(unsigned char c)
00522 {
00523     lcd_text[lcd_text_wr_ptr++] = c;
00524     lcd_text[lcd_text_wr_ptr] = 0;
00525 
00526     lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], 1);
00527 
00528     lcd_scroll_enable = (lcd_text_wr_ptr > 7) ? true : false;
00529 
00530     return 0;
00531 }
00532 
00533 /*---------------------------------------------------------------------------*/
00534 
00535 /**
00536  *  \brief This will enable any of the symbols on the Raven LCD.
00537  *
00538  *  \param symbol Specific symbol to enable on the LCD.
00539 */
00540 void
00541 lcd_symbol_set(lcd_symbol_t symbol)
00542 {
00543     unsigned char mem_offset;
00544     unsigned char bit_offset;
00545     volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
00546 
00547     /* Symbol format = bbbnnnnn where b is bit and n is offset */
00548     bit_offset = (symbol >> 5);
00549     mem_offset = (symbol & 0x1F);
00550     if ( mem_offset >= 20 ){
00551         return;  /* Data out of range of the LCD registers */
00552     }
00553     lcd_data = lcd_data + mem_offset;   /* Point to the  relevant LCDDR */
00554 
00555     *lcd_data = *lcd_data | ( 1 << bit_offset);
00556 }
00557 
00558 /*---------------------------------------------------------------------------*/
00559 
00560 /**
00561  *  \brief This will clear any symbol on the Raven LCD.
00562  *
00563  *  \param symbol Specific symbol to clear from the LCD.
00564 */
00565 void
00566 lcd_symbol_clr(lcd_symbol_t symbol)
00567 {
00568     unsigned char offset;
00569     unsigned char setbit;
00570     volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
00571 
00572     /* symbol format = bbbnnnnn where b is bit and n is offset */
00573     setbit = (symbol >> 5);
00574     offset = (symbol & 0x1F);
00575     if ( offset >= 20 ){
00576         return;  /* data out of range of the LCD registers */
00577     }
00578 
00579     lcd_data = lcd_data + offset;       /* Point to the  relevant LCDDR */
00580 
00581     *lcd_data = *lcd_data & ~( 1 << setbit);
00582 }
00583 
00584 /*---------------------------------------------------------------------------*/
00585 
00586 /**
00587  *  \brief This will enable a group of symbols from the lcd_symbol_chart.
00588  *
00589  *  \param start Position of table to start from.
00590  *  \param count Number of symbols to enable from start position.
00591 */
00592 void
00593 lcd_symbol_set_group(int start, int count)
00594 {
00595     count = (start + count)>LCD_SYMBOL_COUNT ?
00596         LCD_SYMBOL_COUNT - start :
00597         count;
00598     int i;
00599 
00600     for(i=start; i<start+count; ++i){
00601         lcd_symbol_set(pgm_read_byte(&lcd_symbol_chart[i]));
00602     }
00603 }
00604 
00605 /*---------------------------------------------------------------------------*/
00606 
00607 /**
00608  *  \brief This will disable a group of symbols from the lcd_symbol_chart.
00609  *
00610  *  \param start Position of table to start from.
00611  *  \param count Number of symbols to disable from start position.
00612 */
00613 void
00614 lcd_symbol_clr_group(int start, int count)
00615 {
00616     count = (start + count)>LCD_SYMBOL_COUNT ?
00617         LCD_SYMBOL_COUNT - start :
00618         count;
00619     int i;
00620 
00621     for(i=start; i<count; ++i){
00622         lcd_symbol_clr(pgm_read_byte(&lcd_symbol_chart[i]));
00623     }
00624 }
00625 
00626 /*---------------------------------------------------------------------------*/
00627 
00628 /**
00629  *  \brief This will print a number to the LCD with the following parameters.
00630  *
00631  *  \param numb Number to display on LCD.
00632  *  \param negative Display negative sign in the next digit field.
00633  *  \param padding This pads the location to place the value on the LCD.
00634  *
00635  *  \return 0
00636 */
00637 static int
00638 lcd_num_print(uint16_t numb, bool negative, lcd_padding_t padding)
00639 {
00640     int i;
00641     for (i=0;i<4;/**/) {
00642         /* Get segments for this digit and print it */
00643         lcd_nmb_print_dig(pgm_read_byte(&seg_map[(numb&(0xF<<4*i))>>4*i]), i);
00644 
00645         /* If rest of number is zero */
00646         if (++i<4) {
00647             if (numb >> 4*i == 0) {
00648                 if (negative == true) { /* print a 'minus' in the next digit field */
00649                     lcd_nmb_print_dig(pgm_read_byte(&seg_map[(padding == LCD_NUM_PADDING_ZERO) ? LCD_SEV_SEG_INDEX_0 : LCD_SEV_SEG_INDEX_MINUS]), i++);
00650                     if (padding == LCD_NUM_PADDING_ZERO) {
00651                         lcd_symbol_set(LCD_SYMBOL_MINUS);
00652                     }
00653                 } else {
00654                     lcd_symbol_clr(LCD_SYMBOL_MINUS);
00655                 }
00656                 while (i<4){
00657                     lcd_nmb_print_dig(pgm_read_byte(&seg_map[(padding == LCD_NUM_PADDING_ZERO) ? LCD_SEV_SEG_INDEX_0 : LCD_SEV_SEG_INDEX_SPACE]), i++);
00658                 }
00659             }
00660         } else {
00661             if (negative == true) {
00662                 lcd_symbol_set(LCD_SYMBOL_MINUS);
00663             } else {
00664                 lcd_symbol_clr(LCD_SYMBOL_MINUS);
00665             }
00666         }
00667     }
00668     return 0;
00669 }
00670 
00671 /*---------------------------------------------------------------------------*/
00672 
00673 /**
00674  *  \brief This will print a number according to the segment map of the LCD.
00675  *
00676  *  \param val Number that is to be matched to appropriate segments.
00677  *  \param dig Segment to enable
00678 */
00679 static void
00680 lcd_nmb_print_dig(uint8_t val, int dig)
00681 {
00682     volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
00683     int j;
00684 
00685     for (j=0;j<7;++j){
00686         if (val & (1<<j)) {
00687             lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] |= (pgm_read_byte(&seg_inf[j])>>5)<<(dig*2);
00688         }
00689         else {
00690             lcd_data[pgm_read_byte(&seg_inf[j])&0x1F] &= ~((pgm_read_byte(&seg_inf[j])>>5)<<(dig*2));
00691         }
00692     }
00693 }
00694 
00695 /*---------------------------------------------------------------------------*/
00696 
00697 /**
00698  *  \brief This will scroll the test on the LCD.
00699  *
00700  *  \return 0
00701 */
00702 static int
00703 lcd_text_sl(void)
00704 {
00705     static int pos = 1;
00706     if (lcd_text[lcd_text_rd_ptr] == 0) {
00707         lcd_text_rd_ptr = 0;
00708         pos = 7;
00709     }
00710     else {
00711         if (pos){
00712             pos--;
00713         }
00714         else {
00715             lcd_text_rd_ptr++;
00716         }
00717     }
00718 
00719     lcd_text_put((char*)&lcd_text[lcd_text_rd_ptr], pos);
00720     return 0;
00721 }
00722 
00723 /*---------------------------------------------------------------------------*/
00724 
00725 /**
00726  *  \brief This will put test out to the LCD at a certain location padded with
00727  *  spaces.
00728  *
00729  *  \param s First character pointer to the string of test to print.
00730  *  \param pos Count of spaces entered before printing the text.
00731  *
00732  *  \return 0
00733 */
00734 static int
00735 lcd_text_put(const char* s, int pos)
00736 {
00737     int i;
00738 
00739     /* Pad with spaces in front if offset > 0 */
00740     for (i=1; i<pos; i++) {
00741          lcd_char_put(' ', i);
00742     }
00743 
00744     /* Print characters, overwrite with spaces at end if necessary */
00745     for ( i=pos; i<=7; ++i) {
00746         if (*s == 0) {
00747             lcd_char_put(' ', i);
00748         }
00749         else {
00750             lcd_char_put( (unsigned char)*s++, i);
00751         }
00752     }
00753     return 0;
00754 }
00755 
00756 /*---------------------------------------------------------------------------*/
00757 
00758 /**
00759  *  \brief This will put a single char out to the LCD by looking up the
00760  *  proper segments.
00761  *
00762  *  \param c Character to display on the LCD.
00763  *  \param pos This will add spaces for positioning the text on the LCD.
00764  *
00765  *  \return 0
00766 */
00767 static int
00768 lcd_char_put(unsigned char c, int pos)
00769 {
00770         unsigned int seg, segMask;
00771         unsigned char i;
00772         unsigned char mask, nibble, nibbleMask;
00773 
00774         volatile unsigned char* lcd_data = (volatile unsigned char*)0xEC;
00775     unsigned char lcd_reg;
00776 
00777     if (pos > 7){
00778       return EOF;
00779     }
00780 
00781         /* Lookup character table for segmet data */
00782         if (((c >= '*') && (c <= 'z')) || (c == ' ')){
00783                 if (c >= 'a' ){
00784             c &= ~0x20; /* c is in character_table. Convert to upper if necessarry. */
00785         }
00786         if (c == ' ') {
00787             c = 0x00;
00788         }
00789                 else {
00790             c -= '*';
00791         }
00792                 if ( c > 0x35 ){
00793                    return EOF;     /* c points outside array */
00794                 }
00795                 else{
00796                         seg = pgm_read_dword(&LCD_character_table[c]);
00797                 }
00798         }
00799         else {
00800                 return EOF;             /* ASCII code out of range */
00801         }
00802 
00803 
00804         /* Adjust mask according to digit */
00805         segMask = 0x4008;  /* masking out two bits */
00806 
00807         i = pos-1;              /*i used as pointer offset */
00808         i >>= 1;
00809         lcd_data += i;  /* Point to the first relevant LCDDR; i = {0,0,1,1,2,2} */
00810 
00811         i = 4;                  /*i used as loop counter */
00812         do{
00813         nibble = seg & 0x000F;
00814         nibbleMask = segMask & 0x000F;
00815 
00816         seg >>= 4;
00817         segMask >>= 4;
00818 
00819         if (pos & 0x01) {
00820             mask = 0xF0 | nibbleMask;
00821         }
00822         else {
00823             nibble <<= 4;
00824             mask = 0x0F | ( nibbleMask <<4 );
00825         }
00826         lcd_reg = *lcd_data;
00827         *lcd_data |= (lcd_reg & mask) | nibble;  /* Write new bit values */
00828 
00829         lcd_reg = *lcd_data;
00830         *lcd_data &= (lcd_reg & mask) | nibble;
00831 
00832         lcd_data += 5;
00833     } while ( --i );
00834 
00835     return 0;
00836 }
00837 
00838 /*---------------------------------------------------------------------------*/
00839 
00840 /**
00841  *  \brief This is the LCD Start of Frame Interrupt Subroutine.
00842  *
00843  *  This interrupt fires at the beginning of a new frame.
00844 */
00845 ISR
00846 (LCD_vect)
00847 {
00848     if (lcd_scroll_enable) {
00849         if (--lcd_scroll_prescale == 0) {
00850             lcd_text_sl();
00851             lcd_scroll_prescale = lcd_scroll_prescale_value;
00852         }
00853     }
00854 }
00855 
00856 /*---------------------------------------------------------------------------*/
00857 
00858 /**
00859  * \brief Turns the Raven nose LED on.
00860 */
00861 void
00862 led_on(void)
00863 {
00864     DDRB  |=  0x80;
00865     PORTB &= ~0x80;
00866 }
00867 
00868 /*---------------------------------------------------------------------------*/
00869 
00870 /**
00871  *  \brief Turns the Raven nose LED off.
00872 */
00873 void
00874 led_off(void)
00875 {
00876     DDRB &= ~0x80;
00877     PORTB |= 0x80;
00878 }
00879 
00880 /*---------------------------------------------------------------------------*/
00881 
00882 /**
00883  *  \brief This will add the passed in number to any of the four locations of
00884  *  the four digit segment display on the LCD.
00885  *
00886  *  \param numb Number to display.
00887  *  \param pos Position to display number.
00888 */
00889 void
00890 lcd_single_print_dig(uint8_t numb, uint8_t pos)
00891 {
00892     lcd_nmb_print_dig(pgm_read_byte(&seg_map[numb]), pos);
00893 }
00894 
00895 /** \}   */