src/icarus/data-handler/parser.js
import Parser from '../../parser'
import * as conv from './unit-conv'
import {messages, moduleNames} from './cansat-strings' // eslint-disable-line import/named
/**
* The parser for Team Icarus' CanSat.
*/
export default class IcarusParser extends Parser {
/**
* Implementation of {@link Parser#parse}.
* Automatically decodes the quasi-binary packet with {@link decode}.
* Supports telemetry, info and settings packets.
* Also converts sensor values to standard units and attaches text representations
* of module names and messages.
* @param {Buffer} rawPacket Packet to parse.
* @returns {Object} Parsed packet.
*/
parse(rawPacket) {
// Decode packet
this._raw = Buffer.from(rawPacket.toString(), 'base64')
// Parser needs to cleanup some things
super.parse(this._raw)
// Save raw packet (encoded version)
this.packet.raw = rawPacket.toJSON().data
// Save receival time
this.packet.receivedAt = Date.now()
try {
// Stop right now if there are no checksums
if (!this.packet.crc) {
throw new Error('Missing CRC checksums')
}
// Get packet type identifier
this.readChar('type')
// Only handle known packets
if (this.packet.type === 't' || this.packet.type === 'i' || this.packet.type === 's') {
// Now the packet counter, timestamps and alike
this.readUInt('counter', 4)
this.readUInt('sentAt.millis', 4)
this.readUInt('sentAt.unix', 4) // Not yet as of now
// Generate the packet ID
this.packet._id = String(this.packet.counter)
}
switch (this.packet.type) {
case 't':
// Temperature
this.readInt('temp.0', 2, conv.DS18B20)
this.readInt('temp.1', 2, conv.DS18B20)
// Pressure
this.readInt('press.0', 2, conv.MPX4115A)
this.readInt('press.1', 2, conv.MPX4115A)
// GPS data
this.readUInt('gps.flags', 1, conv.gpsFlags)
// GPS Latitude
this.readUInt('gps.lat.deg', 2)
this.readUInt('gps.lat.billionths', 4)
this.setValue('gps.lat', this.packet.gps.lat, conv.gpsCoordinate)
if (this.packet.gps.flags.latSign) {
// The sign bit is true = the value the negative
this.packet.gps.lat *= -1
}
// GPS Longitude
this.readUInt('gps.lng.deg', 2)
this.readUInt('gps.lng.billionths', 4)
this.setValue('gps.lng', this.packet.gps.lng, conv.gpsCoordinate)
if (this.packet.gps.flags.lngSign) {
// The sign bit is true = the value the negative
this.packet.gps.lng *= -1
}
this.readInt('gps.speed', 4, conv.gpsSpeed)
this.readInt('gps.course', 4, conv.gpsCourse)
this.readInt('gps.altitude', 4, conv.gpsAltitude)
// Acceleration
this.readInt('accel.0.x', 2, conv.LIS331HH_24G)
this.readInt('accel.0.y', 2, conv.LIS331HH_24G)
this.readInt('accel.0.z', 2, conv.LIS331HH_24G)
this.readInt('accel.1.x', 2, conv.MMA7361_6G)
this.readInt('accel.1.y', 2, conv.MMA7361_6G)
this.readInt('accel.1.z', 2, conv.MMA7361_6G)
break
case 'i':
// Message code and interpretation
this.readUInt('message.id')
this.setValue('message.text', messages[this.packet.message.id] || 'Unknown message')
break
case 's':
// Module information
this.readUInt('module.id')
this.readBoolean('module.enable')
this.readUInt('module.interval', 4)
this.readUInt('module.lastRun', 4)
// Get module name
this.setValue('module.name', moduleNames[this.packet.module.id] || 'Unknown module')
break
default:
this.packet.type = `?[0x${this.packet.type.charCodeAt(0).toString(16)}]`
break
}
} catch (err) {
// When we can't decode it, we can't continue
this.packet.error = err.message
this.packet.type = '?[error]'
}
return this.packet
}
}