Subversion Repositories dashGPS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
/*
2
 * nmea.c
3
 *
4
 *  Created on: 6 Sep 2020
5
 *      Author: mike
6
 */
7
 
4 mjames 8
#include <math.h>
9
#include <stdint.h>
10
#include <stdlib.h>
11
 
2 mjames 12
#include "nmea.h"
13
 
14
#include "libSerial/serial.h"
15
 
16
char linebuff[80];
17
unsigned linePos = 0;
18
 
19
typedef enum
20
{
21
  SEARCH, READING
22
} NmeaState_t;
23
 
24
NmeaState_t lineState = SEARCH;
25
 
9 mjames 26
static bool
2 mjames 27
decodePacket (char *linebuff, int linePos, Location *loc);
28
 
9 mjames 29
bool
2 mjames 30
updateLocation (Location *loc)
31
{
32
  while (1)
33
    {
34
      if (!SerialCharsReceived (&uc1))
35
        return false; // nothing to read, return immediately
36
 
37
      char c = GetCharSerial (&uc1);
38
      switch (lineState)
39
        {
40
        case SEARCH:
41
          if (c == '$')
42
            lineState = READING;
9 mjames 43
          linePos = 0;
2 mjames 44
          break;
45
        case READING:
46
          if (c == '\r')
47
            {
48
              // handle the read code
9 mjames 49
              bool success = decodePacket (linebuff, linePos, loc);
2 mjames 50
              lineState = SEARCH;
51
 
52
              linePos = 0;
53
              return success;
54
            }
55
          if (linePos < sizeof(linebuff))
56
            linebuff[linePos++] = c;
57
          else
58
            {
59
              lineState = SEARCH;
9 mjames 60
              // search for the $  in any unread string
61
              int i;
62
 
63
              for (i = 0; i < linePos; i++)
64
                if (linebuff[i] == '$')
65
                  {
66
                    int n = i+1;
67
                    memcpy (linebuff, linebuff + n, linePos - i);
68
                    linePos = linePos - i;
69
                    linebuff[linePos++] = c;
70
                    lineState = READING;
71
                  }
72
 
73
              if (lineState == SEARCH)
74
                linePos = 0;
2 mjames 75
            }
76
          break;
77
        }
78
    }
79
  return 0;
80
}
81
 
4 mjames 82
static uint8_t
2 mjames 83
decodeHex (char c)
84
{
85
  if (c >= '0' && c <= '9')
86
    return c - '0';
87
  c = tolower (c);
88
  if (c >= 'a' && c <= 'f')
89
    return c - 'a' + 10;
90
  return 0;
91
}
92
 
4 mjames 93
// lat/long decoder
94
static float
95
decodeLL (char *ptr, int msDigitWeight)
96
{
97
  float digitWeight = msDigitWeight;
98
  float result = 0;
99
  int i = 0;
100
  while (1)
101
    {
102
      char c = ptr[i++];
103
      if (c == '.')
104
        continue;
105
      if (c >= '0' && c <= '9')
106
        {
107
          result += digitWeight * (c - '0');
108
          if (fabs (digitWeight - 1) < 0.01)
109
            digitWeight = 1 / 6.0;
110
          else
111
            digitWeight = digitWeight / 10;
112
 
113
          continue;
114
        }
115
      break;
116
    }
117
 
118
  return result;
119
 
120
}
121
 
9 mjames 122
static float
123
decodeFP (char *ptr)
4 mjames 124
{
9 mjames 125
  return strtof (ptr, NULL);
4 mjames 126
}
127
 
9 mjames 128
bool
2 mjames 129
decodePacket (char *linebuff, int linePos, Location *loc)
130
{
5 mjames 131
  uint8_t checksum = 0;
2 mjames 132
  for (int i = 0; i < linePos - 3; i++)
133
    checksum ^= linebuff[i];
134
  uint8_t givenSum = (decodeHex (linebuff[linePos - 2]) << 4)
135
      + decodeHex (linebuff[linePos - 1]);
136
  if (givenSum != checksum)
9 mjames 137
    return false;
2 mjames 138
 
139
  char *fieldPos[20];
140
  int fieldCnt = 0;
141
  // split fields
4 mjames 142
  for (int i = 5; i < linePos - 3; i++)
2 mjames 143
    {
144
      if (linebuff[i] == ',')
145
        {
146
          fieldPos[fieldCnt++] = linebuff + i + 1;
147
        }
4 mjames 148
 
2 mjames 149
    }
150
 
9 mjames 151
  // decode RMC
4 mjames 152
  if (linebuff[2] == 'R' && linebuff[3] == 'M' && linebuff[4] == 'C')
2 mjames 153
 
154
    {
3 mjames 155
      // decode the fields
9 mjames 156
      memcpy (loc->time, fieldPos[0], 6);
4 mjames 157
      loc->valid = *fieldPos[1];
158
      loc->lat = decodeLL (fieldPos[2], 10);
159
      loc->ns = *fieldPos[3];
160
      loc->lon = decodeLL (fieldPos[4], 100);
161
      loc->ew = *fieldPos[5];
9 mjames 162
      loc->speed = decodeFP (fieldPos[6]);
4 mjames 163
      loc->heading = decodeFP (fieldPos[7]);
9 mjames 164
      loc->good = true;
4 mjames 165
    }
9 mjames 166
  return true;
2 mjames 167
}