node-mavlink 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.sendSigned=exports.send=exports.createMavLinkStream=exports.MavLinkPacketParser=exports.MavLinkPacketSplitter=exports.MavLinkPacket=exports.MavLinkPacketSignature=exports.MavLinkProtocolV2=exports.MavLinkProtocolV1=exports.MavLinkProtocol=exports.MavLinkPacketHeader=void 0;const stream_1=require("stream"),crypto_1=require("crypto"),mavlink_mappings_1=require("mavlink-mappings"),mavlink_mappings_2=require("mavlink-mappings"),utils_1=require("./utils"),logger_1=require("./logger"),serialization_1=require("./serialization");class MavLinkPacketHeader{constructor(){this.timestamp=null,this.magic=0,this.payloadLength=0,this.incompatibilityFlags=0,this.compatibilityFlags=0,this.seq=0,this.sysid=0,this.compid=0,this.msgid=0}}exports.MavLinkPacketHeader=MavLinkPacketHeader;class MavLinkProtocol{constructor(){this.log=logger_1.Logger.getLogger(this)}data(t,s){this.log.trace("Deserializing",s.MSG_NAME,"with payload of size",t.length);const n=new s;return s.FIELDS.forEach(e=>{const i=serialization_1.DESERIALIZERS[e.type];if(!i)throw new Error(`Unknown field type ${e.type}`);n[e.name]=i(t,e.offset,e.length)}),n}}exports.MavLinkProtocol=MavLinkProtocol,MavLinkProtocol.NAME="unknown",MavLinkProtocol.START_BYTE=0,MavLinkProtocol.PAYLOAD_OFFSET=0,MavLinkProtocol.CHECKSUM_LENGTH=2,MavLinkProtocol.SYS_ID=254,MavLinkProtocol.COMP_ID=1;class MavLinkProtocolV1 extends MavLinkProtocol{constructor(t=MavLinkProtocol.SYS_ID,s=MavLinkProtocol.COMP_ID){super(),this.sysid=t,this.compid=s}serialize(t,s){this.log.trace("Serializing message (seq:",s,")");const n=t.constructor,e=Buffer.from(new Uint8Array(MavLinkProtocolV1.PAYLOAD_OFFSET+n.PAYLOAD_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH));e.writeUInt8(MavLinkProtocolV1.START_BYTE,0),e.writeUInt8(n.PAYLOAD_LENGTH,1),e.writeUInt8(s,2),e.writeUInt8(this.sysid,3),e.writeUInt8(this.compid,4),e.writeUInt8(n.MSG_ID,5),n.FIELDS.forEach(r=>{const o=serialization_1.SERIALIZERS[r.type];if(!o)throw new Error(`Unknown field type ${r.type}: serializer not found`);o(t[r.name],e,r.offset+MavLinkProtocolV1.PAYLOAD_OFFSET,r.length)});const i=(0,mavlink_mappings_1.x25crc)(e,1,2,n.MAGIC_NUMBER);return e.writeUInt16LE(i,e.length-2),e}header(t,s=null){this.log.trace("Reading header from buffer (len:",t.length,")");const n=t.readUInt8(0);if(n!==MavLinkProtocolV1.START_BYTE)throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV1.START_BYTE}, got ${n})`);const e=new MavLinkPacketHeader;return e.timestamp=s,e.magic=n,e.payloadLength=t.readUInt8(1),e.seq=t.readUInt8(2),e.sysid=t.readUInt8(3),e.compid=t.readUInt8(4),e.msgid=t.readUInt8(5),e}crc(t){this.log.trace("Reading crc from buffer (len:",t.length,")");const s=t.readUInt8(1);return t.readUInt16LE(MavLinkProtocolV1.PAYLOAD_OFFSET+s)}payload(t){this.log.trace("Reading payload from buffer (len:",t.length,")");const s=t.readUInt8(1),n=t.slice(MavLinkProtocolV1.PAYLOAD_OFFSET,MavLinkProtocolV1.PAYLOAD_OFFSET+s),e=Buffer.from(new Uint8Array(255-n.length));return Buffer.concat([n,e])}}exports.MavLinkProtocolV1=MavLinkProtocolV1,MavLinkProtocolV1.NAME="MAV_V1",MavLinkProtocolV1.START_BYTE=254,MavLinkProtocolV1.PAYLOAD_OFFSET=6;class MavLinkProtocolV2 extends MavLinkProtocol{constructor(t=MavLinkProtocol.SYS_ID,s=MavLinkProtocol.COMP_ID,n=MavLinkProtocolV2.INCOMPATIBILITY_FLAGS,e=MavLinkProtocolV2.COMPATIBILITY_FLAGS){super(),this.sysid=t,this.compid=s,this.incompatibilityFlags=n,this.compatibilityFlags=e}serialize(t,s){this.log.trace("Serializing message (seq:",s,")");const n=t.constructor,e=Buffer.from(new Uint8Array(MavLinkProtocolV2.PAYLOAD_OFFSET+n.PAYLOAD_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH));e.writeUInt8(MavLinkProtocolV2.START_BYTE,0),e.writeUInt8(this.incompatibilityFlags,2),e.writeUInt8(this.compatibilityFlags,3),e.writeUInt8(s,4),e.writeUInt8(this.sysid,5),e.writeUInt8(this.compid,6),e.writeUIntLE(n.MSG_ID,7,3),n.FIELDS.forEach(c=>{const h=serialization_1.SERIALIZERS[c.type];if(!h)throw new Error(`Unknown field type ${c.type}: serializer not found`);h(t[c.name],e,c.offset+MavLinkProtocolV2.PAYLOAD_OFFSET,c.length)});const i=this.calculateTruncatedPayloadLength(e);e.writeUInt8(i,1);const r=e.slice(0,MavLinkProtocolV2.PAYLOAD_OFFSET+i+MavLinkProtocol.CHECKSUM_LENGTH),o=(0,mavlink_mappings_1.x25crc)(r,1,2,n.MAGIC_NUMBER);return r.writeUInt16LE(o,r.length-MavLinkProtocol.CHECKSUM_LENGTH),r}sign(t,s,n,e=Date.now()){this.log.trace("Signing message");const i=Buffer.concat([t,Buffer.from(new Uint8Array(MavLinkPacketSignature.SIGNATURE_LENGTH))]),r=new MavLinkPacketSignature(i);return r.linkId=s,r.timestamp=e,r.signature=r.calculate(n),i}calculateTruncatedPayloadLength(t){let s=t.length;for(let n=t.length-MavLinkProtocol.CHECKSUM_LENGTH-1;n>=MavLinkProtocolV2.PAYLOAD_OFFSET;n--)if(s=n,t[n]!==0){s++;break}return s-MavLinkProtocolV2.PAYLOAD_OFFSET}header(t,s=null){this.log.trace("Reading header from buffer (len:",t.length,")");const n=t.readUInt8(0);if(n!==MavLinkProtocolV2.START_BYTE)throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV2.START_BYTE}, got ${n})`);const e=new MavLinkPacketHeader;return e.timestamp=s,e.magic=n,e.payloadLength=t.readUInt8(1),e.incompatibilityFlags=t.readUInt8(2),e.compatibilityFlags=t.readUInt8(3),e.seq=t.readUInt8(4),e.sysid=t.readUInt8(5),e.compid=t.readUInt8(6),e.msgid=t.readUIntLE(7,3),e}crc(t){this.log.trace("Reading crc from buffer (len:",t.length,")");const s=t.readUInt8(1);return t.readUInt16LE(MavLinkProtocolV2.PAYLOAD_OFFSET+s)}payload(t){this.log.trace("Reading payload from buffer (len:",t.length,")");const s=t.readUInt8(1),n=t.slice(MavLinkProtocolV2.PAYLOAD_OFFSET,MavLinkProtocolV2.PAYLOAD_OFFSET+s),e=Buffer.from(new Uint8Array(255-n.length));return Buffer.concat([n,e])}signature(t,s){return this.log.trace("Reading signature from buffer (len:",t.length,")"),s.incompatibilityFlags&MavLinkProtocolV2.IFLAG_SIGNED?new MavLinkPacketSignature(t):null}}exports.MavLinkProtocolV2=MavLinkProtocolV2,MavLinkProtocolV2.NAME="MAV_V2",MavLinkProtocolV2.START_BYTE=253,MavLinkProtocolV2.PAYLOAD_OFFSET=10,MavLinkProtocolV2.INCOMPATIBILITY_FLAGS=0,MavLinkProtocolV2.COMPATIBILITY_FLAGS=0,MavLinkProtocolV2.IFLAG_SIGNED=1;const KNOWN_PROTOCOLS_BY_STX={[MavLinkProtocolV1.START_BYTE]:MavLinkProtocolV1,[MavLinkProtocolV2.START_BYTE]:MavLinkProtocolV2};class MavLinkPacketSignature{constructor(t){this.buffer=t}static key(t){return(0,crypto_1.createHash)("sha256").update(t).digest()}get offset(){return this.buffer.length-MavLinkPacketSignature.SIGNATURE_LENGTH}get linkId(){return this.buffer.readUInt8(this.offset)}set linkId(t){this.buffer.writeUInt8(this.offset)}get timestamp(){return this.buffer.readUIntLE(this.offset+1,6)}set timestamp(t){this.buffer.writeUIntLE(t,this.offset+1,6)}get signature(){return this.buffer.slice(this.offset+7,this.offset+7+6).toString("hex")}set signature(t){this.buffer.write(t,this.offset+7,"hex")}calculate(t){return(0,crypto_1.createHash)("sha256").update(t).update(this.buffer.slice(0,this.buffer.length-6)).digest("hex").substr(0,12)}matches(t){return this.calculate(t)===this.signature}toString(){return`linkid: ${this.linkId}, timestamp ${this.timestamp}, signature ${this.signature}`}}exports.MavLinkPacketSignature=MavLinkPacketSignature,MavLinkPacketSignature.SIGNATURE_LENGTH=13;class MavLinkPacket{constructor(t,s=new MavLinkPacketHeader,n=Buffer.from(new Uint8Array(255)),e=0,i=new MavLinkProtocolV1,r=null){this.buffer=t,this.header=s,this.payload=n,this.crc=e,this.protocol=i,this.signature=r}debug(){return`Packet (proto: ${this.protocol.constructor.NAME}, sysid: ${this.header.sysid}, compid: ${this.header.compid}, msgid: ${this.header.msgid}, seq: ${this.header.seq}, plen: ${this.header.payloadLength}, magic: ${mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[this.header.msgid]} (${(0,utils_1.hex)(mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[this.header.msgid])}), crc: ${(0,utils_1.hex)(this.crc,4)}`+this.signatureToString(this.signature)+")"}signatureToString(t){return t?`, ${t.toString()}`:""}}exports.MavLinkPacket=MavLinkPacket;var PacketValidationResult;(function(a){a[a.VALID=0]="VALID",a[a.INVALID=1]="INVALID",a[a.UNKNOWN=2]="UNKNOWN"})(PacketValidationResult||(PacketValidationResult={}));class MavLinkPacketSplitter extends stream_1.Transform{constructor(t={},s=()=>{}){super({...t,objectMode:!0}),this.log=logger_1.Logger.getLogger(this),this.buffer=Buffer.from([]),this.onCrcError=null,this.timestamp=null,this._validPackagesCount=0,this._unknownPackagesCount=0,this._invalidPackagesCount=0,this.onCrcError=s}_transform(t,s,n){for(this.buffer=Buffer.concat([this.buffer,t]);this.buffer.byteLength>0;){const e=this.findStartOfPacket(this.buffer);if(e===null)break;e===8?this.timestamp=Buffer.from(this.buffer,0,8).readBigUInt64BE()/1000n:this.timestamp=null,e>0&&(this.buffer=this.buffer.slice(e)),this.log.debug("Found potential packet start at",e);const i=this.getPacketProtocol(this.buffer);if(this.log.debug("Packet protocol is",i.NAME),this.buffer.length<i.PAYLOAD_OFFSET+MavLinkProtocol.CHECKSUM_LENGTH){this.log.debug("Current buffer shorter than the shortest message - skipping");break}const r=this.readPacketLength(this.buffer,i);if(this.log.debug("Expected buffer length:",r,`(${(0,utils_1.hex)(r)})`),this.buffer.length<r){this.log.debug("Current buffer is not fully retrieved yet - skipping");break}else this.log.debug("Current buffer length:",this.buffer.length,`(${(0,utils_1.hex)(this.buffer.length,4)})`);const o=this.buffer.slice(0,r);switch(this.log.debug("Recognized buffer length:",o.length,`(${(0,utils_1.hex)(o.length,2)})`),this.validatePacket(o,i)){case PacketValidationResult.VALID:this.log.debug("Found a valid packet"),this._validPackagesCount++,this.push({buffer:o,timestamp:this.timestamp}),this.buffer=this.buffer.slice(r);break;case PacketValidationResult.INVALID:this.log.debug("Found an invalid packet - skipping"),this._invalidPackagesCount++,this.buffer=this.buffer.slice(1);break;case PacketValidationResult.UNKNOWN:this.log.debug("Found an unknown packet - skipping"),this._unknownPackagesCount++,this.buffer=this.buffer.slice(r);break}}n(null)}findStartOfPacket(t){const s=t.indexOf(MavLinkProtocolV1.START_BYTE),n=t.indexOf(MavLinkProtocolV2.START_BYTE);return s>=0&&n>=0?s<n?s:n:s>=0?s:n>=0?n:null}getPacketProtocol(t){return KNOWN_PROTOCOLS_BY_STX[t.readUInt8(0)]||null}readPacketLength(t,s){const n=t.readUInt8(1);return s.PAYLOAD_OFFSET+n+MavLinkProtocol.CHECKSUM_LENGTH+(this.isV2Signed(t)?MavLinkPacketSignature.SIGNATURE_LENGTH:0)}validatePacket(t,s){const n=new s,e=n.header(t),i=mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[e.msgid];if(i){const r=n.crc(t),o=this.isV2Signed(t)?MavLinkPacketSignature.SIGNATURE_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH:MavLinkProtocol.CHECKSUM_LENGTH,c=(0,mavlink_mappings_1.x25crc)(t,1,o,i);if(r===c)return PacketValidationResult.VALID;{const h=[`CRC error; expected: ${c} (${(0,utils_1.hex)(c,4)}), got ${r} (${(0,utils_1.hex)(r,4)});`,`msgid: ${e.msgid} (${(0,utils_1.hex)(e.msgid)}),`,`seq: ${e.seq} (${(0,utils_1.hex)(e.seq)}),`,`plen: ${e.payloadLength} (${(0,utils_1.hex)(e.payloadLength)}),`,`magic: ${i} (${(0,utils_1.hex)(i)})`];return this.log.warn(h.join(" ")),this.onCrcError(t),PacketValidationResult.INVALID}}else return this.log.debug(`Unknown message with id ${e.msgid} (magic number not found) - skipping`),PacketValidationResult.UNKNOWN}isV2Signed(t){if(t.readUInt8(0)===MavLinkProtocolV2.START_BYTE)return!!(t.readUInt8(2)&MavLinkProtocolV2.IFLAG_SIGNED)}get validPackages(){return this._validPackagesCount}resetValidPackagesCount(){this._validPackagesCount=0}get invalidPackages(){return this._invalidPackagesCount}resetInvalidPackagesCount(){this._invalidPackagesCount=0}get unknownPackagesCount(){return this._unknownPackagesCount}resetUnknownPackagesCount(){this._unknownPackagesCount=0}}exports.MavLinkPacketSplitter=MavLinkPacketSplitter;class MavLinkPacketParser extends stream_1.Transform{constructor(t={}){super({...t,objectMode:!0}),this.log=logger_1.Logger.getLogger(this)}getProtocol(t){const s=t.readUInt8(0);switch(s){case MavLinkProtocolV1.START_BYTE:return new MavLinkProtocolV1;case MavLinkProtocolV2.START_BYTE:return new MavLinkProtocolV2;default:throw new Error(`Unknown protocol '${(0,utils_1.hex)(s)}'`)}}_transform({buffer:t=Buffer.from([]),timestamp:s=null,...n}={},e,i){const r=this.getProtocol(t),o=r.header(t,s),c=r.payload(t),h=r.crc(t),l=r instanceof MavLinkProtocolV2?r.signature(t,o):null,g=new MavLinkPacket(t,o,c,h,r,l);i(null,g)}}exports.MavLinkPacketParser=MavLinkPacketParser;function createMavLinkStream(a,t){return a.pipe(new MavLinkPacketSplitter({},t)).pipe(new MavLinkPacketParser)}exports.createMavLinkStream=createMavLinkStream;let seq=0;async function send(a,t,s=new MavLinkProtocolV1){return new Promise((n,e)=>{const i=s.serialize(t,seq++);seq&=255,a.write(i,r=>{r?e(r):n(i.length)})})}exports.send=send;async function sendSigned(a,t,s,n=1,e=MavLinkProtocol.SYS_ID,i=MavLinkProtocol.COMP_ID,r=Date.now()){return new Promise((o,c)=>{const h=new MavLinkProtocolV2(e,i,MavLinkProtocolV2.IFLAG_SIGNED),l=h.serialize(t,seq++);seq&=255;const g=h.sign(l,n,s,r);a.write(g,u=>{u?c(u):o(g.length)})})}exports.sendSigned=sendSigned;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.sendSigned=exports.send=exports.createMavLinkStream=exports.MavLinkPacketParser=exports.MavLinkPacketSplitter=exports.MavLinkPacket=exports.MavLinkPacketSignature=exports.MavLinkProtocolV2=exports.MavLinkProtocolV1=exports.MavLinkProtocol=exports.MavLinkPacketHeader=void 0;const stream_1=require("stream"),crypto_1=require("crypto"),mavlink_mappings_1=require("mavlink-mappings"),mavlink_mappings_2=require("mavlink-mappings"),utils_1=require("./utils"),logger_1=require("./logger"),serialization_1=require("./serialization");class MavLinkPacketHeader{constructor(){this.timestamp=null,this.magic=0,this.payloadLength=0,this.incompatibilityFlags=0,this.compatibilityFlags=0,this.seq=0,this.sysid=0,this.compid=0,this.msgid=0}}exports.MavLinkPacketHeader=MavLinkPacketHeader;class MavLinkProtocol{constructor(){this.log=logger_1.Logger.getLogger(this)}data(t,s){this.log.trace("Deserializing",s.MSG_NAME,"with payload of size",t.length);const n=new s;return s.FIELDS.forEach(e=>{const i=serialization_1.DESERIALIZERS[e.type];if(!i)throw new Error(`Unknown field type ${e.type}`);n[e.name]=i(t,e.offset,e.length)}),n}}exports.MavLinkProtocol=MavLinkProtocol,MavLinkProtocol.NAME="unknown",MavLinkProtocol.START_BYTE=0,MavLinkProtocol.PAYLOAD_OFFSET=0,MavLinkProtocol.CHECKSUM_LENGTH=2,MavLinkProtocol.SYS_ID=254,MavLinkProtocol.COMP_ID=1;class MavLinkProtocolV1 extends MavLinkProtocol{constructor(t=MavLinkProtocol.SYS_ID,s=MavLinkProtocol.COMP_ID){super(),this.sysid=t,this.compid=s}serialize(t,s){this.log.trace("Serializing message (seq:",s,")");const n=t.constructor,e=Buffer.from(new Uint8Array(MavLinkProtocolV1.PAYLOAD_OFFSET+n.PAYLOAD_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH));e.writeUInt8(MavLinkProtocolV1.START_BYTE,0),e.writeUInt8(n.PAYLOAD_LENGTH,1),e.writeUInt8(s,2),e.writeUInt8(this.sysid,3),e.writeUInt8(this.compid,4),e.writeUInt8(n.MSG_ID,5),n.FIELDS.forEach(r=>{const o=serialization_1.SERIALIZERS[r.type];if(!o)throw new Error(`Unknown field type ${r.type}: serializer not found`);o(t[r.name],e,r.offset+MavLinkProtocolV1.PAYLOAD_OFFSET,r.length)});const i=(0,mavlink_mappings_1.x25crc)(e,1,2,n.MAGIC_NUMBER);return e.writeUInt16LE(i,e.length-2),e}header(t,s=null){this.log.trace("Reading header from buffer (len:",t.length,")");const n=t.readUInt8(0);if(n!==MavLinkProtocolV1.START_BYTE)throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV1.START_BYTE}, got ${n})`);const e=new MavLinkPacketHeader;return e.timestamp=s,e.magic=n,e.payloadLength=t.readUInt8(1),e.seq=t.readUInt8(2),e.sysid=t.readUInt8(3),e.compid=t.readUInt8(4),e.msgid=t.readUInt8(5),e}crc(t){this.log.trace("Reading crc from buffer (len:",t.length,")");const s=t.readUInt8(1);return t.readUInt16LE(MavLinkProtocolV1.PAYLOAD_OFFSET+s)}payload(t){this.log.trace("Reading payload from buffer (len:",t.length,")");const s=t.readUInt8(1),n=t.slice(MavLinkProtocolV1.PAYLOAD_OFFSET,MavLinkProtocolV1.PAYLOAD_OFFSET+s),e=Buffer.from(new Uint8Array(255-n.length));return Buffer.concat([n,e])}}exports.MavLinkProtocolV1=MavLinkProtocolV1,MavLinkProtocolV1.NAME="MAV_V1",MavLinkProtocolV1.START_BYTE=254,MavLinkProtocolV1.PAYLOAD_OFFSET=6;class MavLinkProtocolV2 extends MavLinkProtocol{constructor(t=MavLinkProtocol.SYS_ID,s=MavLinkProtocol.COMP_ID,n=MavLinkProtocolV2.INCOMPATIBILITY_FLAGS,e=MavLinkProtocolV2.COMPATIBILITY_FLAGS){super(),this.sysid=t,this.compid=s,this.incompatibilityFlags=n,this.compatibilityFlags=e}serialize(t,s){this.log.trace("Serializing message (seq:",s,")");const n=t.constructor,e=Buffer.from(new Uint8Array(MavLinkProtocolV2.PAYLOAD_OFFSET+n.PAYLOAD_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH));e.writeUInt8(MavLinkProtocolV2.START_BYTE,0),e.writeUInt8(this.incompatibilityFlags,2),e.writeUInt8(this.compatibilityFlags,3),e.writeUInt8(s,4),e.writeUInt8(this.sysid,5),e.writeUInt8(this.compid,6),e.writeUIntLE(n.MSG_ID,7,3),n.FIELDS.forEach(c=>{const h=serialization_1.SERIALIZERS[c.type];if(!h)throw new Error(`Unknown field type ${c.type}: serializer not found`);h(t[c.name],e,c.offset+MavLinkProtocolV2.PAYLOAD_OFFSET,c.length)});const i=this.calculateTruncatedPayloadLength(e);e.writeUInt8(i,1);const r=e.slice(0,MavLinkProtocolV2.PAYLOAD_OFFSET+i+MavLinkProtocol.CHECKSUM_LENGTH),o=(0,mavlink_mappings_1.x25crc)(r,1,2,n.MAGIC_NUMBER);return r.writeUInt16LE(o,r.length-MavLinkProtocol.CHECKSUM_LENGTH),r}sign(t,s,n,e=Date.now()){this.log.trace("Signing message");const i=Buffer.concat([t,Buffer.from(new Uint8Array(MavLinkPacketSignature.SIGNATURE_LENGTH))]),r=new MavLinkPacketSignature(i);return r.linkId=s,r.timestamp=e,r.signature=r.calculate(n),i}calculateTruncatedPayloadLength(t){let s=t.length;for(let n=t.length-MavLinkProtocol.CHECKSUM_LENGTH-1;n>=MavLinkProtocolV2.PAYLOAD_OFFSET;n--)if(s=n,t[n]!==0){s++;break}return s-MavLinkProtocolV2.PAYLOAD_OFFSET}header(t,s=null){this.log.trace("Reading header from buffer (len:",t.length,")");const n=t.readUInt8(0);if(n!==MavLinkProtocolV2.START_BYTE)throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV2.START_BYTE}, got ${n})`);const e=new MavLinkPacketHeader;return e.timestamp=s,e.magic=n,e.payloadLength=t.readUInt8(1),e.incompatibilityFlags=t.readUInt8(2),e.compatibilityFlags=t.readUInt8(3),e.seq=t.readUInt8(4),e.sysid=t.readUInt8(5),e.compid=t.readUInt8(6),e.msgid=t.readUIntLE(7,3),e}crc(t){this.log.trace("Reading crc from buffer (len:",t.length,")");const s=t.readUInt8(1);return t.readUInt16LE(MavLinkProtocolV2.PAYLOAD_OFFSET+s)}payload(t){this.log.trace("Reading payload from buffer (len:",t.length,")");const s=t.readUInt8(1),n=t.slice(MavLinkProtocolV2.PAYLOAD_OFFSET,MavLinkProtocolV2.PAYLOAD_OFFSET+s),e=Buffer.from(new Uint8Array(255-n.length));return Buffer.concat([n,e])}signature(t,s){return this.log.trace("Reading signature from buffer (len:",t.length,")"),s.incompatibilityFlags&MavLinkProtocolV2.IFLAG_SIGNED?new MavLinkPacketSignature(t):null}}exports.MavLinkProtocolV2=MavLinkProtocolV2,MavLinkProtocolV2.NAME="MAV_V2",MavLinkProtocolV2.START_BYTE=253,MavLinkProtocolV2.PAYLOAD_OFFSET=10,MavLinkProtocolV2.INCOMPATIBILITY_FLAGS=0,MavLinkProtocolV2.COMPATIBILITY_FLAGS=0,MavLinkProtocolV2.IFLAG_SIGNED=1;const KNOWN_PROTOCOLS_BY_STX={[MavLinkProtocolV1.START_BYTE]:MavLinkProtocolV1,[MavLinkProtocolV2.START_BYTE]:MavLinkProtocolV2};class MavLinkPacketSignature{constructor(t){this.buffer=t}static key(t){return(0,crypto_1.createHash)("sha256").update(t).digest()}get offset(){return this.buffer.length-MavLinkPacketSignature.SIGNATURE_LENGTH}get linkId(){return this.buffer.readUInt8(this.offset)}set linkId(t){this.buffer.writeUInt8(this.offset)}get timestamp(){return this.buffer.readUIntLE(this.offset+1,6)}set timestamp(t){this.buffer.writeUIntLE(t,this.offset+1,6)}get signature(){return this.buffer.slice(this.offset+7,this.offset+7+6).toString("hex")}set signature(t){this.buffer.write(t,this.offset+7,"hex")}calculate(t){return(0,crypto_1.createHash)("sha256").update(t).update(this.buffer.slice(0,this.buffer.length-6)).digest("hex").substr(0,12)}matches(t){return this.calculate(t)===this.signature}toString(){return`linkid: ${this.linkId}, timestamp ${this.timestamp}, signature ${this.signature}`}}exports.MavLinkPacketSignature=MavLinkPacketSignature,MavLinkPacketSignature.SIGNATURE_LENGTH=13;class MavLinkPacket{constructor(t,s=new MavLinkPacketHeader,n=Buffer.from(new Uint8Array(255)),e=0,i=new MavLinkProtocolV1,r=null){this.buffer=t,this.header=s,this.payload=n,this.crc=e,this.protocol=i,this.signature=r}debug(){return`Packet (proto: ${this.protocol.constructor.NAME}, sysid: ${this.header.sysid}, compid: ${this.header.compid}, msgid: ${this.header.msgid}, seq: ${this.header.seq}, plen: ${this.header.payloadLength}, magic: ${mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[this.header.msgid]} (${(0,utils_1.hex)(mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[this.header.msgid])}), crc: ${(0,utils_1.hex)(this.crc,4)}`+this.signatureToString(this.signature)+")"}signatureToString(t){return t?`, ${t.toString()}`:""}}exports.MavLinkPacket=MavLinkPacket;var PacketValidationResult;(function(a){a[a.VALID=0]="VALID",a[a.INVALID=1]="INVALID",a[a.UNKNOWN=2]="UNKNOWN"})(PacketValidationResult||(PacketValidationResult={}));class MavLinkPacketSplitter extends stream_1.Transform{constructor(t={},s=()=>{}){super({...t,objectMode:!0}),this.log=logger_1.Logger.getLogger(this),this.buffer=Buffer.from([]),this.onCrcError=null,this.timestamp=null,this._validPackagesCount=0,this._unknownPackagesCount=0,this._invalidPackagesCount=0,this.onCrcError=s}_transform(t,s,n){for(this.buffer=Buffer.concat([this.buffer,t]);this.buffer.byteLength>0;){const e=this.findStartOfPacket(this.buffer);if(e===null)break;e>=8?this.timestamp=this.buffer.readBigUInt64BE(e-8)/1000n:this.timestamp=null,e>0&&(this.buffer=this.buffer.slice(e)),this.log.debug("Found potential packet start at",e);const i=this.getPacketProtocol(this.buffer);if(this.log.debug("Packet protocol is",i.NAME),this.buffer.length<i.PAYLOAD_OFFSET+MavLinkProtocol.CHECKSUM_LENGTH){this.log.debug("Current buffer shorter than the shortest message - skipping");break}const r=this.readPacketLength(this.buffer,i);if(this.log.debug("Expected buffer length:",r,`(${(0,utils_1.hex)(r)})`),this.buffer.length<r){this.log.debug("Current buffer is not fully retrieved yet - skipping");break}else this.log.debug("Current buffer length:",this.buffer.length,`(${(0,utils_1.hex)(this.buffer.length,4)})`);const o=this.buffer.slice(0,r);switch(this.log.debug("Recognized buffer length:",o.length,`(${(0,utils_1.hex)(o.length,2)})`),this.validatePacket(o,i)){case PacketValidationResult.VALID:this.log.debug("Found a valid packet"),this._validPackagesCount++,this.push({buffer:o,timestamp:this.timestamp}),this.buffer=this.buffer.slice(r);break;case PacketValidationResult.INVALID:this.log.debug("Found an invalid packet - skipping"),this._invalidPackagesCount++,this.buffer=this.buffer.slice(1);break;case PacketValidationResult.UNKNOWN:this.log.debug("Found an unknown packet - skipping"),this._unknownPackagesCount++,this.buffer=this.buffer.slice(r);break}}n(null)}findStartOfPacket(t){const s=t.indexOf(MavLinkProtocolV1.START_BYTE),n=t.indexOf(MavLinkProtocolV2.START_BYTE);return s>=0&&n>=0?s<n?s:n:s>=0?s:n>=0?n:null}getPacketProtocol(t){return KNOWN_PROTOCOLS_BY_STX[t.readUInt8(0)]||null}readPacketLength(t,s){const n=t.readUInt8(1);return s.PAYLOAD_OFFSET+n+MavLinkProtocol.CHECKSUM_LENGTH+(this.isV2Signed(t)?MavLinkPacketSignature.SIGNATURE_LENGTH:0)}validatePacket(t,s){const n=new s,e=n.header(t),i=mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[e.msgid];if(i){const r=n.crc(t),o=this.isV2Signed(t)?MavLinkPacketSignature.SIGNATURE_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH:MavLinkProtocol.CHECKSUM_LENGTH,c=(0,mavlink_mappings_1.x25crc)(t,1,o,i);if(r===c)return PacketValidationResult.VALID;{const h=[`CRC error; expected: ${c} (${(0,utils_1.hex)(c,4)}), got ${r} (${(0,utils_1.hex)(r,4)});`,`msgid: ${e.msgid} (${(0,utils_1.hex)(e.msgid)}),`,`seq: ${e.seq} (${(0,utils_1.hex)(e.seq)}),`,`plen: ${e.payloadLength} (${(0,utils_1.hex)(e.payloadLength)}),`,`magic: ${i} (${(0,utils_1.hex)(i)})`];return this.log.warn(h.join(" ")),this.onCrcError(t),PacketValidationResult.INVALID}}else return this.log.debug(`Unknown message with id ${e.msgid} (magic number not found) - skipping`),PacketValidationResult.UNKNOWN}isV2Signed(t){if(t.readUInt8(0)===MavLinkProtocolV2.START_BYTE)return!!(t.readUInt8(2)&MavLinkProtocolV2.IFLAG_SIGNED)}get validPackages(){return this._validPackagesCount}resetValidPackagesCount(){this._validPackagesCount=0}get invalidPackages(){return this._invalidPackagesCount}resetInvalidPackagesCount(){this._invalidPackagesCount=0}get unknownPackagesCount(){return this._unknownPackagesCount}resetUnknownPackagesCount(){this._unknownPackagesCount=0}}exports.MavLinkPacketSplitter=MavLinkPacketSplitter;class MavLinkPacketParser extends stream_1.Transform{constructor(t={}){super({...t,objectMode:!0}),this.log=logger_1.Logger.getLogger(this)}getProtocol(t){const s=t.readUInt8(0);switch(s){case MavLinkProtocolV1.START_BYTE:return new MavLinkProtocolV1;case MavLinkProtocolV2.START_BYTE:return new MavLinkProtocolV2;default:throw new Error(`Unknown protocol '${(0,utils_1.hex)(s)}'`)}}_transform({buffer:t=Buffer.from([]),timestamp:s=null,...n}={},e,i){const r=this.getProtocol(t),o=r.header(t,s),c=r.payload(t),h=r.crc(t),l=r instanceof MavLinkProtocolV2?r.signature(t,o):null,g=new MavLinkPacket(t,o,c,h,r,l);i(null,g)}}exports.MavLinkPacketParser=MavLinkPacketParser;function createMavLinkStream(a,t){return a.pipe(new MavLinkPacketSplitter({},t)).pipe(new MavLinkPacketParser)}exports.createMavLinkStream=createMavLinkStream;let seq=0;async function send(a,t,s=new MavLinkProtocolV1){return new Promise((n,e)=>{const i=s.serialize(t,seq++);seq&=255,a.write(i,r=>{r?e(r):n(i.length)})})}exports.send=send;async function sendSigned(a,t,s,n=1,e=MavLinkProtocol.SYS_ID,i=MavLinkProtocol.COMP_ID,r=Date.now()){return new Promise((o,c)=>{const h=new MavLinkProtocolV2(e,i,MavLinkProtocolV2.IFLAG_SIGNED),l=h.serialize(t,seq++);seq&=255;const g=h.sign(l,n,s,r);a.write(g,u=>{u?c(u):o(g.length)})})}exports.sendSigned=sendSigned;
@@ -9,7 +9,7 @@ import {
9
9
 
10
10
  const splitter = new MavLinkPacketSplitter()
11
11
  const parser = new MavLinkPacketParser()
12
- const file = createReadStream('./GH-5.bin')
12
+ const file = createReadStream(__dirname + '/GH-5.bin')
13
13
  const reader = file.pipe(splitter).pipe(parser)
14
14
 
15
15
  // create a registry of mappings between a message id and a data class
@@ -28,7 +28,11 @@ reader.on('data', packet => {
28
28
  const clazz = REGISTRY[packet.header.msgid]
29
29
  if (clazz) {
30
30
  const data = packet.protocol.data(packet.payload, clazz)
31
- console.log(data)
31
+ if (packet.header.timestamp) {
32
+ console.log(new Date(Number(packet.header.timestamp)).toISOString(), data)
33
+ } else {
34
+ console.log(data)
35
+ }
32
36
  }
33
37
  })
34
38
 
package/lib/mavlink.ts CHANGED
@@ -513,8 +513,8 @@ export class MavLinkPacketSplitter extends Transform {
513
513
  }
514
514
 
515
515
  // if the current offset is exactly the size of the timestamp field from tlog then read it.
516
- if (offset === 8) {
517
- this.timestamp = Buffer.from(this.buffer, 0, 8).readBigUInt64BE() / 1000n
516
+ if (offset >= 8) {
517
+ this.timestamp = this.buffer.readBigUInt64BE(offset - 8) / 1000n
518
518
  } else {
519
519
  this.timestamp = null
520
520
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mavlink",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "author": "Matthias Hryniszak <padcom@gmail.com>",
5
5
  "license": "LGPL",
6
6
  "description": "MavLink definitions and parsing library",