Skip to content

Commit

Permalink
FIX: RMC failed to parse milliseconds
Browse files Browse the repository at this point in the history
  • Loading branch information
becseya committed Feb 10, 2023
1 parent 5221ca4 commit bfc6ba2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 41 deletions.
4 changes: 2 additions & 2 deletions codecs/RMC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* 13. Checksum
*/

import { parseDatetime, parseFloatSafe, parseLatitude, parseLongitude } from "../helpers";
import { parseFloatSafe, parseLatitude, parseLongitude, parseTime } from "../helpers";
import { initStubFields, PacketStub } from "./PacketStub";


Expand All @@ -50,7 +50,7 @@ export interface RMCPacket extends PacketStub<typeof sentenceId> {
export function decodeSentence(stub: PacketStub, fields: string[]): RMCPacket {
return {
...initStubFields(stub, sentenceId, sentenceName),
datetime: parseDatetime(fields[9], fields[1]),
datetime: parseTime(fields[1], fields[9], true),
status: fields[2] === "A" ? "valid" : "warning",
latitude: parseLatitude(fields[3], fields[4]),
longitude: parseLongitude(fields[5], fields[6]),
Expand Down
67 changes: 29 additions & 38 deletions helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,41 @@ export function parseLongitude(lon: string, hemi: string): number {
return parseDmCoordinate(lon) * hemisphere;
}

function getYearFromString(yearString: string, rmcCompatible: boolean): number {
if (yearString.length === 4) {
return Number(yearString);
} else if (yearString.length === 2) {
if (rmcCompatible) {
// GPRMC date doesn't specify century. GPS came out in 1973 so if the year
// is less than 73, assume it's 20xx, otherwise assume it is 19xx.
let year = Number(yearString);

if (year < 73) {
year = 2000 + year;
}
else {
year = 1900 + year;
}

return year;
}
else {
return Number("20" + yearString);
}
}
else {
throw Error(`Unexpected year string: ${yearString}`);
}
}

/**
* Parses a UTC time and optionally a date and returns a Date
* object.
* @param {String} time Time the format "hhmmss" or "hhmmss.ss"
* @param {String=} date Optional date in format the ddmmyyyy or ddmmyy
* @returns {Date}
*/
export function parseTime(time: string, date?: string): Date {
export function parseTime(time: string, date?: string, rmcCompatible = false): Date {

if (time === "") {
return new Date(0);
Expand All @@ -358,14 +385,7 @@ export function parseTime(time: string, date?: string): Date {
const month = parseInt(date.slice(2, 4), 10) - 1;
const day = date.slice(0, 2);

if (year.length === 4) {
ret.setUTCFullYear(Number(year), Number(month), Number(day));
} else {
// If we need to parse older GPRMC data, we should hack something like
// year < 73 ? 2000+year : 1900+year
// Since GPS appeared in 1973
ret.setUTCFullYear(Number("20" + year), Number(month), Number(day));
}
ret.setUTCFullYear(getYearFromString(year, rmcCompatible), Number(month), Number(day));
}

ret.setUTCHours(Number(time.slice(0, 2)));
Expand All @@ -383,32 +403,3 @@ export function parseTime(time: string, date?: string): Date {

return ret;
}


/**
* Parses a date in the format "yyMMdd" along with a time in the format
* "hhmmss" or "hhmmss.ss" and returns a Date object.
*/
export function parseDatetime(date: string, time: string): Date {
const day = parseInt(date.slice(0, 2), 10);
const month = parseInt(date.slice(2, 4), 10);
let year = parseInt(date.slice(4, 6), 10);
// GPRMC date doesn't specify century. GPS came out in 1973 so if the year
// is less than 73, assume it's 20xx, otherwise assume it is 19xx.
if (year < 73) {
year = year + 2000;
}
else {
year = year + 1900;
}

const hours = parseInt(time.slice(0, 2), 10);
const minutes = parseInt(time.slice(2, 4), 10);
const seconds = parseInt(time.slice(4, 6), 10);
let milliseconds = 0;
if (time.length === 9) {
milliseconds = parseInt(time.slice(7, 9), 10) * 10;
}

return new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds, milliseconds));
}
11 changes: 10 additions & 1 deletion tests/RMCtest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "should";

import { parseNmeaSentence } from "../index";
import { assertPacketIs, parseNmeaSentence } from "../index";


describe("RMC", (): void => {
Expand All @@ -21,4 +21,13 @@ describe("RMC", (): void => {
packet.should.have.property("variationPole", "W");
});

it("miliseconds", (): void => {
const packet = parseNmeaSentence("$GNRMC,123411.200,A,4721.2973,N,01906.6971,E,16.19,142.59,040223,,,A,V*37");
assertPacketIs("RMC", packet);
packet.datetime.getMilliseconds().should.equal(200);

const packet2 = parseNmeaSentence("$GPRMC,123409.886,V,,,,,16.10,145.36,040223,,,N,V*08");
assertPacketIs("RMC", packet2);
packet2.datetime.getMilliseconds().should.equal(886);
});
});

0 comments on commit bfc6ba2

Please sign in to comment.