UNPKG

obniz

Version:

obniz sdk for javascript

342 lines (325 loc) 11.3 kB
class GYSFDMAXB { constructor() { this.keys = ['vcc', 'txd', 'rxd', 'gnd', 'Opps']; this.requiredKeys = ['txd', 'rxd']; this.ioKeys = this.keys; this.displayName = 'gps'; this.displayIoNames = { txd: 'txd', rxd: 'rxd', Opps: '1pps' }; } static info() { return { name: 'GYSFDMAXB', }; } wired(obniz) { this.obniz = obniz; this.tx = this.params.txd; this.rx = this.params.rxd; this.vcc = this.params.vcc; this.gnd = this.params.gnd; this.Opps = this.params.Opps; this.obniz.setVccGnd(this.params.vcc, this.params.gnd, '5v'); this.uart = obniz.getFreeUart(); this.uart.start({ tx: this.params.txd, rx: this.params.rxd, baud: 9600, drive: '3v', }); this.editedData = {}; this.editedData.enable = false; this.editedData.GPGSV = new Array(4); this.on1pps = null; this.last1pps = 0; this.gpsInfo = {}; this.gpsInfo._sentenceType = { GPGGA: 0x0001, // GGA - Global Positioning System Fix Data GPGSA: 0x0002, // GSA - GNSS DOP and active satellites GPGSV: 0x0004, // GSV - Satellites in view GPRMC: 0x0008, // RMC - Recommended minimum specific GNSS data GPVTG: 0x0010, // VTG - Track made good and ground speed 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, }; } start1pps(callback) { this.on1pps = callback; if (callback) { this.last1pps = 2; this.obniz.getAD(this.Opps).self = this; this.obniz.getAD(this.Opps).start(function(voltage) { let vol = Math.round(voltage); if (vol != this.self.last1pps) { this.self.last1pps = vol; if (vol == 0 && this.self.on1pps) { this.self.on1pps(); } } }); } else { this.obniz.getAD(this.Opps).end(); } } readSentence() { let results = []; if (this.uart.isDataExists()) { let pos = this.uart.received.indexOf(0x0a); if (pos >= 0) { results = this.uart.received.slice(0, pos - 1); this.uart.received.splice(0, pos + 1); return this.uart.tryConvertString(results); } } return ''; } getEditedData() { let n, utc, format; let sentence = this.readSentence(); this.editedData.enable = false; this.editedData.GPGSV = new Array(4); while (sentence.length > 0) { let part = sentence.split(','); if (sentence.slice(-4, -3) != ',') { let 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, 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], pack_index = gsv[2], 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], // SV PRN number elevation: gsv[isatn + 5], // Elevation in degrees, 90 maximum azimuth: gsv[isatn + 6], // Azimuth, degrees from true north, 000 to 359 snr: gsv[isatn + 7], // SNR, 00-99 dB (null when not tracking) 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; } //------------------- get latitude() { return this.nmea2dd(this._latitude); } get longitude() { return this.nmea2dd(this._longitude); } _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); let d = Math.floor(val / 100); let m = Math.floor((val / 100.0 - d) * 100.0); let 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); let d = Math.floor(val / 100.0); let 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); let d = Math.floor(val / 100.0); let m = Math.floor(((val / 100.0 - d) * 100.0) / 60); let 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); let d = Math.floor(val / 100.0); let m = Math.floor(((val / 100.0 - d) * 100.0) / 60); let s = (((val / 100.0 - d) * 100.0 - m) * 60) / (60 * 60); return (d + m + s) / (1.0 / 60.0 / 60.0); } } if (typeof module === 'object') { module.exports = GYSFDMAXB; }