mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-10 12:49:21 +00:00
Created DlmsReader class and some tests
This commit is contained in:
166
Code/HanDebugger/HanDebugger/DlmsReader.cs
Normal file
166
Code/HanDebugger/HanDebugger/DlmsReader.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HanDebugger
|
||||
{
|
||||
public class DlmsReader
|
||||
{
|
||||
private byte[] buffer;
|
||||
private int position;
|
||||
private int dataLength;
|
||||
private byte frameFormatType;
|
||||
private byte[] destinationAddress;
|
||||
private byte[] sourceAddress;
|
||||
|
||||
public DlmsReader()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
buffer = new byte[256];
|
||||
position = 0;
|
||||
dataLength = 0;
|
||||
destinationAddress = null;
|
||||
sourceAddress = null;
|
||||
frameFormatType = 0;
|
||||
}
|
||||
|
||||
public bool Read(byte data)
|
||||
{
|
||||
if (position == 0 && data != 0x7E)
|
||||
{
|
||||
// we haven't started yet, wait for the start flag (no need to capture any data yet)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have completed reading of one package, so clear and be ready for the next
|
||||
if (dataLength > 0 && position >= dataLength + 2)
|
||||
Clear();
|
||||
|
||||
// Check if we're about to run into a buffer overflow
|
||||
if (position >= buffer.Length)
|
||||
Clear();
|
||||
|
||||
// Check if this is a second start flag, which indicates the previous one was a stop from the last package
|
||||
if (position == 1 && data == 0x7E)
|
||||
{
|
||||
// just return, we can keep the one byte we had in the buffer
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have started, so capture every byte
|
||||
buffer[position++] = data;
|
||||
|
||||
if (position == 1)
|
||||
{
|
||||
// This was the start flag, we're not done yet
|
||||
return false;
|
||||
}
|
||||
else if (position == 2)
|
||||
{
|
||||
// Capture the Frame Format Type
|
||||
frameFormatType = (byte)(data & 0xF0);
|
||||
if (!IsValidFrameFormat(frameFormatType))
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == 3)
|
||||
{
|
||||
// Capture the length of the data package
|
||||
dataLength = ((buffer[1] & 0x0F) << 8) | buffer[2];
|
||||
return false;
|
||||
}
|
||||
else if (destinationAddress == null)
|
||||
{
|
||||
// Capture the destination address
|
||||
destinationAddress = GetAddress(3);
|
||||
if (destinationAddress?.Length > 3)
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (sourceAddress == null)
|
||||
{
|
||||
// Capture the source address
|
||||
sourceAddress = GetAddress(3 + destinationAddress.Length);
|
||||
if (sourceAddress?.Length > 3)
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == 4 + destinationAddress.Length + sourceAddress.Length + 2)
|
||||
{
|
||||
// Verify the header checksum
|
||||
var headerChecksum = GetChecksum(position - 3);
|
||||
if (headerChecksum != Crc16.ComputeChecksum(buffer, 1, position - 3))
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == dataLength + 1)
|
||||
{
|
||||
// Verify the data package checksum
|
||||
var checksum = GetChecksum(position - 3);
|
||||
if (checksum != Crc16.ComputeChecksum(buffer, 1, position - 3))
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
else if (position == dataLength + 2)
|
||||
{
|
||||
// We're done, check the stop flag and signal we're done
|
||||
if (data == 0x7E)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsValidFrameFormat(byte frameFormatType)
|
||||
{
|
||||
return frameFormatType == 0xA0;
|
||||
}
|
||||
|
||||
public byte[] GetRawData()
|
||||
{
|
||||
if (dataLength > 0 && position == dataLength + 2)
|
||||
{
|
||||
var headerLength = 3 + destinationAddress.Length + sourceAddress.Length + 2;
|
||||
return buffer.Skip(headerLength + 1).Take(dataLength - headerLength - 2).ToArray();
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] GetAddress(int addressPosition)
|
||||
{
|
||||
List<byte> address = new List<byte>();
|
||||
for (int i = addressPosition; i < position; i++)
|
||||
{
|
||||
address.Add(buffer[i]);
|
||||
|
||||
// LSB=1 means this was the last address byte
|
||||
if ((buffer[i] & 0x01) == 0x01)
|
||||
break;
|
||||
|
||||
// See if we've reached last byte, try again when we've got more data
|
||||
else if (i == position - 1)
|
||||
return null;
|
||||
}
|
||||
return address.ToArray();
|
||||
}
|
||||
|
||||
private ushort GetChecksum(int checksumPosition)
|
||||
{
|
||||
return (ushort)(buffer[checksumPosition + 2] << 8 |
|
||||
buffer[checksumPosition + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,11 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Crc16.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Reader.cs" />
|
||||
<Compile Include="DlmsReader.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
|
||||
72
Code/HanDebugger/HanDebugger/Reader.cs
Normal file
72
Code/HanDebugger/HanDebugger/Reader.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HanDebugger
|
||||
{
|
||||
public class Reader
|
||||
{
|
||||
private int position;
|
||||
private int dataLength;
|
||||
private byte[] buffer;
|
||||
|
||||
public Reader(byte[] buffer)
|
||||
{
|
||||
this.buffer = buffer;
|
||||
position = 0;
|
||||
dataLength = ((buffer[1] & 0x0F) << 8) | buffer[2];
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return IsValidStart() &&
|
||||
IsValidLength() &&
|
||||
IsValidHeaderChecksum() &&
|
||||
IsValidChecksum();
|
||||
}
|
||||
|
||||
private bool IsValidChecksum()
|
||||
{
|
||||
ushort checkSum = GetChecksum(dataLength - 2);
|
||||
return checkSum == Crc16.ComputeChecksum(buffer, 1, dataLength - 2);
|
||||
}
|
||||
|
||||
private bool IsValidHeaderChecksum()
|
||||
{
|
||||
int headerLength = GetHeaderLength();
|
||||
ushort checkSum = GetChecksum(headerLength);
|
||||
return checkSum == Crc16.ComputeChecksum(buffer, 1, headerLength);
|
||||
}
|
||||
|
||||
private ushort GetChecksum(int checksumPosition)
|
||||
{
|
||||
return (ushort)(buffer[checksumPosition + 2] << 8 |
|
||||
buffer[checksumPosition + 1]);
|
||||
}
|
||||
|
||||
private int GetHeaderLength()
|
||||
{
|
||||
var pos = position + 3; // Dest address
|
||||
while ((buffer[pos] & 0x01) == 0x00)
|
||||
pos++;
|
||||
pos++; // source address
|
||||
while ((buffer[pos] & 0x01) == 0x00)
|
||||
pos++;
|
||||
pos++; // control field
|
||||
return pos;
|
||||
}
|
||||
|
||||
private bool IsValidLength()
|
||||
{
|
||||
return buffer.Length >= dataLength + 2;
|
||||
}
|
||||
|
||||
public bool IsValidStart()
|
||||
{
|
||||
return (buffer[0] == 0x7E);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user