mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-04 18:55:00 +00:00
Merge DIYglenn
This commit is contained in:
6
Debugging/Code/HanDebugger/HanDebugger/App.config
Normal file
6
Debugging/Code/HanDebugger/HanDebugger/App.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
56
Debugging/Code/HanDebugger/HanDebugger/Crc16.cs
Normal file
56
Debugging/Code/HanDebugger/HanDebugger/Crc16.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HanDebugger
|
||||
{
|
||||
public static class Crc16
|
||||
{
|
||||
private const ushort polynomial = 0x8408;
|
||||
private static ushort[] table = new ushort[256];
|
||||
|
||||
static Crc16()
|
||||
{
|
||||
ushort value;
|
||||
ushort temp;
|
||||
for (ushort i = 0; i < table.Length; ++i)
|
||||
{
|
||||
value = 0;
|
||||
temp = i;
|
||||
for (byte j = 0; j < 8; ++j)
|
||||
{
|
||||
if (((value ^ temp) & 0x0001) != 0)
|
||||
{
|
||||
value = (ushort)((value >> 1) ^ polynomial);
|
||||
}
|
||||
else
|
||||
{
|
||||
value >>= 1;
|
||||
}
|
||||
temp >>= 1;
|
||||
}
|
||||
table[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static ushort ComputeChecksum(byte[] data)
|
||||
{
|
||||
return ComputeChecksum(data, 0, data.Length);
|
||||
}
|
||||
|
||||
public static ushort ComputeChecksum(byte[] data, int start, int length)
|
||||
{
|
||||
ushort fcs = 0xffff;
|
||||
for (int i = start; i < (start + length); i++)
|
||||
{
|
||||
var index = (fcs ^ data[i]) & 0xff;
|
||||
fcs = (ushort)((fcs >> 8) ^ table[index]);
|
||||
}
|
||||
fcs ^= 0xffff;
|
||||
return fcs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
166
Debugging/Code/HanDebugger/HanDebugger/DlmsReader.cs
Normal file
166
Debugging/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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Debugging/Code/HanDebugger/HanDebugger/HanDebugger.csproj
Normal file
64
Debugging/Code/HanDebugger/HanDebugger/HanDebugger.csproj
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{EB8BDAFE-8991-4E9E-9E7E-F9BE61EBC122}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>HanDebugger</RootNamespace>
|
||||
<AssemblyName>HanDebugger</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Crc16.cs" />
|
||||
<Compile Include="KaifaHanBeta.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Reader.cs" />
|
||||
<Compile Include="DlmsReader.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
70
Debugging/Code/HanDebugger/HanDebugger/KaifaHanBeta.cs
Normal file
70
Debugging/Code/HanDebugger/HanDebugger/KaifaHanBeta.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HanDebugger
|
||||
{
|
||||
// As it seems Kaifa/Valider put some premature firmware on my AMS,
|
||||
// there's need for some dirty hacks to get any information
|
||||
public class KaifaHanBeta
|
||||
{
|
||||
public const byte ListUnknown = 0x00;
|
||||
public const byte List1 = 0x01;
|
||||
public const byte List2 = 0x0D;
|
||||
public const byte List3 = 0x12;
|
||||
|
||||
public static byte GetListID(byte[] package, int start, int length)
|
||||
{
|
||||
switch (package[start + 23])
|
||||
{
|
||||
case List1:
|
||||
case List2:
|
||||
case List3:
|
||||
return package[start + 23];
|
||||
default:
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
public static double GetPackageTime(byte[] package, int start, int length)
|
||||
{
|
||||
const int timeStart = 10;
|
||||
int year = package[start + timeStart] << 8 |
|
||||
package[start + timeStart + 1];
|
||||
|
||||
int month = package[start + timeStart + 2];
|
||||
int day = package[start + timeStart + 3];
|
||||
int hour = package[start + timeStart + 5];
|
||||
int minute = package[start + timeStart + 6];
|
||||
int second = package[start + timeStart + 7];
|
||||
|
||||
|
||||
return new DateTime(year, month, day, hour, minute, second).Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
|
||||
}
|
||||
|
||||
public static int GetInt(int dataPosition, byte[] buffer, int start, int length)
|
||||
{
|
||||
const int dataStart = 24;
|
||||
int value = 0;
|
||||
int foundPosition = 0;
|
||||
for (int i = start + dataStart; i < start + length; i++)
|
||||
{
|
||||
if (foundPosition == 0)
|
||||
{
|
||||
if (buffer[i] == 0x06)
|
||||
foundPosition = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = value << 8 |
|
||||
buffer[i];
|
||||
if (i == foundPosition + 4)
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Debugging/Code/HanDebugger/HanDebugger/Program.cs
Normal file
63
Debugging/Code/HanDebugger/HanDebugger/Program.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HanDebugger
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static List<byte> gBuffer = new List<byte>();
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
SerialPort vPort = new SerialPort("COM3", 2400, Parity.Even, 8, StopBits.One);
|
||||
vPort.DataReceived += VPort_DataReceived;
|
||||
vPort.Open();
|
||||
|
||||
while (true)
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
private static void VPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
var vPort = sender as SerialPort;
|
||||
byte[] vBuffer = new byte[1000];
|
||||
int vBytesRead = vPort.Read(vBuffer, 0, vBuffer.Length);
|
||||
for (int i = 0; i < vBytesRead; i++)
|
||||
{
|
||||
gBuffer.Add(vBuffer[i]);
|
||||
|
||||
// If we're catching a '7E' and it's not the beginning, it must be the end
|
||||
if (gBuffer.Count > 1 && vBuffer[i] == 0x7e)
|
||||
WriteAndEmptyBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteAndEmptyBuffer()
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} - Received {gBuffer.Count} (0x{gBuffer.Count:X2}) bytes]");
|
||||
|
||||
int j = 0;
|
||||
foreach (var vByte in gBuffer)
|
||||
{
|
||||
Console.Write(string.Format("{0:X2} ", (int)vByte));
|
||||
|
||||
if (++j % 8 == 0)
|
||||
Console.Write(" ");
|
||||
|
||||
if (j % 24 == 0)
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
|
||||
gBuffer.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("HanDebugger")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("HanDebugger")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("eb8bdafe-8991-4e9e-9e7e-f9be61ebc122")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
72
Debugging/Code/HanDebugger/HanDebugger/Reader.cs
Normal file
72
Debugging/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