public int TryParseNextIncomingPacket(byte[] outBuffer, out byte channelId) { ushort dataLength; byte crc, headerLength, headerCrc; if (_bufferLength == 0) { channelId = 0; return(0); } if (!ParseHeader(_buffer, 0, out crc, out headerCrc, out channelId, out dataLength, out headerLength)) { Debug.LogError("invalid message header!!!"); AdvanceToNextViablePacket(); return(0); } var dataLengthBytes = BitConverter.GetBytes(dataLength); var actualHeaderCrc = CrcUtils.Checksum(new byte[] { channelId, dataLengthBytes[0], dataLengthBytes[1] }, 0, 3, HEADER_CRC_SIZE); if (actualHeaderCrc != headerCrc) { Debug.LogError("header crc check failed"); AdvanceToNextViablePacket(); return(0); } if (_bufferLength == 0) { return(0); } if (_bufferLength < (headerLength + dataLength)) { return(0); //not enough data } // copy the data to outBuffer Array.Copy(_buffer, headerLength, outBuffer, 0, dataLength); // Trim the packet from the buffer _bufferLength -= (dataLength + headerLength); Array.Copy(_buffer, headerLength + dataLength, _buffer, 0, _bufferLength); if (!ValidateCrc(crc, outBuffer, 0, dataLength)) { Debug.LogError("data crc check failed"); AdvanceToNextViablePacket(); return(0); } return(dataLength); }
/// <summary> /// Header structure: /// ======================================== /// 1. Fixed packet prefix (2 bits) /// 2. Channel Id (2 bits) /// 3. Data CRC (4 bits) /// 4. Header CRC (4 bits) /// 5. Data Length (12 bits, trimmed ushort, max=4096) /// /// Illustrated header structure /// ======================================== /// BYTE 1 +-+[] FIXED PACKET PREFIX (2 bits) /// | [] /// | /// | [] CHANNEL ID (2 bits) /// | [] /// | /// | [] DATA CRC (4 bits) /// | [] /// | [] /// +-+[] /// /// BYTE 2 +-+[] HEADER CRC (4 bits) /// | [] /// | [] /// | [] /// | /// | [] DATA LENGTH (12 bits) /// | [] /// | [] /// +-+[] /// BYTE 3 +-+[] /// | [] /// | [] /// | [] /// | [] /// | [] /// | [] /// +-+[] /// /// </summary> /// <param name="outHeader">byte[] buffer to write the header into</param> /// <param name="channelId">Channel ID to embed into the header</param> /// <param name="data">Data of the packet, given for calculating the data CRC</param> /// <param name="startPosition">Start position of the data in the given Data buffer</param> /// <param name="length">Length of the data in the given data buffer</param> /// <returns>The length of the header in bytes</returns> private byte CreateHeader(byte[] outHeader, byte channelId, byte[] data, int startPosition, ushort length) { if (length > 4096) { throw new Exception("Maximum data length is 4096 bytes! Got " + length); } var random = new System.Random(); var lengthBytes = BitConverter.GetBytes(length); var crc = CrcUtils.Checksum(data, startPosition, length, DATA_CRC_SIZE); var headerCrc = CrcUtils.Checksum(new byte[] { channelId, lengthBytes[0], lengthBytes[1] }, 0, 3, HEADER_CRC_SIZE); outHeader[0] = crc; outHeader[0] |= (byte)(channelId << 4); outHeader[0] |= (byte)(FIXED_PACKET_PREFIX << 6); outHeader[1] = (byte)(length >> 8 & FOUR_BITS_MASK); outHeader[2] = (byte)(length & FULL_BYTE_MASK); outHeader[1] |= (byte)(headerCrc << 4); return(HEADER_LENGTH); }
private bool ValidateCrc(byte crc, byte[] data, byte position, ushort length) { var dataCrc = CrcUtils.Checksum(data, position, length, DATA_CRC_SIZE); return(dataCrc == crc); }