// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Iot.Device.Arduino { /// /// This class is used to encode larger chunks of data for transmission using the Firmata protocol. /// It converts each block of 7 bytes into a block of 8 bytes, keeping the top bit 0. /// public static class Encoder7Bit { /// /// Calculates the number of bytes generated during decode (the result is smaller than the input) /// public static int Num8BitOutBytes(int inputBytes) { // Equals * 7 / 8 return (int)Math.Floor(((inputBytes) * 7) / 8.0); } /// /// Calculates the number of bytes required for the 7-byte encoding /// public static int Num7BitOutBytes(int inputBytes) { return (int)Math.Ceiling(((inputBytes) * 8.0) / 7); } /// /// Encode a sequence of bytes /// /// The data to encode /// The encoded data public static byte[] Encode(ReadOnlySpan data) { return Encode(data, 0, data.Length); } /// /// Encodes a sequence of bytes /// /// The data to encode /// The start index in the data /// The length of the data /// The encoded data public static byte[] Encode(ReadOnlySpan data, int startIndex, int length) { int shift = 0; byte[] retBytes = new byte[Num7BitOutBytes(length)]; int index = 0; int previous = 0; for (int i = startIndex; i < startIndex + length; i++) { if (shift == 0) { retBytes[index] = (byte)(data[i] & 0x7f); index++; shift++; previous = data[i] >> 7; } else { retBytes[index] = (byte)(((data[i] << shift) & 0x7f) | previous); index++; if (shift == 6) { retBytes[index] = (byte)(data[i] >> 1); index++; shift = 0; } else { shift++; previous = data[i] >> (8 - shift); } } } if (shift > 0) { // Write remainder retBytes[index] = (byte)previous; } return retBytes; } /// /// Decodes the given data sequence /// /// The data to decode /// The decoded data public static byte[] Decode(ReadOnlySpan inData) { byte[] outBytes = new byte[Num8BitOutBytes(inData.Length)]; for (int i = 0; i < outBytes.Length; i++) { int j = i << 3; int pos = j / 7; int shift = j % 7; outBytes[i] = (byte)((inData[pos] >> shift) | ((inData[pos + 1] << (7 - shift)) & 0xFF)); } return outBytes; } } }