parsePacket(buffer) {
    // Check for length
    // At minimum requires: prefix (4), sequence (4), command (4), length (4),
    // CRC (4), and suffix (4) for 24 total bytes
    // Messages from the device also include return code (4), for 28 total bytes
    if (buffer.length < 24) {
      throw new TypeError(`Packet too short. Length: ${buffer.length}.`);
    }

    // Check for prefix
    const prefix = buffer.readUInt32BE(0);

    // Only for 3.4 and 3.5 packets
    if (prefix !== 0x000055AA && prefix !== 0x00006699) {
      throw new TypeError(`Prefix does not match: ${buffer.toString('hex')}`);
    }

    // Check for extra data
    let leftover = false;

    let suffixLocation = buffer.indexOf('0000AA55', 0, 'hex');
    if (suffixLocation === -1) {// Couldn't find 0000AA55 during parse
      suffixLocation = buffer.indexOf('00009966', 0, 'hex');
    }

    if (suffixLocation !== buffer.length - 4) {
      leftover = buffer.slice(suffixLocation + 4);
      buffer = buffer.slice(0, suffixLocation + 4);
    }

    // Check for suffix
    const suffix = buffer.readUInt32BE(buffer.length - 4);

    if (suffix !== 0x0000AA55 && suffix !== 0x00009966) {
      throw new TypeError(`Suffix does not match: ${buffer.toString('hex')}`);
    }

    let sequenceN;
    let commandByte;
    let payloadSize;
    let overwriteVersion;

    if (suffix === 0x0000AA55) {
      // Get sequence number
      sequenceN = buffer.readUInt32BE(4);

      // Get command byte
      commandByte = buffer.readUInt32BE(8);

      // Get payload size
      payloadSize = buffer.readUInt32BE(12);

      // Check for payload
      if (buffer.length - 8 < payloadSize) {
        throw new TypeError(`Packet missing payload: payload has length ${payloadSize}.`);
      }
    } else if (suffix === 0x00009966) {
      // When this suffix comes in we should have 3.5 version
      overwriteVersion = '3.5';

      // Get sequence number
      sequenceN = buffer.readUInt32BE(6);

      // Get command byte
      commandByte = buffer.readUInt32BE(10);

      // Get payload size
      payloadSize = buffer.readUInt32BE(14) + 14; // Add additional bytes for extras

      // Check for payload
      if (buffer.length - 8 < payloadSize) {
        throw new TypeError(`Packet missing payload: payload has length ${payloadSize}.`);
      }
    } else {
      throw new TypeError(`Suffix does not match: ${buffer.toString('hex')}`); // Should never happen
    }

    const packageFromDiscovery = (
      commandByte === CommandType.UDP ||
      commandByte === CommandType.UDP_NEW ||
      commandByte === CommandType.BOARDCAST_LPV34
    );

    // Get the return code, 0 = success
    // This field is only present in messages from the devices
    // Absent in messages sent to device
    const returnCode = buffer.readUInt32BE(16);

    // Get the payload
    // Adjust for messages lacking a return code
    let payload;
    if (overwriteVersion === '3.5' || this.version === '3.5') {
      payload = buffer.slice(HEADER_SIZE_3_5, HEADER_SIZE_3_5 + payloadSize);
      sequenceN = buffer.slice(6, 10).readUInt32BE();
      commandByte = buffer.slice(10, 14).readUInt32BE();
    } else {
      if (returnCode & 0xFFFFFF00) {
        if (this.version === '3.4' && !packageFromDiscovery) {
          payload = buffer.slice(HEADER_SIZE, HEADER_SIZE + payloadSize - 0x24);
        } else if (this.version === '3.5' && !packageFromDiscovery) {
          payload = buffer.slice(HEADER_SIZE, HEADER_SIZE + payloadSize - 0x24);
        } else {
          payload = buffer.slice(HEADER_SIZE, HEADER_SIZE + payloadSize - 8);
        }
      } else if (this.version === '3.4' && !packageFromDiscovery) {
        payload = buffer.slice(HEADER_SIZE + 4, HEADER_SIZE + payloadSize - 0x24);
      } else if (this.version === '3.5' && !packageFromDiscovery) {
        payload = buffer.slice(HEADER_SIZE + 4, HEADER_SIZE + payloadSize - 0x24);
      } else {
        payload = buffer.slice(HEADER_SIZE + 4, HEADER_SIZE + payloadSize - 8);
      }

      // Check CRC
      if (this.version === '3.4' && !packageFromDiscovery) {
        const expectedCrc = buffer.slice(HEADER_SIZE + payloadSize - 0x24, buffer.length - 4).toString('hex');
        const computedCrc = this.cipher.hmac(buffer.slice(0, HEADER_SIZE + payloadSize - 0x24)).toString('hex');

        if (expectedCrc !== computedCrc) {
          throw new Error(`HMAC mismatch: expected ${expectedCrc}, was ${computedCrc}. ${buffer.toString('hex')}`);
        }
      } else if (this.version !== '3.5') {
        const expectedCrc = buffer.readInt32BE(HEADER_SIZE + payloadSize - 8);
        const computedCrc = crc(buffer.slice(0, payloadSize + 8));

        if (expectedCrc !== computedCrc) {
          throw new Error(`CRC mismatch: expected ${expectedCrc}, was ${computedCrc}. ${buffer.toString('hex')}`);
        }
      }
    }

    return {payload, leftover, commandByte, sequenceN, version: overwriteVersion || this.version};
  }
Parses a Buffer of data containing at least
one complete packet at the beginning of the buffer.
Will return multiple packets if necessary.
@param {Buffer} buffer of data to parse
@returns {Packet} packet of data