import { Transform , TransformCallback } from "stream" ; import type { SerialLogger } from "./Logger" ; import { MessageHeaders } from "./MessageHeaders" ; /**
 * Checks if there's enough data in the buffer to deserialize a complete message
 */ function containsCompleteMessage ( data ? ) { return ! ! data && data . length >= 5 && data . length >= getMessageLength ( data ) ; } /** Given a buffer that starts with SOF, this method returns the number of bytes the first message occupies in the buffer */ function getMessageLength ( data ) { const remainingLength = data [ 1 ] ; return remainingLength + 2 ; } export class SerialAPIParser extends Transform { constructor ( private logger ) { super ( { readableObjectMode : true } ) ; } private receiveBuffer = Buffer . allocUnsafe ( 0 ) ; _transform ( chunk , encoding , callback ) { this . receiveBuffer = Buffer . concat ( [ this . receiveBuffer , chunk ] ) ; while ( this . receiveBuffer . length > 0 ) { if ( this . receiveBuffer [ 0 ] !== MessageHeaders . SOF ) { switch ( this . receiveBuffer [ 0 ] ) { case MessageHeaders . ACK : { this . logger . ACK ( "inbound" ) ; this . push ( MessageHeaders . ACK ) ; break ; } case MessageHeaders . NAK : { this . logger . NAK ( "inbound" ) ; this . push ( MessageHeaders . NAK ) ; break ; } case MessageHeaders . CAN : { this . logger . CAN ( "inbound" ) ; this . push ( MessageHeaders . CAN ) ; break ; } default : { } } this . receiveBuffer = skipBytes ( this . receiveBuffer , 1 ) ; continue ; } if ( ! containsCompleteMessage ( this . receiveBuffer ) ) { break ; } else { const msgLength = getMessageLength ( this . receiveBuffer ) ; const msg = this . receiveBuffer . slice ( 0 , msgLength ) ; this . receiveBuffer = skipBytes ( this . receiveBuffer , msgLength ) ; this . logger . data ( "inbound" , msg ) ; this . push ( msg ) ; } } callback ( ) ; } } /** Skips the first n bytes of a buffer and returns the rest */ export function skipBytes ( buf , n ) { return Buffer . from ( buf . slice ( n ) ) ; }