forked from cyberprophet/iot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Encoder7Bit.cs
113 lines (104 loc) · 3.69 KB
/
Encoder7Bit.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// 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
{
/// <summary>
/// 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.
/// </summary>
public static class Encoder7Bit
{
/// <summary>
/// Calculates the number of bytes generated during decode (the result is smaller than the input)
/// </summary>
public static int Num8BitOutBytes(int inputBytes)
{
// Equals * 7 / 8
return (int)Math.Floor(((inputBytes) * 7) / 8.0);
}
/// <summary>
/// Calculates the number of bytes required for the 7-byte encoding
/// </summary>
public static int Num7BitOutBytes(int inputBytes)
{
return (int)Math.Ceiling(((inputBytes) * 8.0) / 7);
}
/// <summary>
/// Encode a sequence of bytes
/// </summary>
/// <param name="data">The data to encode</param>
/// <returns>The encoded data</returns>
public static byte[] Encode(ReadOnlySpan<byte> data)
{
return Encode(data, 0, data.Length);
}
/// <summary>
/// Encodes a sequence of bytes
/// </summary>
/// <param name="data">The data to encode</param>
/// <param name="startIndex">The start index in the data</param>
/// <param name="length">The length of the data</param>
/// <returns>The encoded data</returns>
public static byte[] Encode(ReadOnlySpan<byte> 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;
}
/// <summary>
/// Decodes the given data sequence
/// </summary>
/// <param name="inData">The data to decode</param>
/// <returns>The decoded data</returns>
public static byte[] Decode(ReadOnlySpan<byte> 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;
}
}
}