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