UNPKG

obniz

Version:

obniz sdk for javascript

334 lines (333 loc) 13 kB
"use strict"; /** * @packageDocumentation * @module Parts.Grove_GPS */ Object.defineProperty(exports, "__esModule", { value: true }); class Grove_GPS { constructor() { this._latitude = 0; this._longitude = 0; this.keys = ['tx', 'rx', 'vcc', 'gnd', 'grove']; this.requiredKeys = []; this.ioKeys = this.keys; this.displayName = 'gps'; this.displayIoNames = { tx: 'tx', rx: 'rx' }; } // ------------------- get latitude() { return this.nmea2dd(this._latitude); } get longitude() { return this.nmea2dd(this._longitude); } static info() { return { name: 'Grove_GPS', }; } wired(obniz) { this.obniz = obniz; if (this.params.grove) { this.uart = this.params.grove.getUart(9600, '5v'); } else { this.obniz.setVccGnd(this.params.vcc, this.params.gnd, '5v'); this.uart = obniz.getFreeUart(); this.uart.start({ tx: this.params.tx, rx: this.params.rx, baud: 9600, }); } this.editedData = {}; this.editedData.enable = false; this.editedData.GPGSV = new Array(4); this.gpsInfo = {}; this.gpsInfo._sentenceType = { GPGGA: 0x0001, GPGSA: 0x0002, GPGSV: 0x0004, GPRMC: 0x0008, GPVTG: 0x0010, GPZDA: 0x0020, // ZDA - Date & Time }; this.gpsInfo.status = 'V'; this.gpsInfo.sentences = new Set(); // Set specifying sentence of MNEA from which data have been obtained this.gpsInfo.satelliteInfo = { satellites: [], inView: 0, }; } readSentence() { let results = []; if (this.uart.isDataExists()) { const pos = this.uart.received.indexOf(0x0a); if (pos >= 0) { results = this.uart.received.slice(0, pos - 1); this.uart.received.splice(0, pos + 1); let str = this.uart.tryConvertString(results); if (str === null) { str = ''; } return str; } } return ''; } getEditedData() { let n; let utc; let format; let sentence = this.readSentence(); this.editedData.enable = false; this.editedData.GPGSV = new Array(4); while (sentence.length > 0) { const part = sentence.split(','); if (sentence.slice(-4, -3) !== ',') { const st = part[part.length - 1].slice(0, -3); part.push(part[part.length - 1].slice(-3)); part[part.length - 2] = st; } this.editedData.sentence = part.join(','); switch (part[0]) { case '$GPGGA': this.editedData.GPGGA = part; break; case '$GPGLL': this.editedData.GPGLL = part; break; case '$GPGSA': this.editedData.GPGSA = part; break; case '$GPGSV': n = Number(part[2]); if (n > this.editedData.GPGSV.length) { while (n > this.editedData.GPGSV.length) { this.editedData.GPGSV.push([]); } } this.editedData.GPGSV[n - 1] = part; break; case '$GPRMC': this.editedData.GPRMC = part; break; case '$GPVTG': this.editedData.GPVTG = part; break; case '$GPZDA': this.editedData.GPZDA = part; utc = part[4] + '/' + part[3] + '/' + part[2] + ' ' + part[1].substring(0, 2) + ':' + part[1].substring(2, 4) + ':' + part[1].substring(4, 6) + ' +00:00'; this.editedData.timestamp = new Date(utc); break; default: format = part[0].substr(1); this.editedData[format] = part; } this.editedData.enable = true; sentence = this.readSentence(); } return this.editedData; } getGpsInfo(editedData) { const NMEA_SATINSENTENCE = 4; const NMEA_MAXSAT = 12; editedData = editedData || this.getEditedData(); this.gpsInfo.status = 'V'; if (editedData.enable) { if (editedData.GPGGA) { const gga = editedData.GPGGA; this.gpsInfo.gpsQuality = parseFloat(gga[6]); // Fix Quality: 0 = Invalid, 1 = GPS fix, 2 = DGPS fix this.gpsInfo.hdop = parseFloat(gga[8]); // Horizontal Dilution of Precision (HDOP) this.gpsInfo.altitude = parseFloat(gga[9]); // Antenna Altitude meters above mean sea level const latitude = this.nmea2dd(parseFloat(gga[2])); this.gpsInfo.latitude = gga[3] === 'N' ? latitude : -latitude; const longitude = this.nmea2dd(parseFloat(gga[4])); this.gpsInfo.longitude = gga[5] === 'E' ? longitude : -longitude; this.gpsInfo.sentences.add(this.gpsInfo._sentenceType.GPGGA); } if (editedData.GPGSV) { for (let n = 0; n < editedData.GPGSV.length; n++) { if (editedData.GPGSV[n]) { const gsv = editedData.GPGSV[n].map((v) => parseFloat(v)); const pack_count = gsv[1]; const pack_index = gsv[2]; const sat_count = gsv[3]; if (pack_index > pack_count) { continue; } this.gpsInfo.satelliteInfo.inView = sat_count; let nsat = (pack_index - 1) * NMEA_SATINSENTENCE; nsat = nsat + NMEA_SATINSENTENCE > sat_count ? sat_count - nsat : NMEA_SATINSENTENCE; for (let isat = 0; isat < nsat; ++isat) { const isi = (pack_index - 1) * NMEA_SATINSENTENCE + isat; if (this.gpsInfo.satelliteInfo.satellites.length <= isi) { this.gpsInfo.satelliteInfo.satellites.push({}); } const isatn = isat * NMEA_SATINSENTENCE; this.gpsInfo.satelliteInfo.satellites[isi] = { id: gsv[isatn + 4], elevation: gsv[isatn + 5], azimuth: gsv[isatn + 6], snr: gsv[isatn + 7], inUse: false, }; } this.gpsInfo.sentences.add(this.gpsInfo._sentenceType.GPGSV); } } } if (editedData.GPGSA) { const gsa = editedData.GPGSA; let nuse = 0; this.gpsInfo.fixMode = parseFloat(gsa[2]); // Fix Mode: 1=Fix not available, 2=2D, 3=3D this.gpsInfo.pdop = parseFloat(gsa[15]); // PDOP: Position Dilution of Precision this.gpsInfo.hdop = parseFloat(gsa[16]); // HDOP: Horizontal Dilution of Precision this.gpsInfo.vdop = parseFloat(gsa[17]); // VDOP: Vertical Dilution of Position for (let i = 0; i < NMEA_MAXSAT; ++i) { for (let j = 0; j < this.gpsInfo.satelliteInfo.inView; ++j) { if (this.gpsInfo.satelliteInfo.satellites[j] && gsa[i + 3] === this.gpsInfo.satelliteInfo.satellites[j].id) { this.gpsInfo.satelliteInfo.satellites[j].inUse = true; nuse++; } } } this.gpsInfo.satelliteInfo.inUse = nuse; this.gpsInfo.sentences.add(this.gpsInfo._sentenceType.GPGSA); } if (editedData.GPRMC) { const rmc = editedData.GPRMC; this.gpsInfo.status = rmc[2]; // Status Active or Void const latitude = this.nmea2dd(parseFloat(rmc[3])); this.gpsInfo.latitude = rmc[4] === 'N' ? latitude : -latitude; const longitude = this.nmea2dd(parseFloat(rmc[5])); this.gpsInfo.longitude = rmc[6] === 'E' ? longitude : -longitude; const NMEA_TUD_KNOTS = 1.852; // 1knot=1.852km/h this.gpsInfo.speed = parseFloat(rmc[7]) * NMEA_TUD_KNOTS; // unit: km/h this.gpsInfo.direction = rmc[8]; this.gpsInfo.sentences.add(this.gpsInfo._sentenceType.GPRMC); } if (editedData.GPVTG) { const vtg = editedData.GPVTG; this.gpsInfo.direction = parseFloat(vtg[1]); this.gpsInfo.declination = parseFloat(vtg[3]); this.gpsInfo.speed = parseFloat(vtg[7]); this.gpsInfo.sentences.add(this.gpsInfo._sentenceType.GPVTG); } if (editedData.GPZDA) { this.gpsInfo.utc = editedData.timestamp; this.gpsInfo.sentences.add(this.gpsInfo._sentenceType.GPZDA); } } return this.gpsInfo; } _mneaTo(format, value) { let result = this.nmea2dd(value); if (typeof format === 'string') { switch (format.toUpperCase()) { case 'DMS': result = this.nmea2dms(value); break; case 'DM': result = this.nmea2dm(value); break; case 'S': result = this.nmea2s(value); break; default: } } return result; } latitudeTo(format) { return this._mneaTo(format, this._latitude); } longitudeTo(format) { return this._mneaTo(format, this._longitude); } status2string(status) { status = status || this.status; if (status === 'A') { return 'Active'; } if (status === 'V') { return 'Void'; } return status; } fixMode2string(fixMode) { fixMode = fixMode || this.fixMode; if (fixMode === 1) { return 'Fix not available'; } if (fixMode === 2) { return '2D'; } if (fixMode === 3) { return '3D'; } return fixMode; } gpsQuality2string(gpsQuality) { gpsQuality = gpsQuality || this.gpsQuality; if (gpsQuality === 0) { return 'Invalid'; } if (gpsQuality === 1) { return 'GPS fix'; } if (gpsQuality === 2) { return 'DGPS fix'; } return gpsQuality; } // --- latitude/longitude MNEA format change to each unit nmea2dms(val) { // NMEA format to DMS format string (999° 99'99.9") val = parseFloat(val); const d = Math.floor(val / 100); const m = Math.floor((val / 100.0 - d) * 100.0); const s = ((val / 100.0 - d) * 100.0 - m) * 60; return d + '°' + m + "'" + s.toFixed(1) + '"'; } nmea2dm(val) { // NMEA format to DM format string (999° 99.9999') val = parseFloat(val); const d = Math.floor(val / 100.0); const m = (val / 100.0 - d) * 100.0; return d + '°' + m.toFixed(4) + "'"; } nmea2dd(val) { // NMEA format to DD format decimal (999.999999) val = parseFloat(val); const d = Math.floor(val / 100.0); const m = Math.floor(((val / 100.0 - d) * 100.0) / 60); const s = (((val / 100.0 - d) * 100.0 - m) * 60) / (60 * 60); return parseFloat((d + m + s).toFixed(6)); } nmea2s(val) { // NMEA format to S format decimal (99999.9999) val = parseFloat(val); const d = Math.floor(val / 100.0); const m = Math.floor(((val / 100.0 - d) * 100.0) / 60); const s = (((val / 100.0 - d) * 100.0 - m) * 60) / (60 * 60); return (d + m + s) / (1.0 / 60.0 / 60.0); } } exports.default = Grove_GPS;