Skip to content

Commit

Permalink
NMEA-PARSER: v.2.1.0
Browse files Browse the repository at this point in the history
NMEA-PARSER: v.2.1.0
  • Loading branch information
crisconru authored Jul 22, 2024
2 parents 5d770ff + 1f1ef71 commit 8e3de29
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/nmea-parser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ jobs:

- name: 🧑‍🔬 Tests
run: "npm run nmea-parser:test"

- name: 🛠️ Build
run: "npm run nmea-parser:build"

publish:
name: 🚀 Publish
Expand Down
76 changes: 76 additions & 0 deletions packages/nmea-parser/src/nmea-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Float64, NMEASentence, Uint8 } from './types'

const metadataGGA = (sentence: NMEASentence): NMEASentence => {
const getLatitudeDegrees = (latitude: string, letter: string): Float64 => {
const [left, minutesRight] = latitude.split('.')
const degrees = left.slice(0, -2)
// console.log(`Lat: Degrees = ${degrees}`)
const minutesLeft = left.slice(-2)
const sign = (letter === 'S') ? -1 : 1
const minutes = `${minutesLeft}.${minutesRight}`
// console.log(`Lat: Minutes ${minutes}`)
return sign * (Number(degrees) + (Number(minutes) / 60))
}

const getLongitudeDegrees = (longitude: string, letter: string): Float64 => {
const [left, minutesRight] = longitude.split('.')
const degrees = left.slice(0, -2)
// console.log(`Lon: Degrees = ${degrees}`)
const minutesLeft = left.slice(-2)
const sign = (letter === 'W') ? -1 : 1
const minutes = `${minutesLeft}.${minutesRight}`
// console.log(`Lon: Minutes ${minutes}`)
return sign * (Number(degrees) + (Number(minutes) / 60))
}

const getQuality = (quality: Uint8): string => {
const QUALITIES = {
0: 'Fix not valid',
1: 'GPS fix',
2: 'Differential GPS fix (DGNSS), SBAS, OmniSTAR VBS, Beacon, RTX in GVBS mode',
3: 'Not applicable',
4: 'RTK Fixed, xFill',
5: 'RTK Float, OmniSTAR XP/HP, Location RTK, RTX',
6: 'INS Dead reckoning',
7: 'Manual Input Mode',
8: 'Simulator Mode'
}
return QUALITIES[quality as keyof typeof QUALITIES] ?? 'unknown'
}

sentence.payload.forEach((field, index) => {
// Latitude
if (field.name === 'latitude') {
const latitude = field.value as string
const letter = sentence.payload[index + 1].value as string
const degrees = getLatitudeDegrees(latitude, letter)
sentence.metadata = { latitude: degrees }
return
}
// Longitude
if (field.name === 'longitude') {
const longitude = field.value as string
const letter = sentence.payload[index + 1].value as string
const degrees = getLongitudeDegrees(longitude, letter)
sentence.metadata = { longitude: degrees }
return
}
// Quality
if (field.name === 'quality') {
sentence.metadata = { quality: getQuality(field.value as Uint8) }
// return
}
// Rest
// return
})
return { ...sentence }
}

const METADATA = {
GGA: metadataGGA
}

export const addMetadata = (sentence: NMEASentence): NMEASentence => {
if (sentence.id in METADATA) { return METADATA[sentence.id as keyof typeof METADATA](sentence) }
return sentence
}
6 changes: 3 additions & 3 deletions packages/nmea-parser/src/nmea-sentences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const NMEA_SENTENCES: ProtocolsFileContent = {
{
name: 'latitude',
type: 'string',
units: 'deg'
units: 'deg-min'
},
{
name: 'latitude_direction',
Expand All @@ -58,15 +58,15 @@ export const NMEA_SENTENCES: ProtocolsFileContent = {
{
name: 'longitude',
type: 'string',
units: 'deg'
units: 'deg-min'
},
{
name: 'longitude_direction',
type: 'string',
description: 'E - East\n W - West'
},
{
name: 'gps_quality',
name: 'quality',
type: 'int8',
description: '0: Fix not valid\n 1: GPS fix\n 2: Differential GPS fix (DGNSS), SBAS, OmniSTAR VBS, Beacon, RTX in GVBS mode\n 3: Not applicable\n 4: RTK Fixed, xFill\n 5: RTK Float, OmniSTAR XP/HP, Location RTK, RTX\n 6: INS Dead reckoning\n 7: Manual Input Mode\n 8: Simulator Mode'
},
Expand Down
1 change: 0 additions & 1 deletion packages/nmea-parser/src/nmea.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/nmea-parser/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ const ValibotNMEASentenceSchema = v.object({
description: v.optional(ValibotStringSchema),
checksum: ValibotChecksumSchema,
payload: v.array(ValibotNMEAParsedFieldSchema),
metadata: v.optional(v.any()),
protocol: v.optional(
v.object({
name: ValibotStringSchema,
Expand Down
6 changes: 4 additions & 2 deletions packages/nmea-parser/src/sentences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CHECKSUM_LENGTH, DELIMITER, END_FLAG, END_FLAG_LENGTH, MINIMAL_LENGTH,
import { Float32Schema, Float64Schema, Int16Schema, Int32Schema, Int64Schema, Int8Schema, NMEASentenceSchema, Uint16Schema, Uint32Schema, Uint64Schema, Uint8Schema } from './schemas'
import type { Checksum, NMEALike, NMEASentence, Payload, ProtocolFieldType, StoredSentence, Talker, Value } from './types'
import { isLowerCharASCII, isNumberCharASCII, isUpperCharASCII } from './utils'
import { addMetadata } from './nmea-metadata'

export const lastUncompletedFrame = (text: string): string | null => {
// Start of last possible frame
Expand Down Expand Up @@ -137,15 +138,16 @@ export const getKnownNMEASentence = (
})
const { protocol } = model
// TODO: Metada -> GGA Latitude-Longitude degrees
const sent: NMEASentence = {
const nmeaSentence: NMEASentence = {
received,
sample,
id: sentenceID,
checksum,
payload,
protocol
}
return NMEASentenceSchema.parse(sent)
const nmeaSentenceWithMetadata = addMetadata(nmeaSentence)
return NMEASentenceSchema.parse(nmeaSentenceWithMetadata)
}

export const getTalker = (sentenceID: string): Talker | null => {
Expand Down
2 changes: 1 addition & 1 deletion packages/nmea-parser/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe('Parser', () => {
const parser = new Parser()
parser.addProtocols({ file: NORSUB_FILE })
const storedSentences = parser.getSentences()
const fakeinput = storedSentences.reduce((acc, curr) => acc += createFakeSentence(curr), '')
const fakeinput = storedSentences.reduce((acc, curr) => acc + createFakeSentence(curr), '')
const output = parser.parseData(fakeinput)
expect(output.length).toBe(storedSentences.length)
})
Expand Down

0 comments on commit 8e3de29

Please sign in to comment.