1 //
2 // Copyright (c) 2010-2022 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Linq;
10 using System.Text;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Wireless.IEEE802_15_4
15 {
16     public class Frame
17     {
IsAcknowledgeRequested(byte[] frame)18         public static bool IsAcknowledgeRequested(byte[] frame)
19         {
20             return (frame[0] & 0x20) != 0;
21         }
22 
CreateAckForFrame(byte[] frame, uint crcInitialValue = 0x0, CRCPolynomial? crcPolynomial = null)23         public static Frame CreateAckForFrame(byte[] frame, uint crcInitialValue = 0x0, CRCPolynomial? crcPolynomial = null)
24         {
25             var sequenceNumber = frame[2];
26             // TODO: here we set pending bit as false
27             return CreateACK(sequenceNumber, false, crcInitialValue, crcPolynomial ?? DefaultCrcPolynomial);
28         }
29 
CreateACK(byte sequenceNumber, bool pending, uint crcInitialValue = 0x0, CRCPolynomial? crcPolynomial = null)30         public static Frame CreateACK(byte sequenceNumber, bool pending, uint crcInitialValue = 0x0, CRCPolynomial? crcPolynomial = null)
31         {
32             var result = new Frame();
33             result.Type = FrameType.ACK;
34             result.CRCPolynomial = crcPolynomial ?? DefaultCrcPolynomial;
35             result.FramePending = pending;
36             result.DataSequenceNumber = sequenceNumber;
37             result.Encode(crcInitialValue);
38 
39             return result;
40         }
41 
CalculateCRC(IEnumerable<byte> bytes, uint crcInitialValue = 0x0, CRCPolynomial? crcPolynomial = null)42         public static byte[] CalculateCRC(IEnumerable<byte> bytes, uint crcInitialValue = 0x0, CRCPolynomial? crcPolynomial = null)
43         {
44             uint crc;
45             var polynomial = crcPolynomial ?? DefaultCrcPolynomial;
46             var crcLength = polynomial.WidthInBytes;
47 
48             CRCEngine crcEngine = new CRCEngine(polynomial, init: crcInitialValue);
49             // Byte little endian order
50             switch(crcLength)
51             {
52                 case 2:
53                     crc = crcEngine.Calculate(bytes);
54                     return new[] { (byte)crc, (byte)(crc >> 8) };
55                 case 4:
56                     crc = crcEngine.Calculate(bytes);
57                     return new[] { (byte)crc, (byte)(crc >> 8), (byte)(crc >> 16), (byte)(crc >> 24) };
58                 default:
59                     Logger.Log(LogLevel.Error, "Cannot calculate CRC of invalid length {0}", crcLength);
60                     return new byte[crcLength];
61             }
62 
63         }
64 
Frame(byte[] data, CRCPolynomial? crcPolynomial = null)65         public Frame(byte[] data, CRCPolynomial? crcPolynomial = null)
66         {
67             Bytes = data;
68             CRCPolynomial = crcPolynomial ?? CRCPolynomial.CRC16_CCITT;
69             Decode(data);
70         }
71 
CheckCRC(uint crcInitialValue = 0x0)72         public bool CheckCRC(uint crcInitialValue = 0x0)
73         {
74             var crcLength = CRCPolynomial.WidthInBytes;
75             var crc = CalculateCRC(Bytes.Take(Bytes.Length - crcLength), crcInitialValue, CRCPolynomial);
76             // Byte little endian order
77             switch(crcLength)
78             {
79                 case 2:
80                     return Bytes[Bytes.Length - 2] == crc[0] && Bytes[Bytes.Length - 1] == crc[1];
81                 case 4:
82                     return Bytes[Bytes.Length - 4] == crc[0] && Bytes[Bytes.Length - 3] == crc[1] && Bytes[Bytes.Length - 2] == crc[2] && Bytes[Bytes.Length - 1] == crc[3];
83                 default:
84                     Logger.Log(LogLevel.Error, "Cannot check CRC of invalid length {0}", crcLength);
85                     return false;
86             }
87         }
88 
89         public byte Length { get { return (byte)Bytes.Length; } }
90         public FrameType Type { get; private set; }
91         public bool SecurityEnabled { get; private set; }
92         public bool FramePending { get; private set; }
93         public bool AcknowledgeRequest { get; private set; }
94         public bool IntraPAN { get; private set; }
95         public AddressingMode DestinationAddressingMode { get; private set; }
96         public byte FrameVersion { get; private set; }
97         public AddressingMode SourceAddressingMode { get; private set; }
98         public byte DataSequenceNumber { get; private set; }
99         public AddressInformation AddressInformation { get; private set; }
100         public IList<byte> Payload { get; private set; }
101         public byte[] Bytes { get; private set; }
102         public uint FrameControlField { get; private set; }
103         public CRCPolynomial CRCPolynomial { get; private set; }
104 
105         public string StringView
106         {
107             get
108             {
109                 var result = new StringBuilder();
110                 var nonPrintableCharacterFound = false;
111                 for(int i = 0; i < Payload.Count; i++)
112                 {
113                     if(Payload[i] < ' ' || Payload[i] > '~')
114                     {
115                         nonPrintableCharacterFound = true;
116                     }
117                     else {
118                         if(nonPrintableCharacterFound)
119                         {
120                             result.Append('.');
121                             nonPrintableCharacterFound = false;
122                         }
123 
124                         result.Append((char)Payload[i]);
125                     }
126                 }
127 
128                 return result.ToString();
129             }
130         }
131 
Frame()132         private Frame()
133         {
134         }
135 
GetAddressingFieldsLength()136         private int GetAddressingFieldsLength()
137         {
138             var result = 0;
139             result += DestinationAddressingMode.GetBytesLength();
140             result += SourceAddressingMode.GetBytesLength();
141             if(DestinationAddressingMode != AddressingMode.None)
142             {
143                 result += 2;
144             }
145             if(!IntraPAN && SourceAddressingMode != AddressingMode.None)
146             {
147                 result += 2;
148             }
149             return result;
150         }
151 
Decode(byte[] data)152         private void Decode(byte[] data)
153         {
154             if(data.Length > 127)
155             {
156                 throw new Exception("Frame length should not exceed 127 bytes.");
157             }
158 
159             Type = (FrameType)(data[0] & 0x7);
160             SecurityEnabled = (data[0] & 0x8) != 0;
161             FramePending = (data[0] & 0x10) != 0;
162             AcknowledgeRequest = IsAcknowledgeRequested(data);
163             IntraPAN = (data[0] & 0x40) != 0;
164             DestinationAddressingMode = (AddressingMode)((data[1] >> 2) & 0x3);
165             FrameVersion = (byte)((data[1] >> 4) & 0x3);
166             SourceAddressingMode = (AddressingMode)(data[1] >> 6);
167 
168             FrameControlField = ((uint)data[0] << 8) + data[1];
169 
170             DataSequenceNumber = data[2];
171             AddressInformation = new AddressInformation(DestinationAddressingMode, SourceAddressingMode, IntraPAN, new ArraySegment<byte>(data, 3, GetAddressingFieldsLength()));
172             Payload = new ArraySegment<byte>(data, 3 + AddressInformation.Bytes.Count, Length - (5 + AddressInformation.Bytes.Count));
173         }
174 
Encode(uint crcInitialValue = 0x0)175         private void Encode(uint crcInitialValue = 0x0)
176         {
177             var bytes = new List<byte>();
178             var frameControlByte0 = (byte)Type;
179             if(FramePending)
180             {
181                 frameControlByte0 |= (0x1 << 4);
182             }
183             bytes.Add(frameControlByte0);
184             bytes.Add(0); // frameControlByte1
185 
186             bytes.Add(DataSequenceNumber);
187             if(AddressInformation != null && AddressInformation.Bytes.Count > 0)
188             {
189                 bytes.AddRange(AddressInformation.Bytes);
190             }
191             if(Payload != null && Payload.Count > 0)
192             {
193                 bytes.AddRange(Payload);
194             }
195 
196             var crcLength = CRCPolynomial.WidthInBytes;
197             var crc = CalculateCRC(bytes, crcInitialValue, CRCPolynomial);
198             switch(crcLength)
199             {
200                 case 2:
201                     bytes.Add(crc[0]);
202                     bytes.Add(crc[1]);
203                     break;
204                 case 4:
205                     bytes.Add(crc[0]);
206                     bytes.Add(crc[1]);
207                     bytes.Add(crc[2]);
208                     bytes.Add(crc[3]);
209                     break;
210                 default:
211                     Logger.Log(LogLevel.Error, "Cannot generate CRC of invalid length {0}, the packet will not contain CRC data", crcLength);
212                     break;
213             }
214 
215             Bytes = bytes.ToArray();
216         }
217 
218         private static CRCPolynomial DefaultCrcPolynomial => CRCPolynomial.CRC16_CCITT;
219     }
220 }
221 
222