| 6 | kaklik | 1 | // Change the following to change the clock frequency
 | 
        
           |  |  | 2 | #define CRYSTAL_FREQ    16000000
 | 
        
           |  |  | 3 | // Change the following to change between 16 or 20 column display
 | 
        
           |  |  | 4 | #define DISPLAY_COLS    20
 | 
        
           |  |  | 5 | // Speed units are "1" (nautical knots), "2" (metric kph), or "3" (statute mph)
 | 
        
           |  |  | 6 | #define SPEED_UNITS     1
 | 
        
           |  |  | 7 |   | 
        
           |  |  | 8 | /****************************************************************************
 | 
        
           |  |  | 9 | GPS18.c
 | 
        
           |  |  | 10 |   | 
        
           |  |  | 11 | This program receives NMEA-0183 data from a GPS and displays it.
 | 
        
           |  |  | 12 | Meant for large display version still in 16F876.
 | 
        
           |  |  | 13 | Three buttons
 | 
        
           |  |  | 14 | Automicaly resets if main loop stops (not the best solution, still don't know why it's stopping)
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | Next: don't display GPS screens unless GPS is active
 | 
        
           |  |  | 17 |       detect display needing reset
 | 
        
           |  |  | 18 |       preset data eeprom for first-time operation
 | 
        
           |  |  | 19 |       don't display init stuff if reseting from main loop
 | 
        
           |  |  | 20 |   | 
        
           |  |  | 21 |   | 
        
           |  |  | 22 |   | 
        
           |  |  | 23 |                  +5                       +5+5
 | 
        
           |  |  | 24 |                   |                        | |
 | 
        
           |  |  | 25 |                   20                      15 2
 | 
        
           |  |  | 26 |                 ----------             ----------
 | 
        
           |  |  | 27 | ~SerIn -----18-|          |-24-----11-|DB4 A Vdd |
 | 
        
           |  |  | 28 |                |          |-25-----12-|DB5       |
 | 
        
           |  |  | 29 |   ADC0 ------2-|          |-26-----13-|DB6       |
 | 
        
           |  |  | 30 |   ADC1 ------3-|  16F876  |-27-----14-|DB7     Vo| 3--
 | 
        
           |  |  | 31 |   ADC2 ------5-|          |           |    LCD   |    |
 | 
        
           |  |  | 32 |                |          |-14------6-|EN        |    |
 | 
        
           |  |  | 33 |        XTAL--9-|          |-15------4-|R/S       |    |
 | 
        
           |  |  | 34 |        XTAL-10-|          |-28-FET-16-|K         |    |
 | 
        
           |  |  | 35 |                |          |           |  RW  Vss |    |
 | 
        
           |  |  | 36 |  BUTTON 1---21-|          |            ----------     |
 | 
        
           |  |  | 37 |  BUTTON 2---22-|          |              1   5        |
 | 
        
           |  |  | 38 |  BUTTON 3---23-|          |              |   |        |
 | 
        
           |  |  | 39 |                |          |             Gnd Gnd       |
 | 
        
           |  |  | 40 |                |          |                           |
 | 
        
           |  |  | 41 |                |          |-11----------R/C-----------
 | 
        
           |  |  | 42 |                |          |
 | 
        
           |  |  | 43 |                |          |
 | 
        
           |  |  | 44 |                 ----------
 | 
        
           |  |  | 45 |                   8    19
 | 
        
           |  |  | 46 |                   |     |
 | 
        
           |  |  | 47 |                  Gnd   Gnd
 | 
        
           |  |  | 48 |   | 
        
           |  |  | 49 | ***************************************************************************/
 | 
        
           |  |  | 50 | #case
 | 
        
           |  |  | 51 | #include <16F876.h>
 | 
        
           |  |  | 52 | #include <jonsinc.h>
 | 
        
           |  |  | 53 | #device = *=16 ADC=10                /* allow RAM addresses over 255 */
 | 
        
           |  |  | 54 |   | 
        
           |  |  | 55 | #if ( ( CRYSTAL_FREQ < 4000000) || ( CRYSTAL_FREQ > 20000000 ) )
 | 
        
           |  |  | 56 | #error "CRYSTAL FREQ" not defined to between 8000000 and 20000000
 | 
        
           |  |  | 57 | #endif
 | 
        
           |  |  | 58 | #if ( ( DISPLAY_COLS != 16 ) && ( DISPLAY_COLS != 20 ) )
 | 
        
           |  |  | 59 | #error "DISPLAY COLS" not defined to 16 or 20
 | 
        
           |  |  | 60 | #endif
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 | // RMC_TIME = 1 per clock megahertz, rounded
 | 
        
           |  |  | 63 | #define RMC_TIME        CRYSTAL_FREQ/1000000
 | 
        
           |  |  | 64 |   | 
        
           |  |  | 65 | #define LCD_D0          PIN_B3
 | 
        
           |  |  | 66 | #define LCD_D1          PIN_B4
 | 
        
           |  |  | 67 | #define LCD_D2          PIN_B5
 | 
        
           |  |  | 68 | #define LCD_D3          PIN_B6
 | 
        
           |  |  | 69 | #define LCD_EN          PIN_C3
 | 
        
           |  |  | 70 | #define LCD_RS          PIN_C4
 | 
        
           |  |  | 71 | #define RX_IN           PIN_C7
 | 
        
           |  |  | 72 | #define BUTTON_1        PIN_B0
 | 
        
           |  |  | 73 | #define BUTTON_2        PIN_B1
 | 
        
           |  |  | 74 | #define BUTTON_3        PIN_B2
 | 
        
           |  |  | 75 | #define LCD_BACKLITE    PIN_B7
 | 
        
           |  |  | 76 | #define LINE_1          0x00
 | 
        
           |  |  | 77 | #define LINE_2          0x40
 | 
        
           |  |  | 78 | #if DISPLAY_COLS == 20
 | 
        
           |  |  | 79 | #define LINE_3          0x14
 | 
        
           |  |  | 80 | #define LINE_4          0x54
 | 
        
           |  |  | 81 | #endif
 | 
        
           |  |  | 82 | #if DISPLAY_COLS == 16
 | 
        
           |  |  | 83 | #define LINE_3          0x10
 | 
        
           |  |  | 84 | #define LINE_4          0x50
 | 
        
           |  |  | 85 | #endif
 | 
        
           |  |  | 86 | #define CLEAR_DISP      0x01
 | 
        
           |  |  | 87 | #define EOF             0x00
 | 
        
           |  |  | 88 | #define COMMA           ','
 | 
        
           |  |  | 89 | #define CR              13
 | 
        
           |  |  | 90 | #define SPACE           ' '
 | 
        
           |  |  | 91 | #define PERIOD          '.'
 | 
        
           |  |  | 92 | #define DEGREE          0xdf
 | 
        
           |  |  | 93 | #define DOLLAR          '$'
 | 
        
           |  |  | 94 | #define NULL            0
 | 
        
           |  |  | 95 | #define GPRMC_CODE      75
 | 
        
           |  |  | 96 | #define GPRMB_CODE      74
 | 
        
           |  |  | 97 | #define RX_BUFFER_SIZE  70
 | 
        
           |  |  | 98 | #define POSITION_SCREEN 1
 | 
        
           |  |  | 99 | #define WAYPOINT_SCREEN 2
 | 
        
           |  |  | 100 | #define BATTERY_SCREEN  3
 | 
        
           |  |  | 101 | #define HIDDEN_RMC      5
 | 
        
           |  |  | 102 | #define WARNING_MSG     0
 | 
        
           |  |  | 103 | #define NODATA_MSG      1
 | 
        
           |  |  | 104 | #define ACTIVITY_SYMBOL 0xFF
 | 
        
           |  |  | 105 | #define MAX_VOLTS       15
 | 
        
           |  |  | 106 | #define EEPROM_CONTRAST 0
 | 
        
           |  |  | 107 | #define EEPROM_INITIAL  1
 | 
        
           |  |  | 108 |   | 
        
           |  |  | 109 | /* Set the following define to "YES" to display XOR'ed GPS sentence code */
 | 
        
           |  |  | 110 | /* such as GPRMC and the display will read out the value of 74. */
 | 
        
           |  |  | 111 | #define GET_GPS_CODE    NO
 | 
        
           |  |  | 112 |   | 
        
           |  |  | 113 | #separate void Display ( void );
 | 
        
           |  |  | 114 | #separate void LCD_Init ( void );
 | 
        
           |  |  | 115 | #separate void LCD_SetPosition ( unsigned int cX );
 | 
        
           |  |  | 116 | #separate void LCD_PutChar ( unsigned int cX );
 | 
        
           |  |  | 117 | #separate void LCD_PutCmd ( unsigned int cX );
 | 
        
           |  |  | 118 | #separate void LCD_PulseEnable ( void );
 | 
        
           |  |  | 119 | #separate void LCD_SetData ( unsigned int cX );
 | 
        
           |  |  | 120 | #separate void SkipField ( char cCnt );
 | 
        
           |  |  | 121 | #separate char GetField ( void );
 | 
        
           |  |  | 122 | #separate void InitRxBuffer ( char cCode );
 | 
        
           |  |  | 123 | #separate char GetRxChar ( void );
 | 
        
           |  |  | 124 | #separate void DisplayLatLon ( void );
 | 
        
           |  |  | 125 | #separate void DisplayWaypoint ( void );
 | 
        
           |  |  | 126 | #separate void DisplayLatitude ( char cLine );
 | 
        
           |  |  | 127 | #separate void DisplayLongitude ( char cLine );
 | 
        
           |  |  | 128 | #separate void DisplayHeading ( char cLine );
 | 
        
           |  |  | 129 | #separate void DisplaySpeed ( char cLine );
 | 
        
           |  |  | 130 | #separate void DisplaySteer ( char cLine, char cX );
 | 
        
           |  |  | 131 | #separate void DisplayWaypointName ( char cLine, char cX );
 | 
        
           |  |  | 132 | #separate void DisplayDistance ( char cLine, char cX );
 | 
        
           |  |  | 133 | #separate void DisplayBearing ( char cLine, char cX );
 | 
        
           |  |  | 134 | #separate void GetUtcAndMagVar ( void );
 | 
        
           |  |  | 135 | #separate long TrueToMag ( long iH );
 | 
        
           |  |  | 136 | #separate long FieldFiveToLong ( void );
 | 
        
           |  |  | 137 | #separate void DisplayAnalog ( void );
 | 
        
           |  |  | 138 | #separate void DisplayScaledVoltage ( long iV, char cScale );
 | 
        
           |  |  | 139 | #separate void DisplayArrival ( char cLine );
 | 
        
           |  |  | 140 | #separate void DisplayMessage ( char cMsgNum );
 | 
        
           |  |  | 141 | #separate void DisplayTemplateLatLon ( void );
 | 
        
           |  |  | 142 | #separate void DisplayTemplateWaypoint ( void );
 | 
        
           |  |  | 143 | #separate void DisplayTemplateAnalog ( void );
 | 
        
           |  |  | 144 | #separate void Delay5mS ( char cCnt );
 | 
        
           |  |  | 145 |   | 
        
           |  |  | 146 | #fuses HS, NOPROTECT, PUT, NOWDT, BROWNOUT, NOLVP, NOCPD
 | 
        
           |  |  | 147 | #use standard_io ( A )
 | 
        
           |  |  | 148 | #use standard_io ( B )
 | 
        
           |  |  | 149 | #use standard_io ( C )
 | 
        
           |  |  | 150 | #use delay ( clock = CRYSTAL_FREQ )
 | 
        
           |  |  | 151 | #use rs232 ( baud=4800, xmit=PIN_C6, rcv=PIN_C7, ERRORS )    // XMIT must be assigned to enable hardward USART
 | 
        
           |  |  | 152 | #priority RDA, RTCC, EXT
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 | static char cC [ 10 ];      // local buffer
 | 
        
           |  |  | 155 | static char cTimeOut;
 | 
        
           |  |  | 156 | static char cRxBuffer [ RX_BUFFER_SIZE ];    // Fifo
 | 
        
           |  |  | 157 | static char cRxByteCnt;         // Number of bytes in the recv fifo
 | 
        
           |  |  | 158 | static char *cRxBufferWritePtr;    // Pointers for the Rx buffer
 | 
        
           |  |  | 159 | static char *cRxBufferReadPtr;
 | 
        
           |  |  | 160 | static char cRxIsrState, cRxMsgTypeReceived, cRxMsgTypeDesired;
 | 
        
           |  |  | 161 | static char cRxMsgReady, cReceiveFlag;
 | 
        
           |  |  | 162 | static long iVar, iLastRange, iTimeOut;
 | 
        
           |  |  | 163 | static char cVarDir, cScreenChanged, cAdcDone;
 | 
        
           |  |  | 164 | static char cButtonPressed, cSkip, cButtonCount;
 | 
        
           |  |  | 165 | static char cScreen, cSavedScreen, cRmcTimer1, cRmcTimer2;
 | 
        
           |  |  | 166 | static char cToFrom [ 5 ], cIndicator, cIllumination, cRxErrorFlag;
 | 
        
           |  |  | 167 | static char cDone, cContrast;
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 | /*******************************************************************/
 | 
        
           |  |  | 170 | #int_ad
 | 
        
           |  |  | 171 | void AdcInterrupt ( void )
 | 
        
           |  |  | 172 |     {
 | 
        
           |  |  | 173 |     /* Gets here when ADC is done conversion, sets flag */
 | 
        
           |  |  | 174 |     cAdcDone = YES;
 | 
        
           |  |  | 175 |     }
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 | #int_timer1
 | 
        
           |  |  | 178 | void Timer1Interrupt ( void )
 | 
        
           |  |  | 179 |     {
 | 
        
           |  |  | 180 |     /* Periodic RMC data timer, gets here every 204mS */
 | 
        
           |  |  | 181 |     /* This routine forces RMC to run every 10 minutes to update */
 | 
        
           |  |  | 182 |     /* magnetic variation */
 | 
        
           |  |  | 183 |     if ( cRmcTimer1-- == 0 )
 | 
        
           |  |  | 184 |         {
 | 
        
           |  |  | 185 |         cRmcTimer1 = 255;               // 52 seconds @ 10.240MHz
 | 
        
           |  |  | 186 |         if ( cRmcTimer2-- == 0 )
 | 
        
           |  |  | 187 |             {
 | 
        
           |  |  | 188 |             cRmcTimer2 = RMC_TIME;      // triggers every 10 minutes
 | 
        
           |  |  | 189 |             cSavedScreen = cScreen;     // save current screen type
 | 
        
           |  |  | 190 |             cScreen = HIDDEN_RMC;       // force RMC to run
 | 
        
           |  |  | 191 |             }
 | 
        
           |  |  | 192 |         }
 | 
        
           |  |  | 193 |     }
 | 
        
           |  |  | 194 |   | 
        
           |  |  | 195 | #int_rtcc
 | 
        
           |  |  | 196 | void Timer0Interrupt ( void )
 | 
        
           |  |  | 197 |     {
 | 
        
           |  |  | 198 |     // Gets here every 16.4mS at 8MHz, 8.2mS at 16MHz
 | 
        
           |  |  | 199 |     // Handles data timeout and switch debounce.
 | 
        
           |  |  | 200 |   | 
        
           |  |  | 201 |     // DATA TIMEOUT TIMER
 | 
        
           |  |  | 202 |     if ( cTimeOut != 0 )
 | 
        
           |  |  | 203 |         {
 | 
        
           |  |  | 204 |         cTimeOut--;
 | 
        
           |  |  | 205 |         }
 | 
        
           |  |  | 206 |   | 
        
           |  |  | 207 |     // This timer is preset by the normal operating loop, unless the operating
 | 
        
           |  |  | 208 |     // loop stops looping, at which point iTimeOut finally decrements to zero
 | 
        
           |  |  | 209 |     // and resets CPU.
 | 
        
           |  |  | 210 |     if ( iTimeOut != 0 )
 | 
        
           |  |  | 211 |         {
 | 
        
           |  |  | 212 |         iTimeOut--;
 | 
        
           |  |  | 213 |         }
 | 
        
           |  |  | 214 |     else
 | 
        
           |  |  | 215 |         {
 | 
        
           |  |  | 216 |         reset_cpu();                // force reset
 | 
        
           |  |  | 217 |         }
 | 
        
           |  |  | 218 |   | 
        
           |  |  | 219 |     if ( input ( BUTTON_2 ) == LOW )  // if button still pressed
 | 
        
           |  |  | 220 |         {
 | 
        
           |  |  | 221 |         cScreen = WAYPOINT_SCREEN;
 | 
        
           |  |  | 222 |         cSkip = YES;                // skip out of anything in process
 | 
        
           |  |  | 223 |         cScreenChanged = YES;       // repaint complete screen
 | 
        
           |  |  | 224 |         }
 | 
        
           |  |  | 225 |   | 
        
           |  |  | 226 |     if ( input ( BUTTON_3 ) == LOW )  // if button still pressed
 | 
        
           |  |  | 227 |         {
 | 
        
           |  |  | 228 |         cScreen = BATTERY_SCREEN;
 | 
        
           |  |  | 229 |         cSkip = YES;                // skip out of anything in process
 | 
        
           |  |  | 230 |         cScreenChanged = YES;       // repaint complete screen
 | 
        
           |  |  | 231 |         }
 | 
        
           |  |  | 232 |   | 
        
           |  |  | 233 |     // SWITCH DEBOUNCE
 | 
        
           |  |  | 234 |     if ( input ( BUTTON_1 ) == LOW )  // if button still pressed
 | 
        
           |  |  | 235 |         {
 | 
        
           |  |  | 236 |         if ( cButtonCount < 255 )   // hold at 255
 | 
        
           |  |  | 237 |             {
 | 
        
           |  |  | 238 |             cButtonCount++;         // otherwise increment
 | 
        
           |  |  | 239 |             }
 | 
        
           |  |  | 240 |         }
 | 
        
           |  |  | 241 |     else            // if button is unpressed
 | 
        
           |  |  | 242 |         {
 | 
        
           |  |  | 243 |         if ( cButtonCount > 2 )     // filter out glitches
 | 
        
           |  |  | 244 |             {
 | 
        
           |  |  | 245 |             //If button press is greater than 3.3 seconds, cold reset
 | 
        
           |  |  | 246 |             if ( cButtonCount == 255 )
 | 
        
           |  |  | 247 |                 {
 | 
        
           |  |  | 248 |                 reset_cpu();
 | 
        
           |  |  | 249 |                 }
 | 
        
           |  |  | 250 |             if ( ( cButtonCount > 57 ) && ( cButtonCount < 255 ) )
 | 
        
           |  |  | 251 |                 {
 | 
        
           |  |  | 252 |                 if ( cScreen != HIDDEN_RMC )       // if not in the middle of getting magnetic variation
 | 
        
           |  |  | 253 |                     {
 | 
        
           |  |  | 254 |                     // cIllumination ^= ON;
 | 
        
           |  |  | 255 |                     output_bit ( LCD_BACKLITE, cIllumination ^= ON );
 | 
        
           |  |  | 256 |                     }
 | 
        
           |  |  | 257 |                 }
 | 
        
           |  |  | 258 |             // If button press is less than 0.5 second
 | 
        
           |  |  | 259 |             if ( cButtonCount <= 57 )
 | 
        
           |  |  | 260 |                 {
 | 
        
           |  |  | 261 |                 if ( cScreen != HIDDEN_RMC )       // if not in the middle of getting magnetic variation
 | 
        
           |  |  | 262 |                     {
 | 
        
           |  |  | 263 |                     //if ( cScreen++ >= BATTERY_SCREEN )   // increment to next screen
 | 
        
           |  |  | 264 |                         {
 | 
        
           |  |  | 265 |                         cScreen = POSITION_SCREEN;                    // wrap
 | 
        
           |  |  | 266 |                         }
 | 
        
           |  |  | 267 |                     cSkip = YES;                // skip out of anything in process
 | 
        
           |  |  | 268 |                     cScreenChanged = YES;       // repaint complete screen
 | 
        
           |  |  | 269 |                     }
 | 
        
           |  |  | 270 |                 }
 | 
        
           |  |  | 271 |             }
 | 
        
           |  |  | 272 |         cButtonCount = 0;       // restart
 | 
        
           |  |  | 273 |         }
 | 
        
           |  |  | 274 |     }
 | 
        
           |  |  | 275 |   | 
        
           |  |  | 276 | #int_rda
 | 
        
           |  |  | 277 | void SerialInterrupt ( void )
 | 
        
           |  |  | 278 |     {
 | 
        
           |  |  | 279 |     /*
 | 
        
           |  |  | 280 |     Reads incoming data from the USART and puts in in a rolling buffer
 | 
        
           |  |  | 281 |     ( but in this application, it should never roll.)
 | 
        
           |  |  | 282 |     If the buffer is full, this routine just discards the received byte.
 | 
        
           |  |  | 283 |     Not checking the LRC byte at the end of the NMEA-0183 sentence.
 | 
        
           |  |  | 284 |     */
 | 
        
           |  |  | 285 |     char cChar;
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 |     if ( rs232_errors & 0x04 )  // get framing error bit from Rx status reg
 | 
        
           |  |  | 288 |         {
 | 
        
           |  |  | 289 |         cRxErrorFlag = ON;
 | 
        
           |  |  | 290 |         }
 | 
        
           |  |  | 291 |     cChar = getchar();       // get char from UART, clear any errors
 | 
        
           |  |  | 292 |   | 
        
           |  |  | 293 |     if ( cRxByteCnt == RX_BUFFER_SIZE ) // is recv fifo full ???
 | 
        
           |  |  | 294 |         {
 | 
        
           |  |  | 295 |         goto done;
 | 
        
           |  |  | 296 |         }
 | 
        
           |  |  | 297 |     switch ( cRxIsrState )
 | 
        
           |  |  | 298 |         {
 | 
        
           |  |  | 299 |         case 0:
 | 
        
           |  |  | 300 |             {
 | 
        
           |  |  | 301 |             if ( cChar == DOLLAR )  // if start of NMEA0183 message
 | 
        
           |  |  | 302 |                 {
 | 
        
           |  |  | 303 |                 cRxByteCnt = 0;     // reset byte count
 | 
        
           |  |  | 304 |                 cReceiveFlag = OFF;     // default to off
 | 
        
           |  |  | 305 |                 cRxMsgTypeReceived = NULL;  // set hashed value to null
 | 
        
           |  |  | 306 |                 cRxIsrState++;                 // next state
 | 
        
           |  |  | 307 |                 }
 | 
        
           |  |  | 308 |             break;
 | 
        
           |  |  | 309 |             }
 | 
        
           |  |  | 310 |         case 1:                           // five type characters to obtain
 | 
        
           |  |  | 311 |         case 2:
 | 
        
           |  |  | 312 |         case 3:
 | 
        
           |  |  | 313 |         case 4:
 | 
        
           |  |  | 314 |         case 5:
 | 
        
           |  |  | 315 |             {
 | 
        
           |  |  | 316 |             cRxMsgTypeReceived ^= cChar;      // hash in msg type
 | 
        
           |  |  | 317 |             if ( cRxIsrState++ == 5 )        // if time to check message type
 | 
        
           |  |  | 318 |                 {
 | 
        
           |  |  | 319 |                 if ( cRxMsgTypeReceived == cRxMsgTypeDesired )  // if good
 | 
        
           |  |  | 320 |                     {
 | 
        
           |  |  | 321 |                     cReceiveFlag = YES;            // enable receiving
 | 
        
           |  |  | 322 |                     cRxBufferWritePtr = cRxBuffer;    // reset to beginning of buffer
 | 
        
           |  |  | 323 |                     }
 | 
        
           |  |  | 324 |                 else                    // don't want this message
 | 
        
           |  |  | 325 |                     {
 | 
        
           |  |  | 326 |                     cRxIsrState = 0;    // reset to look for next msg
 | 
        
           |  |  | 327 |                     }
 | 
        
           |  |  | 328 |                 }
 | 
        
           |  |  | 329 |             break;
 | 
        
           |  |  | 330 |             }
 | 
        
           |  |  | 331 |         case 6:
 | 
        
           |  |  | 332 |             {
 | 
        
           |  |  | 333 |             /* Case 6 skips the comma character following msg type */
 | 
        
           |  |  | 334 |             cRxIsrState++;
 | 
        
           |  |  | 335 |             break;
 | 
        
           |  |  | 336 |             }
 | 
        
           |  |  | 337 |         default:                          // remainder of characters
 | 
        
           |  |  | 338 |             {
 | 
        
           |  |  | 339 |             if ( cReceiveFlag == YES )        // if this message is wanted
 | 
        
           |  |  | 340 |                 {
 | 
        
           |  |  | 341 |                 *cRxBufferWritePtr = cChar;     // put char in fifo
 | 
        
           |  |  | 342 |                 cRxBufferWritePtr++;            // increment pointer
 | 
        
           |  |  | 343 |                 if ( cRxBufferWritePtr == ( cRxBuffer + RX_BUFFER_SIZE ) ) // pointer past end ?
 | 
        
           |  |  | 344 |                     {
 | 
        
           |  |  | 345 |                     cRxBufferWritePtr = cRxBuffer;      // set pointer to start of fifo
 | 
        
           |  |  | 346 |                     }
 | 
        
           |  |  | 347 |                 cRxByteCnt++;              // Increment byte count
 | 
        
           |  |  | 348 |                 if ( cChar == CR )
 | 
        
           |  |  | 349 |                     {
 | 
        
           |  |  | 350 |                     cRxMsgReady = YES;         // signal that message is ready
 | 
        
           |  |  | 351 |                     cReceiveFlag = NO;      // no more receive
 | 
        
           |  |  | 352 |                     }
 | 
        
           |  |  | 353 |                 }
 | 
        
           |  |  | 354 |             }
 | 
        
           |  |  | 355 |         }
 | 
        
           |  |  | 356 |     done:;
 | 
        
           |  |  | 357 |     }
 | 
        
           |  |  | 358 |   | 
        
           |  |  | 359 | /*******************************************************************/
 | 
        
           |  |  | 360 |   | 
        
           |  |  | 361 | void main ( void )
 | 
        
           |  |  | 362 |     {
 | 
        
           |  |  | 363 |     char cX;
 | 
        
           |  |  | 364 |   | 
        
           |  |  | 365 |     iTimeOut = 65535;                       // default to very long to get by init
 | 
        
           |  |  | 366 |     /* INITIALIZE */
 | 
        
           |  |  | 367 |     output_float ( RX_IN );             // ensure Rx input is HiZ
 | 
        
           |  |  | 368 |     output_float ( BUTTON_1 );          // ensure switch input is HiZ
 | 
        
           |  |  | 369 |     output_float ( BUTTON_2 );          // ensure switch input is HiZ
 | 
        
           |  |  | 370 |     output_float ( BUTTON_3 );          // ensure switch input is HiZ
 | 
        
           |  |  | 371 |     output_low ( LCD_BACKLITE );        // turn off backlighting
 | 
        
           |  |  | 372 |     port_b_pullups ( ON );              // enable pullups on switches
 | 
        
           |  |  | 373 |   | 
        
           |  |  | 374 |     // GET SAVED SETTINGS
 | 
        
           |  |  | 375 |     cContrast = read_eeprom ( EEPROM_CONTRAST );        // get stored value
 | 
        
           |  |  | 376 |   | 
        
           |  |  | 377 |     // PWM is for display contrast
 | 
        
           |  |  | 378 |     setup_ccp2 ( CCP_PWM );                     // set for PWM mode
 | 
        
           |  |  | 379 |     //The cycle time will be (1/clock)*4*t2div*(period+1)
 | 
        
           |  |  | 380 |     // 1/8000000 * 4 * 1 * 128 = 51.2uS = 19.5KHz
 | 
        
           |  |  | 381 |     setup_timer_2 ( T2_DIV_BY_1, 255, 1 );      // set PWM period
 | 
        
           |  |  | 382 |     // duty cycle = value*(1/clock)*t2div
 | 
        
           |  |  | 383 |     // 10 * 1/8000000 * 1 = 1.2uS
 | 
        
           |  |  | 384 |     set_pwm2_duty ( cContrast );                // set contrast duty cycle
 | 
        
           |  |  | 385 |   | 
        
           |  |  | 386 |     // SETUP TIMER 0
 | 
        
           |  |  | 387 |     // Need 8-bit Timer0 to roll over every 13mS, approximately.
 | 
        
           |  |  | 388 |     // Roll time = 256 * 1 / ( clock_freq / prescaler setting / 4 )
 | 
        
           |  |  | 389 |     #if CRYSTAL_FREQ >= 15000000
 | 
        
           |  |  | 390 |     setup_counters ( RTCC_INTERNAL, RTCC_DIV_256 );   // ~13mS timer wrap
 | 
        
           |  |  | 391 |     #elif CRYSTAL_FREQ >= 8000000
 | 
        
           |  |  | 392 |     setup_counters ( RTCC_INTERNAL, RTCC_DIV_128 );   // ~13mS timer wrap
 | 
        
           |  |  | 393 |     #elif CRYSTAL_FREQ < 8000000
 | 
        
           |  |  | 394 |     setup_counters ( RTCC_INTERNAL, RTCC_DIV_64 );    // ~13mS timer wrap
 | 
        
           |  |  | 395 |     #endif
 | 
        
           |  |  | 396 |   | 
        
           |  |  | 397 |     // Timer 1 roll time = 65536 * 1 / ( clock_freq / prescaler setting / 4 )
 | 
        
           |  |  | 398 |     setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );    // 16-bit timer
 | 
        
           |  |  | 399 |   | 
        
           |  |  | 400 |     setup_adc_ports ( RA0_RA1_RA3_ANALOG );  /* these three statements set up the ADC */
 | 
        
           |  |  | 401 |     setup_adc ( ADC_CLOCK_INTERNAL );
 | 
        
           |  |  | 402 |     cIllumination = OFF;
 | 
        
           |  |  | 403 |   | 
        
           |  |  | 404 |     LCD_Init();                        // set up LCD for 4-wire bus, etc.
 | 
        
           |  |  | 405 |   | 
        
           |  |  | 406 |     /* INIT MESSAGE */
 | 
        
           |  |  | 407 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 408 |     LCD_SetPosition ( LINE_1 + 0 );
 | 
        
           |  |  | 409 |     printf ( LCD_PutChar, "   Northern Light   " );   // welcome screen
 | 
        
           |  |  | 410 |     LCD_SetPosition ( LINE_2 + 2 );
 | 
        
           |  |  | 411 |     printf ( LCD_PutChar, "Monitor/Repeater" );
 | 
        
           |  |  | 412 |     LCD_SetPosition ( LINE_3 + 3 );
 | 
        
           |  |  | 413 |     printf ( LCD_PutChar, "v18   06/21/03" );
 | 
        
           |  |  | 414 |     LCD_SetPosition ( LINE_4 + 5 );
 | 
        
           |  |  | 415 |     printf ( LCD_PutChar, "c Jon Fick" );
 | 
        
           |  |  | 416 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 417 |     LCD_SetPosition ( LINE_1 + 0);
 | 
        
           |  |  | 418 |     printf ( LCD_PutChar, " Northern Light " );       // welcome screen
 | 
        
           |  |  | 419 |     LCD_SetPosition ( LINE_2 + 2 );
 | 
        
           |  |  | 420 |     printf ( LCD_PutChar, "GPS Repeater" );
 | 
        
           |  |  | 421 |     LCD_SetPosition ( LINE_3 + 1 );
 | 
        
           |  |  | 422 |     printf ( LCD_PutChar, "v18   06/21/03" );
 | 
        
           |  |  | 423 |     LCD_SetPosition ( LINE_4 + 3 );
 | 
        
           |  |  | 424 |     printf ( LCD_PutChar, "c Jon Fick" );
 | 
        
           |  |  | 425 |     #endif
 | 
        
           |  |  | 426 |     delay_ms ( 1000 );
 | 
        
           |  |  | 427 |   | 
        
           |  |  | 428 |     /* INSTRUCTION MESSAGE */
 | 
        
           |  |  | 429 |     LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 430 |     LCD_SetPosition ( LINE_1 + 0 );
 | 
        
           |  |  | 431 |     printf ( LCD_PutChar, "BUTTONS:" );
 | 
        
           |  |  | 432 |     LCD_SetPosition ( LINE_2 + 0 );
 | 
        
           |  |  | 433 |     printf ( LCD_PutChar, "<-- Lat/Lon" );
 | 
        
           |  |  | 434 |     LCD_SetPosition ( LINE_3 + 0 );
 | 
        
           |  |  | 435 |     printf ( LCD_PutChar, "<-- Waypoint" );
 | 
        
           |  |  | 436 |     LCD_SetPosition ( LINE_4 + 0 );
 | 
        
           |  |  | 437 |     printf ( LCD_PutChar, "<-- Battery" );
 | 
        
           |  |  | 438 |     delay_ms ( 2000 );
 | 
        
           |  |  | 439 |   | 
        
           |  |  | 440 |     /* SETUP MODE */
 | 
        
           |  |  | 441 |     if ( input ( BUTTON_1 ) == LOW )  // if button is pressed
 | 
        
           |  |  | 442 |         {
 | 
        
           |  |  | 443 |         LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 444 |         LCD_SetPosition ( LINE_1 + 0 );
 | 
        
           |  |  | 445 |         printf ( LCD_PutChar, "Set contrast:" );
 | 
        
           |  |  | 446 |         LCD_SetPosition ( LINE_2 + 0 );
 | 
        
           |  |  | 447 |         printf ( LCD_PutChar, "<-- More" );
 | 
        
           |  |  | 448 |         LCD_SetPosition ( LINE_3 + 0 );
 | 
        
           |  |  | 449 |         printf ( LCD_PutChar, "<-- DONE" );
 | 
        
           |  |  | 450 |         LCD_SetPosition ( LINE_4 + 0 );
 | 
        
           |  |  | 451 |         printf ( LCD_PutChar, "<-- Less" );
 | 
        
           |  |  | 452 |         while ( input ( BUTTON_1 ) == LOW );    // wait for switch to be released after entering SETUP mode
 | 
        
           |  |  | 453 |         cContrast = 120;          // start at full contrast
 | 
        
           |  |  | 454 |         cDone = NO;
 | 
        
           |  |  | 455 |         while ( cDone == NO )
 | 
        
           |  |  | 456 |             {
 | 
        
           |  |  | 457 |             set_pwm2_duty ( cContrast );        // update contrast
 | 
        
           |  |  | 458 |             if ( input ( BUTTON_1 ) == LOW )
 | 
        
           |  |  | 459 |                 {
 | 
        
           |  |  | 460 |                 if ( cContrast > 0 )
 | 
        
           |  |  | 461 |                     {
 | 
        
           |  |  | 462 |                     cContrast--;            // more
 | 
        
           |  |  | 463 |                     }
 | 
        
           |  |  | 464 |                 }
 | 
        
           |  |  | 465 |             if ( input ( BUTTON_2 ) == LOW )
 | 
        
           |  |  | 466 |                 {
 | 
        
           |  |  | 467 |                 cDone = YES;                // done
 | 
        
           |  |  | 468 |                 }
 | 
        
           |  |  | 469 |             if ( input ( BUTTON_3 ) == LOW )
 | 
        
           |  |  | 470 |                 {
 | 
        
           |  |  | 471 |                 if ( cContrast < 255 )
 | 
        
           |  |  | 472 |                     {
 | 
        
           |  |  | 473 |                     cContrast++;        // less
 | 
        
           |  |  | 474 |                     }
 | 
        
           |  |  | 475 |                 }
 | 
        
           |  |  | 476 |             delay_ms ( 30 );                   // autorepeat
 | 
        
           |  |  | 477 |             }
 | 
        
           |  |  | 478 |         write_eeprom ( EEPROM_CONTRAST, cContrast );    // save CONTRAST to EEPROM
 | 
        
           |  |  | 479 |   | 
        
           |  |  | 480 |         LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 481 |         LCD_SetPosition ( LINE_2 + 0 );
 | 
        
           |  |  | 482 |         printf ( LCD_PutChar, "<- Press initial" );
 | 
        
           |  |  | 483 |         LCD_SetPosition ( LINE_3 + 0 );
 | 
        
           |  |  | 484 |         printf ( LCD_PutChar, "   bootup screen" );
 | 
        
           |  |  | 485 |         while ( input ( BUTTON_1 ) == LOW );  // wait until button not pressed
 | 
        
           |  |  | 486 |         cX = POSITION_SCREEN;
 | 
        
           |  |  | 487 |         while ( TRUE )
 | 
        
           |  |  | 488 |             {
 | 
        
           |  |  | 489 |             LCD_SetPosition ( LINE_4 + 3 );
 | 
        
           |  |  | 490 |             switch ( cX )
 | 
        
           |  |  | 491 |                 {
 | 
        
           |  |  | 492 |                 case POSITION_SCREEN:
 | 
        
           |  |  | 493 |                     {
 | 
        
           |  |  | 494 |                     printf ( LCD_PutChar, "POSITION " );
 | 
        
           |  |  | 495 |                     break;
 | 
        
           |  |  | 496 |                     }
 | 
        
           |  |  | 497 |                 case WAYPOINT_SCREEN:
 | 
        
           |  |  | 498 |                     {
 | 
        
           |  |  | 499 |                     printf ( LCD_PutChar, "WAYPOINT " );
 | 
        
           |  |  | 500 |                     break;
 | 
        
           |  |  | 501 |                     }
 | 
        
           |  |  | 502 |                 case BATTERY_SCREEN:
 | 
        
           |  |  | 503 |                     {
 | 
        
           |  |  | 504 |                     printf ( LCD_PutChar, "BATTERY  " );
 | 
        
           |  |  | 505 |                     break;
 | 
        
           |  |  | 506 |                     }
 | 
        
           |  |  | 507 |                 }
 | 
        
           |  |  | 508 |             delay_ms ( 750 );
 | 
        
           |  |  | 509 |             if ( input ( BUTTON_1 ) == LOW )  // if button is pressed
 | 
        
           |  |  | 510 |                 {
 | 
        
           |  |  | 511 |                 write_eeprom ( EEPROM_INITIAL, cX );   // save screen number to EEPROM
 | 
        
           |  |  | 512 |                 break;
 | 
        
           |  |  | 513 |                 }
 | 
        
           |  |  | 514 |             if ( cX++ == BATTERY_SCREEN )
 | 
        
           |  |  | 515 |                 {
 | 
        
           |  |  | 516 |                 cX = POSITION_SCREEN;
 | 
        
           |  |  | 517 |                 }
 | 
        
           |  |  | 518 |             }
 | 
        
           |  |  | 519 |         LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 520 |         }
 | 
        
           |  |  | 521 |   | 
        
           |  |  | 522 |     /* This IF/ENDIF is a tool for getting the $GP... codes */
 | 
        
           |  |  | 523 |     /* that are used in the switch/case in the main loop. */
 | 
        
           |  |  | 524 |     #if ( GET_GPS_CODE == YES )
 | 
        
           |  |  | 525 |     printf ( LCD_PutChar, "%u", 'G'^'P'^'R'^'M'^'B');
 | 
        
           |  |  | 526 |     while ( TRUE );
 | 
        
           |  |  | 527 |     #endif
 | 
        
           |  |  | 528 |   | 
        
           |  |  | 529 |     /* INTERRUPTS */
 | 
        
           |  |  | 530 |     ext_int_edge ( H_TO_L );            // set falling edge ext interrupt
 | 
        
           |  |  | 531 |     enable_interrupts ( INT_TIMER1 );   // enable Timer1 interrupt
 | 
        
           |  |  | 532 |     enable_interrupts ( INT_RDA );      // enable serial interrupt
 | 
        
           |  |  | 533 |     enable_interrupts ( INT_RTCC );     // enable Timer0 interrupt
 | 
        
           |  |  | 534 |     enable_interrupts ( INT_AD );       // enable ADC interrupt
 | 
        
           |  |  | 535 |     enable_interrupts ( GLOBAL );       // enable all interrupts
 | 
        
           |  |  | 536 |   | 
        
           |  |  | 537 |     /* VARIABLES */
 | 
        
           |  |  | 538 |     iVar = NULL;                        // default, no variation yet
 | 
        
           |  |  | 539 |     cVarDir = SPACE;                    // default, no variation yet
 | 
        
           |  |  | 540 |     cRmcTimer1 = 255;                   // initialize to 52 seconds
 | 
        
           |  |  | 541 |     cRmcTimer2 = RMC_TIME;              // trigger forced RMC after 10 minutes
 | 
        
           |  |  | 542 |     cScreen = HIDDEN_RMC;               // default screen, get magnetic variation first
 | 
        
           |  |  | 543 |     cSavedScreen = read_eeprom ( EEPROM_INITIAL ); // restore initial screen
 | 
        
           |  |  | 544 |     iLastRange = 65535;                 // make max by default
 | 
        
           |  |  | 545 |     strcpy ( cToFrom, "  " );           // blank by default
 | 
        
           |  |  | 546 |     cScreenChanged = YES;
 | 
        
           |  |  | 547 |     cIndicator = 0;
 | 
        
           |  |  | 548 |     cButtonCount = 0;
 | 
        
           |  |  | 549 |     cButtonPressed = NO;
 | 
        
           |  |  | 550 |     cRxErrorFlag = OFF;
 | 
        
           |  |  | 551 |   | 
        
           |  |  | 552 |     /* MAIN LOOP */
 | 
        
           |  |  | 553 |     while ( TRUE )
 | 
        
           |  |  | 554 |         {
 | 
        
           |  |  | 555 |         cTimeOut = 188;        // 231 * 0.013mS = 3 seconds
 | 
        
           |  |  | 556 |         switch ( cScreen )
 | 
        
           |  |  | 557 |             {
 | 
        
           |  |  | 558 |             case HIDDEN_RMC:
 | 
        
           |  |  | 559 |                 {
 | 
        
           |  |  | 560 |                 InitRxBuffer( GPRMC_CODE );     // set code and turn on serial interrupt
 | 
        
           |  |  | 561 |                 while ( ( cRxMsgReady == NO ) && ( cTimeOut != 0 ) );
 | 
        
           |  |  | 562 |                 disable_interrupts ( INT_RDA );         // ignore rest of messages
 | 
        
           |  |  | 563 |                 if ( cTimeOut != 0 )            // if not timed out
 | 
        
           |  |  | 564 |                     {
 | 
        
           |  |  | 565 |                     GetUtcAndMagVar();             // get and store the magnetic variation
 | 
        
           |  |  | 566 |                     }
 | 
        
           |  |  | 567 |                 cScreen = cSavedScreen;         // revert to previous screen
 | 
        
           |  |  | 568 |                 break;
 | 
        
           |  |  | 569 |                 }
 | 
        
           |  |  | 570 |             case POSITION_SCREEN:
 | 
        
           |  |  | 571 |                 {
 | 
        
           |  |  | 572 |                 if ( cScreenChanged == YES )
 | 
        
           |  |  | 573 |                     {
 | 
        
           |  |  | 574 |                     disable_interrupts ( INT_RDA );
 | 
        
           |  |  | 575 |                     cScreenChanged = NO;
 | 
        
           |  |  | 576 |                     cSkip = NO;
 | 
        
           |  |  | 577 |                     LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 578 |                     DisplayTemplateLatLon();
 | 
        
           |  |  | 579 |                     enable_interrupts ( INT_RDA );
 | 
        
           |  |  | 580 |                     }
 | 
        
           |  |  | 581 |                 InitRxBuffer( GPRMC_CODE );     // set code and turn on serial interrupt
 | 
        
           |  |  | 582 |                 while ( ( cRxMsgReady == NO ) && ( cTimeOut != 0 ) && ( cScreenChanged != YES ) );
 | 
        
           |  |  | 583 |                 disable_interrupts ( INT_RDA );         // ignore rest of messages
 | 
        
           |  |  | 584 |                 if ( cScreenChanged == NO )
 | 
        
           |  |  | 585 |                     {
 | 
        
           |  |  | 586 |                     if ( cTimeOut != 0 )
 | 
        
           |  |  | 587 |                         {
 | 
        
           |  |  | 588 |                         DisplayLatLon();
 | 
        
           |  |  | 589 |                         }
 | 
        
           |  |  | 590 |                     else
 | 
        
           |  |  | 591 |                         {
 | 
        
           |  |  | 592 |                         DisplayMessage ( NODATA_MSG );
 | 
        
           |  |  | 593 |                         }
 | 
        
           |  |  | 594 |                     }
 | 
        
           |  |  | 595 |                 cRxErrorFlag = OFF;
 | 
        
           |  |  | 596 |                 break;
 | 
        
           |  |  | 597 |                 }
 | 
        
           |  |  | 598 |             case WAYPOINT_SCREEN:
 | 
        
           |  |  | 599 |                 {
 | 
        
           |  |  | 600 |                 if ( cScreenChanged == YES )
 | 
        
           |  |  | 601 |                     {
 | 
        
           |  |  | 602 |                     disable_interrupts ( INT_RDA );
 | 
        
           |  |  | 603 |                     cScreenChanged = NO;
 | 
        
           |  |  | 604 |                     cSkip = NO;
 | 
        
           |  |  | 605 |                     LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 606 |                     DisplayTemplateWaypoint();
 | 
        
           |  |  | 607 |                     enable_interrupts ( INT_RDA );
 | 
        
           |  |  | 608 |                     }
 | 
        
           |  |  | 609 |                 cSkip = NO;
 | 
        
           |  |  | 610 |                 InitRxBuffer( GPRMB_CODE );     // set code and turn on serial interrupt
 | 
        
           |  |  | 611 |                 while ( ( cRxMsgReady == NO ) && ( cTimeOut != 0 ) && ( cScreenChanged != YES ) );
 | 
        
           |  |  | 612 |                 disable_interrupts ( INT_RDA );         // ignore rest of messages
 | 
        
           |  |  | 613 |                 if ( cScreenChanged == NO )
 | 
        
           |  |  | 614 |                     {
 | 
        
           |  |  | 615 |                     if ( cTimeOut != 0 )
 | 
        
           |  |  | 616 |                         {
 | 
        
           |  |  | 617 |                         DisplayWaypoint();
 | 
        
           |  |  | 618 |                         }
 | 
        
           |  |  | 619 |                     else
 | 
        
           |  |  | 620 |                         {
 | 
        
           |  |  | 621 |                         DisplayMessage ( NODATA_MSG );
 | 
        
           |  |  | 622 |                         }
 | 
        
           |  |  | 623 |                     }
 | 
        
           |  |  | 624 |                 break;
 | 
        
           |  |  | 625 |                 }
 | 
        
           |  |  | 626 |             case BATTERY_SCREEN:
 | 
        
           |  |  | 627 |                 {
 | 
        
           |  |  | 628 |                 if ( cScreenChanged == YES )
 | 
        
           |  |  | 629 |                     {
 | 
        
           |  |  | 630 |                     disable_interrupts ( INT_RDA );
 | 
        
           |  |  | 631 |                     cScreenChanged = NO;
 | 
        
           |  |  | 632 |                     cSkip = NO;
 | 
        
           |  |  | 633 |                     LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 634 |                     DisplayTemplateAnalog();
 | 
        
           |  |  | 635 |                     }
 | 
        
           |  |  | 636 |                 DisplayAnalog();
 | 
        
           |  |  | 637 |                 break;
 | 
        
           |  |  | 638 |                 }
 | 
        
           |  |  | 639 |             }
 | 
        
           |  |  | 640 |   | 
        
           |  |  | 641 |         // Preset timeout counter each loop; RTCC interrupt decrements, resets if zero is reached
 | 
        
           |  |  | 642 |         iTimeOut = 2000;     // ~ 30 seconds
 | 
        
           |  |  | 643 |   | 
        
           |  |  | 644 |         /* Flashing activity indicator in lower right of screen. */
 | 
        
           |  |  | 645 |         cIndicator ^= 1;
 | 
        
           |  |  | 646 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 647 |         LCD_SetPosition ( LINE_4 + 19 );
 | 
        
           |  |  | 648 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 649 |         LCD_SetPosition ( LINE_4 + 15 );
 | 
        
           |  |  | 650 |         #endif
 | 
        
           |  |  | 651 |         if ( cIndicator == 1 )
 | 
        
           |  |  | 652 |             {
 | 
        
           |  |  | 653 |             printf ( LCD_PutChar, "%c", ACTIVITY_SYMBOL );
 | 
        
           |  |  | 654 |             }
 | 
        
           |  |  | 655 |         else
 | 
        
           |  |  | 656 |             {
 | 
        
           |  |  | 657 |             printf ( LCD_PutChar, " " );
 | 
        
           |  |  | 658 |             }
 | 
        
           |  |  | 659 |         }
 | 
        
           |  |  | 660 |     }
 | 
        
           |  |  | 661 |   | 
        
           |  |  | 662 | #separate void DisplayTemplateLatLon ( void )
 | 
        
           |  |  | 663 |     {
 | 
        
           |  |  | 664 |     LCD_SetPosition ( LINE_1 );
 | 
        
           |  |  | 665 |     printf ( LCD_PutChar, "LAT" );
 | 
        
           |  |  | 666 |     LCD_SetPosition ( LINE_2 );
 | 
        
           |  |  | 667 |     printf ( LCD_PutChar, "LON" );
 | 
        
           |  |  | 668 |     LCD_SetPosition ( LINE_3 );
 | 
        
           |  |  | 669 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 670 |     printf ( LCD_PutChar, "SPEED" );
 | 
        
           |  |  | 671 |     LCD_SetPosition ( LINE_4 );
 | 
        
           |  |  | 672 |     printf ( LCD_PutChar, "HEADING" );
 | 
        
           |  |  | 673 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 674 |     printf ( LCD_PutChar, "SPD" );
 | 
        
           |  |  | 675 |     LCD_SetPosition ( LINE_4 );
 | 
        
           |  |  | 676 |     printf ( LCD_PutChar, "HDG" );
 | 
        
           |  |  | 677 |     #endif
 | 
        
           |  |  | 678 |     }
 | 
        
           |  |  | 679 |   | 
        
           |  |  | 680 | #separate void DisplayTemplateWaypoint ( void )
 | 
        
           |  |  | 681 |     {
 | 
        
           |  |  | 682 |     LCD_SetPosition ( LINE_1 );
 | 
        
           |  |  | 683 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 684 |     printf ( LCD_PutChar, "WAYPOINT" );
 | 
        
           |  |  | 685 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 686 |     printf ( LCD_PutChar, "WAYPT" );
 | 
        
           |  |  | 687 |     #endif
 | 
        
           |  |  | 688 |     LCD_SetPosition ( LINE_2 );
 | 
        
           |  |  | 689 |     printf ( LCD_PutChar, "STEER" );
 | 
        
           |  |  | 690 |     LCD_SetPosition ( LINE_3 );
 | 
        
           |  |  | 691 |     printf ( LCD_PutChar, "DIST" );
 | 
        
           |  |  | 692 |     LCD_SetPosition ( LINE_4 );
 | 
        
           |  |  | 693 |     printf ( LCD_PutChar, "BEARING" );
 | 
        
           |  |  | 694 |     }
 | 
        
           |  |  | 695 |   | 
        
           |  |  | 696 | #separate void DisplayTemplateAnalog ( void )
 | 
        
           |  |  | 697 |     {
 | 
        
           |  |  | 698 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 699 |     LCD_SetPosition ( LINE_1 + 3 );
 | 
        
           |  |  | 700 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 701 |     LCD_SetPosition ( LINE_1 + 1 );
 | 
        
           |  |  | 702 |     #endif
 | 
        
           |  |  | 703 |     printf ( LCD_PutChar, "BATTERY STATUS" );
 | 
        
           |  |  | 704 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 705 |     LCD_SetPosition ( LINE_2 );
 | 
        
           |  |  | 706 |     printf ( LCD_PutChar, "Primary" );
 | 
        
           |  |  | 707 |     LCD_SetPosition ( LINE_3 );
 | 
        
           |  |  | 708 |     printf ( LCD_PutChar, "Secondary" );
 | 
        
           |  |  | 709 |     LCD_SetPosition ( LINE_4 );
 | 
        
           |  |  | 710 |     printf ( LCD_PutChar, "Refrigerator" );
 | 
        
           |  |  | 711 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 712 |     LCD_SetPosition ( LINE_2 );
 | 
        
           |  |  | 713 |     printf ( LCD_PutChar, "Main#1 " );
 | 
        
           |  |  | 714 |     LCD_SetPosition ( LINE_3 );
 | 
        
           |  |  | 715 |     printf ( LCD_PutChar, "Main#2 " );
 | 
        
           |  |  | 716 |     LCD_SetPosition ( LINE_4 );
 | 
        
           |  |  | 717 |     printf ( LCD_PutChar, "Refrig " );
 | 
        
           |  |  | 718 |     #endif
 | 
        
           |  |  | 719 |     }
 | 
        
           |  |  | 720 |   | 
        
           |  |  | 721 | #separate void DisplayLatLon ( void )
 | 
        
           |  |  | 722 |     {
 | 
        
           |  |  | 723 |     SkipField ( 1 );   // skip UTC
 | 
        
           |  |  | 724 |     GetField();        // A = OK, V = warning
 | 
        
           |  |  | 725 |     if ( ( cC [ 0 ] == 'A' ) && ( !cSkip ) )
 | 
        
           |  |  | 726 |         {
 | 
        
           |  |  | 727 |         GetField();                   // LAT
 | 
        
           |  |  | 728 |         if ( !cSkip )
 | 
        
           |  |  | 729 |             {
 | 
        
           |  |  | 730 |             DisplayLatitude ( LINE_1 );
 | 
        
           |  |  | 731 |             }
 | 
        
           |  |  | 732 |         GetField();                   // LON
 | 
        
           |  |  | 733 |         if ( !cSkip )
 | 
        
           |  |  | 734 |             {
 | 
        
           |  |  | 735 |             DisplayLongitude ( LINE_2 );
 | 
        
           |  |  | 736 |             }
 | 
        
           |  |  | 737 |         GetField();                   // SPEED
 | 
        
           |  |  | 738 |         if ( !cSkip )
 | 
        
           |  |  | 739 |             {
 | 
        
           |  |  | 740 |             DisplaySpeed ( LINE_3 );
 | 
        
           |  |  | 741 |             }
 | 
        
           |  |  | 742 |         GetField();                   // HEADING
 | 
        
           |  |  | 743 |         if ( !cSkip )
 | 
        
           |  |  | 744 |             {
 | 
        
           |  |  | 745 |             DisplayHeading ( LINE_4 );
 | 
        
           |  |  | 746 |             }
 | 
        
           |  |  | 747 |         }
 | 
        
           |  |  | 748 |     else
 | 
        
           |  |  | 749 |         {
 | 
        
           |  |  | 750 |         DisplayMessage( WARNING_MSG );
 | 
        
           |  |  | 751 |         }
 | 
        
           |  |  | 752 |     }
 | 
        
           |  |  | 753 |   | 
        
           |  |  | 754 | #separate void DisplayWaypoint ( void )
 | 
        
           |  |  | 755 |     {
 | 
        
           |  |  | 756 |     char cX;
 | 
        
           |  |  | 757 |   | 
        
           |  |  | 758 |     GetField();        // A = OK, V = warning
 | 
        
           |  |  | 759 |     if ( ( cC [ 0 ] == 'A' ) && ( !cSkip ) )
 | 
        
           |  |  | 760 |         {
 | 
        
           |  |  | 761 |         cX = GetField();        // XTE
 | 
        
           |  |  | 762 |         if ( !cSkip )
 | 
        
           |  |  | 763 |             {
 | 
        
           |  |  | 764 |             DisplaySteer ( LINE_2, cX );
 | 
        
           |  |  | 765 |             }
 | 
        
           |  |  | 766 |         SkipField ( 1 );        // skip origin WP ID
 | 
        
           |  |  | 767 |         GetField();                     // DEST WP ID
 | 
        
           |  |  | 768 |         if ( !cSkip )
 | 
        
           |  |  | 769 |             {
 | 
        
           |  |  | 770 |             DisplayWaypointName ( LINE_1, cX );
 | 
        
           |  |  | 771 |             }
 | 
        
           |  |  | 772 |         SkipField ( 4 );        // skip LAT, NS, LON, EW
 | 
        
           |  |  | 773 |         cX = GetField();                     // RANGE
 | 
        
           |  |  | 774 |         if ( !cSkip )
 | 
        
           |  |  | 775 |             {
 | 
        
           |  |  | 776 |             DisplayDistance ( LINE_3, cX );
 | 
        
           |  |  | 777 |             }
 | 
        
           |  |  | 778 |         cX = GetField();                     // BEARING
 | 
        
           |  |  | 779 |         if ( !cSkip )
 | 
        
           |  |  | 780 |             {
 | 
        
           |  |  | 781 |             DisplayBearing ( LINE_4, cX );
 | 
        
           |  |  | 782 |             }
 | 
        
           |  |  | 783 |         SkipField ( 1 );        // skip SPEED TO DEST
 | 
        
           |  |  | 784 |         GetField();                     // ARRIVAL FLAG
 | 
        
           |  |  | 785 |         if ( !cSkip )
 | 
        
           |  |  | 786 |             {
 | 
        
           |  |  | 787 |             DisplayArrival ( LINE_1 );    // overwrite RANGE if arrived
 | 
        
           |  |  | 788 |             }
 | 
        
           |  |  | 789 |         }
 | 
        
           |  |  | 790 |     else
 | 
        
           |  |  | 791 |         {
 | 
        
           |  |  | 792 |         DisplayMessage( WARNING_MSG );
 | 
        
           |  |  | 793 |         }
 | 
        
           |  |  | 794 |     }
 | 
        
           |  |  | 795 |   | 
        
           |  |  | 796 | #separate void DisplayAnalog ( void )
 | 
        
           |  |  | 797 |     {
 | 
        
           |  |  | 798 |     long iX;
 | 
        
           |  |  | 799 |     char cCnt;
 | 
        
           |  |  | 800 |   | 
        
           |  |  | 801 |     set_adc_channel ( 0 );                      // set channel
 | 
        
           |  |  | 802 |     delay_us ( 100 );                           // wait aquisition time
 | 
        
           |  |  | 803 |     cAdcDone = NO;
 | 
        
           |  |  | 804 |     if ( !cSkip )
 | 
        
           |  |  | 805 |         {
 | 
        
           |  |  | 806 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 807 |         LCD_SetPosition ( LINE_2 + 13 );
 | 
        
           |  |  | 808 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 809 |         LCD_SetPosition ( LINE_2 + 8 );
 | 
        
           |  |  | 810 |         #endif
 | 
        
           |  |  | 811 |         DisplayScaledVoltage ( read_adc(), MAX_VOLTS );
 | 
        
           |  |  | 812 |         printf ( LCD_PutChar, " V " );
 | 
        
           |  |  | 813 |         }
 | 
        
           |  |  | 814 |     set_adc_channel ( 1 );
 | 
        
           |  |  | 815 |     delay_us ( 100 );
 | 
        
           |  |  | 816 |     cAdcDone = NO;
 | 
        
           |  |  | 817 |     if ( !cSkip )
 | 
        
           |  |  | 818 |         {
 | 
        
           |  |  | 819 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 820 |         LCD_SetPosition ( LINE_3 + 13 );
 | 
        
           |  |  | 821 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 822 |         LCD_SetPosition ( LINE_3 + 8 );
 | 
        
           |  |  | 823 |         #endif
 | 
        
           |  |  | 824 |         DisplayScaledVoltage ( read_adc(), MAX_VOLTS );
 | 
        
           |  |  | 825 |         printf ( LCD_PutChar, " V " );
 | 
        
           |  |  | 826 |         }
 | 
        
           |  |  | 827 |     set_adc_channel ( 3 );
 | 
        
           |  |  | 828 |     delay_us ( 100 );
 | 
        
           |  |  | 829 |     cAdcDone = NO;
 | 
        
           |  |  | 830 |     if ( !cSkip )
 | 
        
           |  |  | 831 |         {
 | 
        
           |  |  | 832 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 833 |         LCD_SetPosition ( LINE_4 + 13 );
 | 
        
           |  |  | 834 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 835 |         LCD_SetPosition ( LINE_4 + 8 );
 | 
        
           |  |  | 836 |         #endif
 | 
        
           |  |  | 837 |         DisplayScaledVoltage ( read_adc(), MAX_VOLTS );
 | 
        
           |  |  | 838 |         printf ( LCD_PutChar, " V " );
 | 
        
           |  |  | 839 |         }
 | 
        
           |  |  | 840 |     Delay5mS ( 100 );         // slow loop down a bit
 | 
        
           |  |  | 841 |     }
 | 
        
           |  |  | 842 |   | 
        
           |  |  | 843 | #separate void GetUtcAndMagVar ( void )
 | 
        
           |  |  | 844 |     {
 | 
        
           |  |  | 845 |     /*
 | 
        
           |  |  | 846 |     This is a non-display version of the RMC sentence
 | 
        
           |  |  | 847 |     to get the A/V warning, the magnetic variation, and the
 | 
        
           |  |  | 848 |     magnetic direction.
 | 
        
           |  |  | 849 |     */
 | 
        
           |  |  | 850 |   | 
        
           |  |  | 851 |     GetField();              // get UTC
 | 
        
           |  |  | 852 |     GetField();        // A = OK, V = warning
 | 
        
           |  |  | 853 |     if ( cC [ 0 ] == 'A' )
 | 
        
           |  |  | 854 |         {
 | 
        
           |  |  | 855 |         SkipField ( 7 );   // skip fields
 | 
        
           |  |  | 856 |         GetField();             // MAGNETIC VARIATION
 | 
        
           |  |  | 857 |         iVar = FieldFiveToLong();     // save to global variable, used in other sentences
 | 
        
           |  |  | 858 |         GetField();     // EW
 | 
        
           |  |  | 859 |         cVarDir = cC [ 0 ];     // save direction
 | 
        
           |  |  | 860 |         }
 | 
        
           |  |  | 861 |     else
 | 
        
           |  |  | 862 |         {
 | 
        
           |  |  | 863 |         iVar = NULL;              // invalid
 | 
        
           |  |  | 864 |         cVarDir = SPACE;
 | 
        
           |  |  | 865 |         }
 | 
        
           |  |  | 866 |     }
 | 
        
           |  |  | 867 |   | 
        
           |  |  | 868 | /******************************************************************/
 | 
        
           |  |  | 869 |   | 
        
           |  |  | 870 | #separate void DisplayScaledVoltage ( long iV, char cScale )
 | 
        
           |  |  | 871 |     {
 | 
        
           |  |  | 872 |     float fX;
 | 
        
           |  |  | 873 |   | 
        
           |  |  | 874 |     /*
 | 
        
           |  |  | 875 |   | 
        
           |  |  | 876 |     scales it to something else.
 | 
        
           |  |  | 877 |     */
 | 
        
           |  |  | 878 |     while ( cAdcDone == NO );         // wait for completion by ADC interrupt
 | 
        
           |  |  | 879 |     if ( iV == 1023 )
 | 
        
           |  |  | 880 |         {
 | 
        
           |  |  | 881 |         printf ( LCD_PutChar, "O/L" );  /* print it to the screen */
 | 
        
           |  |  | 882 |         }
 | 
        
           |  |  | 883 |     else
 | 
        
           |  |  | 884 |         {
 | 
        
           |  |  | 885 |         fX = ( ( float ) iV ) / 1023 * ( float ) cScale;   // scale to proper range, 1023 leaves room for out-of-range
 | 
        
           |  |  | 886 |         printf ( LCD_PutChar, "%2.1f", fX );  /* print it to the screen */
 | 
        
           |  |  | 887 |         }
 | 
        
           |  |  | 888 |     }
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 | #separate void DisplayArrival ( char cLine )
 | 
        
           |  |  | 891 |     {
 | 
        
           |  |  | 892 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 893 |     LCD_SetPosition ( cLine + 11 );
 | 
        
           |  |  | 894 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 895 |     LCD_SetPosition ( cLine + 9 );
 | 
        
           |  |  | 896 |     #endif
 | 
        
           |  |  | 897 |     if ( cC [ 0 ] == 'A' )
 | 
        
           |  |  | 898 |         {
 | 
        
           |  |  | 899 |         printf ( LCD_PutChar, "Arrived" );
 | 
        
           |  |  | 900 |         }
 | 
        
           |  |  | 901 |     else
 | 
        
           |  |  | 902 |         {
 | 
        
           |  |  | 903 |         printf ( LCD_PutChar, "       " );
 | 
        
           |  |  | 904 |         }
 | 
        
           |  |  | 905 |     }
 | 
        
           |  |  | 906 |   | 
        
           |  |  | 907 | #separate void DisplayWaypointName ( char cLine, char cX )
 | 
        
           |  |  | 908 |     {
 | 
        
           |  |  | 909 |     /* Displays waypoint name, pads field with blanks */
 | 
        
           |  |  | 910 |     char cChar, cI;
 | 
        
           |  |  | 911 |   | 
        
           |  |  | 912 |     LCD_SetPosition ( cLine );
 | 
        
           |  |  | 913 |     if ( cX != 0 )
 | 
        
           |  |  | 914 |         {
 | 
        
           |  |  | 915 |         printf ( LCD_PutChar, "\"" );
 | 
        
           |  |  | 916 |         for ( cI = 0; cI < 6; cI++ )
 | 
        
           |  |  | 917 |             {
 | 
        
           |  |  | 918 |             cChar = cC [ cI ];
 | 
        
           |  |  | 919 |             if ( cChar == EOF )
 | 
        
           |  |  | 920 |                 {
 | 
        
           |  |  | 921 |                 break;
 | 
        
           |  |  | 922 |                 }
 | 
        
           |  |  | 923 |             printf ( LCD_PutChar, "%c", cChar );
 | 
        
           |  |  | 924 |             }
 | 
        
           |  |  | 925 |         printf ( LCD_PutChar, "\"" );
 | 
        
           |  |  | 926 |         // Blank remainder of field
 | 
        
           |  |  | 927 |         cChar = SPACE;
 | 
        
           |  |  | 928 |         for ( ; cI < 6; cI++ )
 | 
        
           |  |  | 929 |             {
 | 
        
           |  |  | 930 |             printf ( LCD_PutChar, "%c", cChar );
 | 
        
           |  |  | 931 |             }
 | 
        
           |  |  | 932 |         }
 | 
        
           |  |  | 933 |     else
 | 
        
           |  |  | 934 |         {
 | 
        
           |  |  | 935 |         printf ( LCD_PutChar, "- none -" );
 | 
        
           |  |  | 936 |         }
 | 
        
           |  |  | 937 |     }
 | 
        
           |  |  | 938 |   | 
        
           |  |  | 939 | #separate void DisplaySteer ( char cLine, char cX )
 | 
        
           |  |  | 940 |     {
 | 
        
           |  |  | 941 |     /*
 | 
        
           |  |  | 942 |     Displays A.BC literals, appends 'L' or 'R'.
 | 
        
           |  |  | 943 |     If less than 1.0, displays feet rather than nm.
 | 
        
           |  |  | 944 |     Doesn't display distance if on track.
 | 
        
           |  |  | 945 |     */
 | 
        
           |  |  | 946 |     long iX;
 | 
        
           |  |  | 947 |     char cCnt;
 | 
        
           |  |  | 948 |   | 
        
           |  |  | 949 |     if ( cX != 0 )
 | 
        
           |  |  | 950 |         {
 | 
        
           |  |  | 951 |         if ( ( cC [ 0 ] != '0' ) || ( cC [ 2 ] != '0' ) || ( cC [ 3 ] != '0' ) )   // if not 0.00
 | 
        
           |  |  | 952 |             {
 | 
        
           |  |  | 953 |             LCD_SetPosition ( cLine + 14 );
 | 
        
           |  |  | 954 |             #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 955 |             printf ( LCD_PutChar, "      " );         // blank possible characters
 | 
        
           |  |  | 956 |             LCD_SetPosition ( cLine + 11 );
 | 
        
           |  |  | 957 |             #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 958 |             printf ( LCD_PutChar, "  " );         // blank possible characters
 | 
        
           |  |  | 959 |             LCD_SetPosition ( cLine + 8);
 | 
        
           |  |  | 960 |             #endif
 | 
        
           |  |  | 961 |             if ( cC [ 0 ] == '0' )          // if less than 1.0 nm, display as feet
 | 
        
           |  |  | 962 |                 {
 | 
        
           |  |  | 963 |                 iX = ( 528 * ( long ) ( cC [ 2 ] - 0x30 ) ) + ( 52 * ( long ) ( cC [ 3 ] - 0x30 ) );
 | 
        
           |  |  | 964 |                 printf ( LCD_PutChar, "%luft  ", iX );
 | 
        
           |  |  | 965 |                 }
 | 
        
           |  |  | 966 |             else                             // if 1.0 nm or greater, display as nautical miles
 | 
        
           |  |  | 967 |                 {
 | 
        
           |  |  | 968 |                 printf ( LCD_PutChar, "%c%c%c%cmi  ", cC [ 0 ], cC [ 1 ], cC [ 2 ] , cC [ 3 ] );
 | 
        
           |  |  | 969 |                 }
 | 
        
           |  |  | 970 |             GetField();              // L or R
 | 
        
           |  |  | 971 |             LCD_SetPosition ( cLine + 6 );
 | 
        
           |  |  | 972 |             if ( cC [ 0 ] == 'L' )
 | 
        
           |  |  | 973 |                 {
 | 
        
           |  |  | 974 |                 #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 975 |                 printf ( LCD_PutChar, "PORT " );
 | 
        
           |  |  | 976 |                 #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 977 |                 printf ( LCD_PutChar, "L" );
 | 
        
           |  |  | 978 |                 #endif
 | 
        
           |  |  | 979 |                 }
 | 
        
           |  |  | 980 |             else
 | 
        
           |  |  | 981 |                 {
 | 
        
           |  |  | 982 |                 #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 983 |                 printf ( LCD_PutChar, "STBD " );
 | 
        
           |  |  | 984 |                 #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 985 |                 printf ( LCD_PutChar, "R" );
 | 
        
           |  |  | 986 |                 #endif
 | 
        
           |  |  | 987 |                 }
 | 
        
           |  |  | 988 |             }
 | 
        
           |  |  | 989 |         else           // if 0.00
 | 
        
           |  |  | 990 |             {
 | 
        
           |  |  | 991 |             #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 992 |             LCD_SetPosition ( cLine + 11 );
 | 
        
           |  |  | 993 |             printf ( LCD_PutChar, "On track " );
 | 
        
           |  |  | 994 |             #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 995 |             LCD_SetPosition ( cLine + 6 );
 | 
        
           |  |  | 996 |             printf ( LCD_PutChar, "  On track" );
 | 
        
           |  |  | 997 |             #endif
 | 
        
           |  |  | 998 |             GetField();              // dummy L or R
 | 
        
           |  |  | 999 |             }
 | 
        
           |  |  | 1000 |         }
 | 
        
           |  |  | 1001 |     else
 | 
        
           |  |  | 1002 |         {
 | 
        
           |  |  | 1003 |         LCD_SetPosition ( cLine + 6 );
 | 
        
           |  |  | 1004 |         printf ( LCD_PutChar, "              " );
 | 
        
           |  |  | 1005 |         }
 | 
        
           |  |  | 1006 |     }
 | 
        
           |  |  | 1007 |   | 
        
           |  |  | 1008 | #separate void DisplayDistance ( char cLine, char cX )
 | 
        
           |  |  | 1009 |     {
 | 
        
           |  |  | 1010 |     /* Format: ABC.D nautical miles */
 | 
        
           |  |  | 1011 |     char cChar, cI;
 | 
        
           |  |  | 1012 |     long iThisRange;
 | 
        
           |  |  | 1013 |   | 
        
           |  |  | 1014 |     if ( cX != 0 )           // if waypoint data to display
 | 
        
           |  |  | 1015 |         {
 | 
        
           |  |  | 1016 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1017 |         LCD_SetPosition ( cLine + 11 );
 | 
        
           |  |  | 1018 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1019 |         LCD_SetPosition ( cLine + 8 );
 | 
        
           |  |  | 1020 |         #endif
 | 
        
           |  |  | 1021 |         cI = 0;
 | 
        
           |  |  | 1022 |         for ( cI = 0; cI < 2; cI++ )    // find first non-zero
 | 
        
           |  |  | 1023 |             {
 | 
        
           |  |  | 1024 |             cChar = cC [ cI ];
 | 
        
           |  |  | 1025 |             if ( cChar != '0' )
 | 
        
           |  |  | 1026 |                 {
 | 
        
           |  |  | 1027 |                 break;
 | 
        
           |  |  | 1028 |                 }
 | 
        
           |  |  | 1029 |             }
 | 
        
           |  |  | 1030 |         for ( ; cI < 5; cI++ )    // display from there on
 | 
        
           |  |  | 1031 |             {
 | 
        
           |  |  | 1032 |             printf ( LCD_PutChar, "%c", cC [ cI ] );
 | 
        
           |  |  | 1033 |             }
 | 
        
           |  |  | 1034 |         printf ( LCD_PutChar, "nm  " );     // pad with blanks
 | 
        
           |  |  | 1035 |   | 
        
           |  |  | 1036 |         /*
 | 
        
           |  |  | 1037 |         The least significant character from the GPS is 0.1 nm.
 | 
        
           |  |  | 1038 |         Multiply whole thing by 10 and make it type long.
 | 
        
           |  |  | 1039 |         Discern if increasing (FROM) or decreasing (TO).
 | 
        
           |  |  | 1040 |         */
 | 
        
           |  |  | 1041 |         iThisRange = 1000 * ( long ) ( cC [ 0 ] - 0x30 );
 | 
        
           |  |  | 1042 |         iThisRange += 100 * ( long ) ( cC [ 1 ] - 0x30 );
 | 
        
           |  |  | 1043 |         iThisRange += 10 * ( long ) ( cC [ 2 ] - 0x30 );
 | 
        
           |  |  | 1044 |         iThisRange += ( long ) ( cC [ 4 ] - 0x30 );
 | 
        
           |  |  | 1045 |         if ( iThisRange < iLastRange )
 | 
        
           |  |  | 1046 |             {
 | 
        
           |  |  | 1047 |             #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1048 |             strcpy ( cToFrom, "TO  " );
 | 
        
           |  |  | 1049 |             #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1050 |             strcpy ( cToFrom, "TO" );
 | 
        
           |  |  | 1051 |             #endif
 | 
        
           |  |  | 1052 |             }
 | 
        
           |  |  | 1053 |         if ( iThisRange > iLastRange )
 | 
        
           |  |  | 1054 |             {
 | 
        
           |  |  | 1055 |             #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1056 |             strcpy ( cToFrom, "FROM" );
 | 
        
           |  |  | 1057 |             #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1058 |             strcpy ( cToFrom, "FM" );
 | 
        
           |  |  | 1059 |             #endif
 | 
        
           |  |  | 1060 |             }
 | 
        
           |  |  | 1061 |         iLastRange = iThisRange;    // save this range to compare next time
 | 
        
           |  |  | 1062 |         LCD_SetPosition ( cLine + 5 );
 | 
        
           |  |  | 1063 |         printf ( LCD_PutChar, cToFrom );
 | 
        
           |  |  | 1064 |         }
 | 
        
           |  |  | 1065 |     else
 | 
        
           |  |  | 1066 |         {
 | 
        
           |  |  | 1067 |         LCD_SetPosition ( cLine + 5 );
 | 
        
           |  |  | 1068 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1069 |         printf ( LCD_PutChar, "               " );
 | 
        
           |  |  | 1070 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1071 |         printf ( LCD_PutChar, "          " );
 | 
        
           |  |  | 1072 |         #endif
 | 
        
           |  |  | 1073 |         }
 | 
        
           |  |  | 1074 |     }
 | 
        
           |  |  | 1075 |   | 
        
           |  |  | 1076 | #separate void DisplayBearing ( char cLine, char cX )
 | 
        
           |  |  | 1077 |     {
 | 
        
           |  |  | 1078 |     /*
 | 
        
           |  |  | 1079 |     Compass variation comes from RMC sentence.  If RMC has not run yet
 | 
        
           |  |  | 1080 |     then "T" is displayed after bearing.
 | 
        
           |  |  | 1081 |     */
 | 
        
           |  |  | 1082 |     long iHdg;
 | 
        
           |  |  | 1083 |     char cTrueIndicator;
 | 
        
           |  |  | 1084 |   | 
        
           |  |  | 1085 |     if ( cX != 0 )           // if waypoint data to display
 | 
        
           |  |  | 1086 |         {
 | 
        
           |  |  | 1087 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1088 |         LCD_SetPosition ( cLine + 11 );
 | 
        
           |  |  | 1089 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1090 |         LCD_SetPosition ( cLine + 8 );
 | 
        
           |  |  | 1091 |         #endif
 | 
        
           |  |  | 1092 |         iHdg = FieldFiveToLong();
 | 
        
           |  |  | 1093 |         iHdg = TrueToMag ( iHdg );    // factor variation into heading
 | 
        
           |  |  | 1094 |         if ( ( iVar == NULL ) || ( cVarDir == SPACE ) )
 | 
        
           |  |  | 1095 |             {
 | 
        
           |  |  | 1096 |             cTrueIndicator = 'T';
 | 
        
           |  |  | 1097 |             }
 | 
        
           |  |  | 1098 |         else
 | 
        
           |  |  | 1099 |             {
 | 
        
           |  |  | 1100 |             cTrueIndicator = ' ';
 | 
        
           |  |  | 1101 |             }
 | 
        
           |  |  | 1102 |         printf ( LCD_PutChar, "%lu%c%c  ", iHdg, DEGREE, cTrueIndicator );   // pad with blanks
 | 
        
           |  |  | 1103 |         }
 | 
        
           |  |  | 1104 |     else
 | 
        
           |  |  | 1105 |         {
 | 
        
           |  |  | 1106 |         #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1107 |         LCD_SetPosition ( cLine + 11 );
 | 
        
           |  |  | 1108 |         printf ( LCD_PutChar, "         " );
 | 
        
           |  |  | 1109 |         #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1110 |         LCD_SetPosition ( cLine + 8 );
 | 
        
           |  |  | 1111 |         printf ( LCD_PutChar, "        " );
 | 
        
           |  |  | 1112 |         #endif
 | 
        
           |  |  | 1113 |         }
 | 
        
           |  |  | 1114 |     }
 | 
        
           |  |  | 1115 |   | 
        
           |  |  | 1116 | #separate void DisplayLatitude ( char cLine )
 | 
        
           |  |  | 1117 |     {
 | 
        
           |  |  | 1118 |     /* Displays latitude ABCD.EF as AB CD.EF, appends 'N' or 'S' */
 | 
        
           |  |  | 1119 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1120 |     LCD_SetPosition ( cLine + 8 );
 | 
        
           |  |  | 1121 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1122 |     LCD_SetPosition ( cLine + 5 );
 | 
        
           |  |  | 1123 |     #endif
 | 
        
           |  |  | 1124 |     if ( cC [ 0 ] == '0' )
 | 
        
           |  |  | 1125 |         {
 | 
        
           |  |  | 1126 |         cC [ 0 ] = SPACE;
 | 
        
           |  |  | 1127 |         }
 | 
        
           |  |  | 1128 |     printf ( LCD_PutChar, "%c%c%c", cC [ 0 ], cC [ 1 ], DEGREE );
 | 
        
           |  |  | 1129 |     printf ( LCD_PutChar, "%c%c%c%c%c%c", cC [ 2 ], cC [ 3 ], cC [ 4 ], cC [ 5 ], cC [ 6 ], cC [ 7 ] );
 | 
        
           |  |  | 1130 |     GetField();              // NS
 | 
        
           |  |  | 1131 |     printf ( LCD_PutChar, " %c", cC [ 0 ] );
 | 
        
           |  |  | 1132 |     }
 | 
        
           |  |  | 1133 |   | 
        
           |  |  | 1134 | #separate void DisplayLongitude ( char cLine )
 | 
        
           |  |  | 1135 |     {
 | 
        
           |  |  | 1136 |     /* Displays longitude ABCDE.FG as ABC DE.FG, appends 'E' or 'W' */
 | 
        
           |  |  | 1137 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1138 |     LCD_SetPosition ( cLine + 7 );
 | 
        
           |  |  | 1139 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1140 |     LCD_SetPosition ( cLine + 4 );
 | 
        
           |  |  | 1141 |     #endif
 | 
        
           |  |  | 1142 |     if ( cC [ 0 ] == '0' )
 | 
        
           |  |  | 1143 |         {
 | 
        
           |  |  | 1144 |         cC [ 0 ] = SPACE;
 | 
        
           |  |  | 1145 |         }
 | 
        
           |  |  | 1146 |     if ( cC [ 1 ] == '0' )
 | 
        
           |  |  | 1147 |         {
 | 
        
           |  |  | 1148 |         cC [ 1 ] = SPACE;
 | 
        
           |  |  | 1149 |         }
 | 
        
           |  |  | 1150 |     printf ( LCD_PutChar, "%c%c%c%c", cC [ 0 ], cC [ 1 ], cC [ 2 ], DEGREE );
 | 
        
           |  |  | 1151 |     printf ( LCD_PutChar, "%c%c%c%c%c%c", cC [ 3 ], cC [ 4 ], cC [ 5 ], cC [ 6 ], cC [ 7 ], cC [ 8 ] );
 | 
        
           |  |  | 1152 |     GetField();              // EW
 | 
        
           |  |  | 1153 |     printf ( LCD_PutChar, " %c", cC [ 0 ] );
 | 
        
           |  |  | 1154 |     }
 | 
        
           |  |  | 1155 |   | 
        
           |  |  | 1156 | #separate void DisplaySpeed ( char cLine )
 | 
        
           |  |  | 1157 |     {
 | 
        
           |  |  | 1158 |     float fX;
 | 
        
           |  |  | 1159 |   | 
        
           |  |  | 1160 |     // Format ABC.D
 | 
        
           |  |  | 1161 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1162 |     LCD_SetPosition ( cLine + 8 );
 | 
        
           |  |  | 1163 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1164 |     LCD_SetPosition ( cLine + 5 );
 | 
        
           |  |  | 1165 |     #endif
 | 
        
           |  |  | 1166 |     fX = 100 * ( cC [ 0 ] - 0x30 );
 | 
        
           |  |  | 1167 |     fX += 10 * ( cC [ 1 ] - 0x30 );
 | 
        
           |  |  | 1168 |     fX += 1 * ( cC [ 2 ] - 0x30 );
 | 
        
           |  |  | 1169 |     fX += 0.1 * ( cC [ 4 ] - 0x30 );
 | 
        
           |  |  | 1170 |     #if SPEED_UNITS == 2
 | 
        
           |  |  | 1171 |     fX *= 1.852;        // convert knots to km/h
 | 
        
           |  |  | 1172 |     #endif
 | 
        
           |  |  | 1173 |     #if SPEED_UNITS == 3
 | 
        
           |  |  | 1174 |     fX *= 1.151;        // convert knots to mi/h
 | 
        
           |  |  | 1175 |     #endif
 | 
        
           |  |  | 1176 |     printf ( LCD_PutChar, "%3.1f ", fX );  // print it to the screen
 | 
        
           |  |  | 1177 |     #if SPEED_UNITS == 1
 | 
        
           |  |  | 1178 |     printf ( LCD_PutChar, "kts    " );     // print it to the screen
 | 
        
           |  |  | 1179 |     #endif
 | 
        
           |  |  | 1180 |     #if SPEED_UNITS == 2
 | 
        
           |  |  | 1181 |     printf ( LCD_PutChar, "kph    " );     // print it to the screen
 | 
        
           |  |  | 1182 |     #endif
 | 
        
           |  |  | 1183 |     #if SPEED_UNITS == 3
 | 
        
           |  |  | 1184 |     printf ( LCD_PutChar, "mph    " );     // print it to the screen
 | 
        
           |  |  | 1185 |     #endif
 | 
        
           |  |  | 1186 |     }
 | 
        
           |  |  | 1187 |   | 
        
           |  |  | 1188 | #separate void DisplayHeading ( char cLine )
 | 
        
           |  |  | 1189 |     {
 | 
        
           |  |  | 1190 |     long iHdg;
 | 
        
           |  |  | 1191 |   | 
        
           |  |  | 1192 |     #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1193 |     LCD_SetPosition ( cLine + 8 );
 | 
        
           |  |  | 1194 |     #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1195 |     LCD_SetPosition ( cLine + 5 );
 | 
        
           |  |  | 1196 |     #endif
 | 
        
           |  |  | 1197 |     iHdg = FieldFiveToLong();
 | 
        
           |  |  | 1198 |     SkipField ( 1 );     // skip fix date
 | 
        
           |  |  | 1199 |     GetField();             // MAGNETIC VARIATION
 | 
        
           |  |  | 1200 |     iVar = FieldFiveToLong();     // save to global variable, used in other sentences
 | 
        
           |  |  | 1201 |     GetField();     // EW
 | 
        
           |  |  | 1202 |     cVarDir = cC [ 0 ];     // save direction
 | 
        
           |  |  | 1203 |     iHdg = TrueToMag ( iHdg );    // factor variation into heading
 | 
        
           |  |  | 1204 |     printf ( LCD_PutChar, "%lu%c  ", iHdg, DEGREE );    // pad with blanks
 | 
        
           |  |  | 1205 |     }
 | 
        
           |  |  | 1206 |   | 
        
           |  |  | 1207 | #separate long FieldFiveToLong ( void )
 | 
        
           |  |  | 1208 |     {
 | 
        
           |  |  | 1209 |     /* Converts ABC.D to long, rounds decimal up or down */
 | 
        
           |  |  | 1210 |     long iX;
 | 
        
           |  |  | 1211 |   | 
        
           |  |  | 1212 |     iX = 100 * ( long ) ( cC [ 0 ] - 0x30 );
 | 
        
           |  |  | 1213 |     iX += 10 * ( long ) ( cC [ 1 ] - 0x30 );
 | 
        
           |  |  | 1214 |     iX += ( long ) ( cC [ 2 ] - 0x30 );
 | 
        
           |  |  | 1215 |     if ( ( cC [ 3 ] == PERIOD ) && ( cC [ 4 ] >= '5' ) )
 | 
        
           |  |  | 1216 |         {
 | 
        
           |  |  | 1217 |         iX++;           // round up
 | 
        
           |  |  | 1218 |         }
 | 
        
           |  |  | 1219 |     return ( iX );
 | 
        
           |  |  | 1220 |     }
 | 
        
           |  |  | 1221 |   | 
        
           |  |  | 1222 | #separate long TrueToMag ( long iH )
 | 
        
           |  |  | 1223 |     {
 | 
        
           |  |  | 1224 |     /* Magnetic variation information comes from the RMC sentence */
 | 
        
           |  |  | 1225 |   | 
        
           |  |  | 1226 |     if ( cVarDir == 'W' )
 | 
        
           |  |  | 1227 |         {
 | 
        
           |  |  | 1228 |         iH += iVar;
 | 
        
           |  |  | 1229 |         }
 | 
        
           |  |  | 1230 |     else
 | 
        
           |  |  | 1231 |         {
 | 
        
           |  |  | 1232 |         if ( iH >= iVar )
 | 
        
           |  |  | 1233 |             {
 | 
        
           |  |  | 1234 |             iH -= iVar;     // OK as-is
 | 
        
           |  |  | 1235 |             }
 | 
        
           |  |  | 1236 |         else
 | 
        
           |  |  | 1237 |             {
 | 
        
           |  |  | 1238 |             iH = iH + 360 - iVar;   // correct for below zero
 | 
        
           |  |  | 1239 |             }
 | 
        
           |  |  | 1240 |         }
 | 
        
           |  |  | 1241 |     if ( iH >= 360 )
 | 
        
           |  |  | 1242 |         {
 | 
        
           |  |  | 1243 |         iH -= 360;
 | 
        
           |  |  | 1244 |         }
 | 
        
           |  |  | 1245 |     return ( iH );
 | 
        
           |  |  | 1246 |     }
 | 
        
           |  |  | 1247 |   | 
        
           |  |  | 1248 | #separate void DisplayMessage ( char cMsgNum )
 | 
        
           |  |  | 1249 |     {
 | 
        
           |  |  | 1250 |     LCD_PutCmd ( CLEAR_DISP );
 | 
        
           |  |  | 1251 |     LCD_SetPosition ( LINE_2 );
 | 
        
           |  |  | 1252 |     switch ( cMsgNum )
 | 
        
           |  |  | 1253 |         {
 | 
        
           |  |  | 1254 |         case WARNING_MSG:
 | 
        
           |  |  | 1255 |             {
 | 
        
           |  |  | 1256 |             #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1257 |             printf ( LCD_PutChar,     "    GPS warning   " );
 | 
        
           |  |  | 1258 |             #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1259 |             printf ( LCD_PutChar, "  GPS warning" );
 | 
        
           |  |  | 1260 |             #endif
 | 
        
           |  |  | 1261 |             break;
 | 
        
           |  |  | 1262 |             }
 | 
        
           |  |  | 1263 |         case NODATA_MSG:
 | 
        
           |  |  | 1264 |             {
 | 
        
           |  |  | 1265 |             if ( cRxErrorFlag == OFF )    // is it a framing error problem ?
 | 
        
           |  |  | 1266 |                 {
 | 
        
           |  |  | 1267 |                 #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1268 |                 printf ( LCD_PutChar, "  No data from GPS" );
 | 
        
           |  |  | 1269 |                 #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1270 |                 printf ( LCD_PutChar, "No data from GPS" );
 | 
        
           |  |  | 1271 |                 #endif
 | 
        
           |  |  | 1272 |                 }
 | 
        
           |  |  | 1273 |             else
 | 
        
           |  |  | 1274 |                 {
 | 
        
           |  |  | 1275 |                 #if ( DISPLAY_COLS == 20 )
 | 
        
           |  |  | 1276 |                 printf ( LCD_PutChar, "     Baud error" );
 | 
        
           |  |  | 1277 |                 #elif ( DISPLAY_COLS == 16 )
 | 
        
           |  |  | 1278 |                 printf ( LCD_PutChar, "   Baud error" );
 | 
        
           |  |  | 1279 |                 #endif
 | 
        
           |  |  | 1280 |                 cRxErrorFlag = OFF;
 | 
        
           |  |  | 1281 |                 }
 | 
        
           |  |  | 1282 |             break;
 | 
        
           |  |  | 1283 |             }
 | 
        
           |  |  | 1284 |         }
 | 
        
           |  |  | 1285 |     Delay5mS ( 255 );                   // delay 1.25 seconds
 | 
        
           |  |  | 1286 |     iVar = NULL;
 | 
        
           |  |  | 1287 |     cVarDir = SPACE;                     // signal "no magnetic variation" yet
 | 
        
           |  |  | 1288 |     cScreenChanged = YES;
 | 
        
           |  |  | 1289 |     }
 | 
        
           |  |  | 1290 |   | 
        
           |  |  | 1291 | #separate void Delay5mS ( char cCnt )
 | 
        
           |  |  | 1292 |     {
 | 
        
           |  |  | 1293 |     char cX;
 | 
        
           |  |  | 1294 |   | 
        
           |  |  | 1295 |     /* This variable-count 5mS delay is interruptable by a button press */
 | 
        
           |  |  | 1296 |     for ( cX = 0; cX < cCnt; cX++ )
 | 
        
           |  |  | 1297 |         {
 | 
        
           |  |  | 1298 |         if ( cScreenChanged == YES )
 | 
        
           |  |  | 1299 |             {
 | 
        
           |  |  | 1300 |             break;
 | 
        
           |  |  | 1301 |             }
 | 
        
           |  |  | 1302 |         delay_ms ( 5 );
 | 
        
           |  |  | 1303 |         }
 | 
        
           |  |  | 1304 |     }
 | 
        
           |  |  | 1305 |   | 
        
           |  |  | 1306 | #separate char GetField ( void )
 | 
        
           |  |  | 1307 |     {
 | 
        
           |  |  | 1308 |     char cX, cIndex;
 | 
        
           |  |  | 1309 |   | 
        
           |  |  | 1310 |     cX = NULL;
 | 
        
           |  |  | 1311 |     cIndex = 0;
 | 
        
           |  |  | 1312 |     while ( !cSkip )
 | 
        
           |  |  | 1313 |         {
 | 
        
           |  |  | 1314 |         cX = GetRxChar();
 | 
        
           |  |  | 1315 |         if ( ( cX == COMMA ) || ( cX == CR ) )
 | 
        
           |  |  | 1316 |             {
 | 
        
           |  |  | 1317 |             break;
 | 
        
           |  |  | 1318 |             }
 | 
        
           |  |  | 1319 |         cC [ cIndex++ ] = cX;
 | 
        
           |  |  | 1320 |         }
 | 
        
           |  |  | 1321 |     cC [ cIndex ] = EOF;
 | 
        
           |  |  | 1322 |     return ( cIndex );         // return number of characters in field
 | 
        
           |  |  | 1323 |     }
 | 
        
           |  |  | 1324 |   | 
        
           |  |  | 1325 | #separate void SkipField ( char cCnt )
 | 
        
           |  |  | 1326 |     {
 | 
        
           |  |  | 1327 |     char cX;
 | 
        
           |  |  | 1328 |   | 
        
           |  |  | 1329 |     for ( cX = 0; cX < cCnt; cX++ )
 | 
        
           |  |  | 1330 |         {
 | 
        
           |  |  | 1331 |         while ( GetRxChar() != COMMA );
 | 
        
           |  |  | 1332 |         }
 | 
        
           |  |  | 1333 |     }
 | 
        
           |  |  | 1334 |   | 
        
           |  |  | 1335 | /* RS232 FUNCTIONS ================================================== */
 | 
        
           |  |  | 1336 |   | 
        
           |  |  | 1337 | #separate void InitRxBuffer ( char cCode )
 | 
        
           |  |  | 1338 |     {
 | 
        
           |  |  | 1339 |     disable_interrupts ( INT_RDA );
 | 
        
           |  |  | 1340 |     cRxBufferWritePtr = cRxBuffer;      // point to beginning of buffer
 | 
        
           |  |  | 1341 |     cRxBufferReadPtr = cRxBuffer;
 | 
        
           |  |  | 1342 |     cRxByteCnt = 0;
 | 
        
           |  |  | 1343 |     cRxIsrState = 0;
 | 
        
           |  |  | 1344 |     cRxMsgReady = NO;
 | 
        
           |  |  | 1345 |     cRxMsgTypeDesired = cCode;
 | 
        
           |  |  | 1346 |     enable_interrupts ( INT_RDA );
 | 
        
           |  |  | 1347 |     }
 | 
        
           |  |  | 1348 |   | 
        
           |  |  | 1349 | #separate char GetRxChar ( void )
 | 
        
           |  |  | 1350 |     {
 | 
        
           |  |  | 1351 |     // Get the next available byte in the recv fifo.
 | 
        
           |  |  | 1352 |     // Call this function ONLY if the recv fifo contains data.
 | 
        
           |  |  | 1353 |     char cValue;
 | 
        
           |  |  | 1354 |   | 
        
           |  |  | 1355 |     cValue = 0;
 | 
        
           |  |  | 1356 |     if ( cRxByteCnt > 0 )       // For safety, check if there is any data
 | 
        
           |  |  | 1357 |         {
 | 
        
           |  |  | 1358 |         cValue = *cRxBufferReadPtr++;     // Read byte from fifo
 | 
        
           |  |  | 1359 |         if ( cRxBufferReadPtr == ( cRxBuffer + RX_BUFFER_SIZE ) ) // Did tail ptr wrap ?
 | 
        
           |  |  | 1360 |             {
 | 
        
           |  |  | 1361 |             cRxBufferReadPtr = cRxBuffer;    // If so, reset it to start of buffer
 | 
        
           |  |  | 1362 |             }
 | 
        
           |  |  | 1363 |         cRxByteCnt--; // Decrement byte count
 | 
        
           |  |  | 1364 |         }
 | 
        
           |  |  | 1365 |     return ( cValue );
 | 
        
           |  |  | 1366 |     }
 | 
        
           |  |  | 1367 |   | 
        
           |  |  | 1368 | /* LCD FUNCTIONS ================================= */
 | 
        
           |  |  | 1369 |   | 
        
           |  |  | 1370 | #separate void LCD_Init ( void )
 | 
        
           |  |  | 1371 |     {
 | 
        
           |  |  | 1372 |     LCD_SetData ( 0x00 );
 | 
        
           |  |  | 1373 |     delay_ms ( 200 );       /* wait enough time after Vdd rise */
 | 
        
           |  |  | 1374 |     output_low ( LCD_RS );
 | 
        
           |  |  | 1375 |     LCD_SetData ( 0x03 );   /* init with specific nibbles to start 4-bit mode */
 | 
        
           |  |  | 1376 |     LCD_PulseEnable();
 | 
        
           |  |  | 1377 |     LCD_PulseEnable();
 | 
        
           |  |  | 1378 |     LCD_PulseEnable();
 | 
        
           |  |  | 1379 |     LCD_SetData ( 0x02 );   /* set 4-bit interface */
 | 
        
           |  |  | 1380 |     LCD_PulseEnable();      /* send dual nibbles hereafter, MSN first */
 | 
        
           |  |  | 1381 |     LCD_PutCmd ( 0x2C );    /* function set (all lines, 5x7 characters) */
 | 
        
           |  |  | 1382 |     LCD_PutCmd ( 0x0C );    /* display ON, cursor off, no blink */
 | 
        
           |  |  | 1383 |     LCD_PutCmd ( 0x01 );    /* clear display */
 | 
        
           |  |  | 1384 |     LCD_PutCmd ( 0x06 );    /* entry mode set, increment & scroll left */
 | 
        
           |  |  | 1385 |     }
 | 
        
           |  |  | 1386 |   | 
        
           |  |  | 1387 | #separate void LCD_SetPosition ( unsigned int cX )
 | 
        
           |  |  | 1388 |     {
 | 
        
           |  |  | 1389 |     /* this subroutine works specifically for 4-bit Port A */
 | 
        
           |  |  | 1390 |     LCD_SetData ( swap ( cX ) | 0x08 );
 | 
        
           |  |  | 1391 |     LCD_PulseEnable();
 | 
        
           |  |  | 1392 |     LCD_SetData ( swap ( cX ) );
 | 
        
           |  |  | 1393 |     LCD_PulseEnable();
 | 
        
           |  |  | 1394 |     }
 | 
        
           |  |  | 1395 |   | 
        
           |  |  | 1396 | #separate void LCD_PutChar ( unsigned int cX )
 | 
        
           |  |  | 1397 |     {
 | 
        
           |  |  | 1398 |     /* this subroutine works specifically for 4-bit Port A */
 | 
        
           |  |  | 1399 |     if ( !cSkip )
 | 
        
           |  |  | 1400 |         {
 | 
        
           |  |  | 1401 |         output_high ( LCD_RS );
 | 
        
           |  |  | 1402 |         LCD_SetData ( swap ( cX ) );     /* send high nibble */
 | 
        
           |  |  | 1403 |         LCD_PulseEnable();
 | 
        
           |  |  | 1404 |         LCD_SetData ( swap ( cX ) );     /* send low nibble */
 | 
        
           |  |  | 1405 |         LCD_PulseEnable();
 | 
        
           |  |  | 1406 |         output_low ( LCD_RS );
 | 
        
           |  |  | 1407 |         }
 | 
        
           |  |  | 1408 |     }
 | 
        
           |  |  | 1409 |   | 
        
           |  |  | 1410 | #separate void LCD_PutCmd ( unsigned int cX )
 | 
        
           |  |  | 1411 |     {
 | 
        
           |  |  | 1412 |     /* this subroutine works specifically for 4-bit Port A */
 | 
        
           |  |  | 1413 |     LCD_SetData ( swap ( cX ) );     /* send high nibble */
 | 
        
           |  |  | 1414 |     LCD_PulseEnable();
 | 
        
           |  |  | 1415 |     LCD_SetData ( swap ( cX ) );     /* send low nibble */
 | 
        
           |  |  | 1416 |     LCD_PulseEnable();
 | 
        
           |  |  | 1417 |     }
 | 
        
           |  |  | 1418 |   | 
        
           |  |  | 1419 | #separate void LCD_PulseEnable ( void )
 | 
        
           |  |  | 1420 |     {
 | 
        
           |  |  | 1421 |     output_high ( LCD_EN );
 | 
        
           |  |  | 1422 |     delay_us ( 3 );         // was 10
 | 
        
           |  |  | 1423 |     output_low ( LCD_EN );
 | 
        
           |  |  | 1424 |     delay_ms ( 3 );         // was 5
 | 
        
           |  |  | 1425 |     }
 | 
        
           |  |  | 1426 |   | 
        
           |  |  | 1427 | #separate void LCD_SetData ( unsigned int cX )
 | 
        
           |  |  | 1428 |     {
 | 
        
           |  |  | 1429 |     output_bit ( LCD_D0, cX & 0x01 );
 | 
        
           |  |  | 1430 |     output_bit ( LCD_D1, cX & 0x02 );
 | 
        
           |  |  | 1431 |     output_bit ( LCD_D2, cX & 0x04 );
 | 
        
           |  |  | 1432 |     output_bit ( LCD_D3, cX & 0x08 );
 | 
        
           |  |  | 1433 |     }
 | 
        
           |  |  | 1434 |   |