Subversion Repositories svnkaklik

Rev

Rev 6 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log

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