////////////////////////////////////////////////////////////////////////////////
//                     PIC16F88 Delorme Tripmate GPS Logger
//
// Filename     : 16F88 - 24LC1025 GPS Compress DR1r4.c
// Programmer   : Steven Cholewiak, www.semifluid.com
// Version      : Version 1.4 - 01/26/2007
// Remarks      : DR1r4 is the initial release
//
//                More information on the circuit can be found at:
//                http://semifluid.com/?p=43
////////////////////////////////////////////////////////////////////////////////

#include <16F88.h>
#fuses INTRC_IO, MCLR, NOWDT, NOBROWNOUT, NOPROTECT, NOLVP, NODEBUG
#use delay(clock=8000000)
#use rs232(stream=PC, baud=4800, parity=N, bits=8, xmit=PIN_B5, rcv=PIN_B2, ERRORS)

#define EEPROM_SDA   PIN_B7
#define EEPROM_SCL   PIN_B6
#define pinButton    PIN_A2
#define pinLEDEEPROM PIN_A0
#define pinLEDSTATUS PIN_A4

#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL)

#build(reset=0x1, interrupt=0x5)
#ORG 0x0F00,0x0FFF {}

#include <241025multi.c>
#include <STDLIB.H>
#include <MATH.H>

#define BUFFER_SIZE 50
int8 buffer[BUFFER_SIZE];
int8 next_in = 0;
int8 next_out = 0;

#INT_RDA
void serial_isr() {                       // Serial Interrupt
   int t;

   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
     next_in=t;           // Buffer full !!
}

#define bkbhit (next_in!=next_out)

int8 bgetc() {
   BYTE c;

   WHILE(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
}

float convertPos(int16 theHandM, int16 theFM) {
   int16 Hours = 0.0;
   float Minutes = 0.0;
   float Seconds = 0.0;

   Hours = theHandM/100;
   Minutes = (float) theHandM - (Hours*100);
   Seconds = (float)theFM*60;
   Seconds = Seconds/10000;
   return (Hours + (Minutes/60) + (Seconds/3600));
}

int16 bread16(int8 theEndChar) {
   int8 tempChar = 0;
   int8 tempString[8];
   int8 tPointer = 0;
   int8 *ePointer;

   tPointer = 0;
   tempChar = bgetc();
   WHILE (tempChar != theEndChar) {
      tempString[tPointer] = tempChar; tPointer++;
      tempChar = bgetc();
   }
   tempString[tPointer] = 0;
   return strToUL(tempString, ePointer, 10);
}

void main() {
   int1 readData = FALSE;
   int1 dataOK = FALSE;
   int8 n = 0;
   int32 i =0;
   int8 theChar = 0;
   int16 HoursAndMinutes = 0;
   int16 FractionalMinutes = 0;
   float thePos = 0.0;

   SETUP_OSCILLATOR(OSC_8MHZ);
   SETUP_ADC_PORTS(NO_ANALOGS);
   SETUP_ADC(ADC_OFF);
   SETUP_COMPARATOR(NC_NC_NC_NC);
   SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_1);
   SETUP_TIMER_1(T1_DISABLED);
   SETUP_TIMER_2(T2_DISABLED,0,1);

   enable_interrupts(global);
   enable_interrupts(int_rda);

   OUTPUT_HIGH(pinLEDSTATUS);

   init_ext_eeprom();

   delay_ms(50);

   if (INPUT(pinButton)) readData = TRUE;
   else readData = FALSE;

   delay_ms(250);

   if (!readData) {
      // Wait until button it pressed to start
      WHILE (!INPUT(pinButton));

      dataOK = FALSE;
      OUTPUT_LOW(pinLEDSTATUS);

      WHILE (i<EEPROM_SIZE) {
         WHILE (theChar != '$') theChar = bgetc();                              // Look for a '$' - the start of a NMEA sentence
         theChar = bgetc();
         IF (theChar == 'G') {
            theChar = bgetc();
            IF (theChar == 'P') {
               theChar = bgetc();
               IF (theChar == 'R') {
                  theChar = bgetc();
                  IF (theChar == 'M') {
                     theChar = bgetc();
                     IF (theChar == 'C') {
                        theChar = bgetc();                                       // Discard ','

                        OUTPUT_HIGH(pinLEDEEPROM);

                        theChar = bgetc();                                       // Discard Time
                        WHILE (theChar != ',') theChar = bgetc();

                        theChar = bgetc();                                       // Use Navigation Receiver Warning
                        if (theChar == 'A') {
                           dataOK = TRUE;
                           OUTPUT_HIGH(pinLEDSTATUS);
                        }
                        else dataOK = FALSE;
                        theChar = bgetc();                                       // Discard ','

                        if (dataOK) {
                           HoursAndMinutes = bread16('.');                       // Save Latitude Hours and Minutes
                           write_ext_eeprom(0,i,MAKE8(HoursAndMinutes,1)); i++;
                           write_ext_eeprom(0,i,MAKE8(HoursAndMinutes,0)); i++;

                           FractionalMinutes = bread16(',');                     // Save Latitude Fractional Minutes
                           write_ext_eeprom(0,i,MAKE8(FractionalMinutes,1)); i++;
                           write_ext_eeprom(0,i,MAKE8(FractionalMinutes,0)); i++;

                           theChar = bgetc();                                    // Save Latitude North/South
                           write_ext_eeprom(0,i,theChar); i++;
                           theChar = bgetc();                                    // Discard ','
                           write_ext_eeprom(0,i,','); i++;

                           HoursAndMinutes = bread16('.');                       // Save Longitude Hours and Minutes
                           write_ext_eeprom(0,i,MAKE8(HoursAndMinutes,1)); i++;
                           write_ext_eeprom(0,i,MAKE8(HoursAndMinutes,0)); i++;

                           FractionalMinutes = bread16(',');                     // Save Longitude Fractional Minutes
                           write_ext_eeprom(0,i,MAKE8(FractionalMinutes,1)); i++;
                           write_ext_eeprom(0,i,MAKE8(FractionalMinutes,0)); i++;

                           theChar = bgetc();                                    // Save Longitude East/West
                           write_ext_eeprom(0,i,theChar); i++;

                           write_ext_eeprom(0,i,13); i++;                        // Add a carriage return to the end
                        }

                        OUTPUT_LOW(pinLEDSTATUS);
                        OUTPUT_LOW(pinLEDEEPROM);
                     }
                  }
               }
            }
         }
      }
   }
   else {
      OUTPUT_LOW(pinLEDSTATUS);

      WHILE (i<EEPROM_SIZE) {
         OUTPUT_TOGGLE(pinLEDEEPROM);
         HoursAndMinutes = Make16(read_ext_eeprom(0,i),read_ext_eeprom(0,i+1)); i++; i++;
         FractionalMinutes = Make16(read_ext_eeprom(0,i),read_ext_eeprom(0,i+1)); i++; i++;
         thePos = convertPos(HoursAndMinutes,FractionalMinutes);
         n = read_ext_eeprom(0,i); i++;
         if (n == 'S') thePos = -thePos;
         n = read_ext_eeprom(0,i); i++;
         fprintf(PC,"%f,", thePos);

         HoursAndMinutes = Make16(read_ext_eeprom(0,i),read_ext_eeprom(0,i+1)); i++; i++;
         FractionalMinutes = Make16(read_ext_eeprom(0,i),read_ext_eeprom(0,i+1)); i++; i++;
         thePos = convertPos(HoursAndMinutes,FractionalMinutes);
         n = read_ext_eeprom(0,i); i++;
         if (n == 'W') thePos = -thePos;
         n = read_ext_eeprom(0,i); i++;
         fprintf(PC,"%f\r\n",thePos);

      }
      OUTPUT_LOW(pinLEDEEPROM);
   }

   WHILE (TRUE) {
      OUTPUT_TOGGLE(pinLEDSTATUS);
      delay_ms(500);
   }
}

