mirror of
https://github.com/JasonYANG170/logicanalyzer.git
synced 2024-11-23 20:16:29 +00:00
Serial protocol analyzer
This commit is contained in:
parent
d087198d2c
commit
5189069412
|
@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogicAnalyzer", "LogicAnaly
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SPIProtocolAnalyzer", "SPIProtocolAnalyzer\SPIProtocolAnalyzer.csproj", "{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SPIProtocolAnalyzer", "SPIProtocolAnalyzer\SPIProtocolAnalyzer.csproj", "{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialProtocolAnalyzer", "SerialProtocolAnalyzer\SerialProtocolAnalyzer.csproj", "{E71855EA-04A7-48C1-860A-6A85E9D9E727}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -33,6 +35,10 @@ Global
|
||||||
{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6F18CFDA-7596-47F7-ABB9-AB09DC003C0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E71855EA-04A7-48C1-860A-6A85E9D9E727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E71855EA-04A7-48C1-860A-6A85E9D9E727}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E71855EA-04A7-48C1-860A-6A85E9D9E727}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E71855EA-04A7-48C1-860A-6A85E9D9E727}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<_LastSelectedProfileId>C:\Users\geniw\source\repos\LogicAnalyzer\LogicAnalyzer\Properties\PublishProfiles\Windows.pubxml</_LastSelectedProfileId>
|
<_LastSelectedProfileId>C:\Users\geniw\source\repos\LogicAnalyzer\LogicAnalyzer\Properties\PublishProfiles\Windows-Arm64.pubxml</_LastSelectedProfileId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -340,6 +340,9 @@ namespace LogicAnalyzer
|
||||||
if (await dlg.ShowDialog<bool>(this) != true)
|
if (await dlg.ShowDialog<bool>(this) != true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (dlg.SelectedSettings == null)
|
||||||
|
return;
|
||||||
|
|
||||||
var channels = dlg.SelectedChannels;
|
var channels = dlg.SelectedChannels;
|
||||||
var samples = sampleViewer.Samples;
|
var samples = sampleViewer.Samples;
|
||||||
|
|
||||||
|
|
213
Software/LogicAnalyzer/SerialProtocolAnalyzer/SerialAnalyzer.cs
Normal file
213
Software/LogicAnalyzer/SerialProtocolAnalyzer/SerialAnalyzer.cs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using LogicAnalyzer.Protocols;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SerialProtocolAnalyzer
|
||||||
|
{
|
||||||
|
public class SerialAnalyzer : ProtocolAnalyzerBase
|
||||||
|
{
|
||||||
|
private SimpleSegmentRenderer renderer = new SimpleSegmentRenderer();
|
||||||
|
|
||||||
|
static ProtocolAnalyzerSetting[] settings = new ProtocolAnalyzerSetting[]
|
||||||
|
{
|
||||||
|
new ProtocolAnalyzerSetting
|
||||||
|
{
|
||||||
|
Caption = "Polarity",
|
||||||
|
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||||
|
ListValues = new string[] { "Positive (TTL)", "Negative (RS232)" }
|
||||||
|
},
|
||||||
|
new ProtocolAnalyzerSetting
|
||||||
|
{
|
||||||
|
Caption = "Data bits",
|
||||||
|
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||||
|
ListValues = new string[] { "8", "7" }
|
||||||
|
},
|
||||||
|
new ProtocolAnalyzerSetting
|
||||||
|
{
|
||||||
|
Caption = "Parity",
|
||||||
|
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||||
|
ListValues = new string[] { "None", "Even", "Odd" }
|
||||||
|
},
|
||||||
|
new ProtocolAnalyzerSetting
|
||||||
|
{
|
||||||
|
Caption = "Stop bits",
|
||||||
|
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.List,
|
||||||
|
ListValues = new string[] { "1", "1.5", "2" }
|
||||||
|
},
|
||||||
|
new ProtocolAnalyzerSetting
|
||||||
|
{
|
||||||
|
Caption = "Bauds",
|
||||||
|
SettingType = ProtocolAnalyzerSetting.ProtocolAnalyzerSettingType.Integer,
|
||||||
|
IntegerMinimumValue= 200,
|
||||||
|
IntegerMaximumValue= 20000000,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static ProtocolAnalyzerSignal[] signals = new ProtocolAnalyzerSignal[]
|
||||||
|
{
|
||||||
|
new ProtocolAnalyzerSignal{ SignalName = "RX", Required = false },
|
||||||
|
new ProtocolAnalyzerSignal{ SignalName = "TX", Required = false },
|
||||||
|
};
|
||||||
|
public override string ProtocolName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Serial";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ProtocolAnalyzerSetting[] Settings
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ProtocolAnalyzerSignal[] Signals
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return signals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ProtocolAnalyzedChannel[] Analyze(int SamplingRate, int TriggerSample, ProtocolAnalyzerSettingValue[] SelectedSettings, ProtocolAnalyzerSelectedChannel[] SelectedChannels)
|
||||||
|
{
|
||||||
|
double period = (double)SamplingRate / (double)(int)SelectedSettings[4].Value;
|
||||||
|
|
||||||
|
if (period < 1)
|
||||||
|
return new ProtocolAnalyzedChannel[0];
|
||||||
|
|
||||||
|
int zero = SelectedSettings[0].Value.ToString() == settings[0].ListValues[0] ? 0 : 1;
|
||||||
|
|
||||||
|
int dataBits = int.Parse(SelectedSettings[1].Value.ToString());
|
||||||
|
string parity = SelectedSettings[2].Value.ToString();
|
||||||
|
double stopBits = double.Parse(SelectedSettings[3].Value.ToString());
|
||||||
|
List<ProtocolAnalyzedChannel> analyzed = new List<ProtocolAnalyzedChannel>();
|
||||||
|
|
||||||
|
foreach(var channel in SelectedChannels)
|
||||||
|
analyzed.Add(AnalyzeSerialData(dataBits, parity, stopBits, period, zero, channel));
|
||||||
|
|
||||||
|
return analyzed.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProtocolAnalyzedChannel AnalyzeSerialData(int dataBits, string? parity, double stopBits, double period, int zero, ProtocolAnalyzerSelectedChannel channel)
|
||||||
|
{
|
||||||
|
List<ProtocolAnalyzerDataSegment> segments = new List<ProtocolAnalyzerDataSegment>();
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
//Minimum samples needed for a byte, we skip the parity bits for the chance of getting a byte at the end
|
||||||
|
//of the samples
|
||||||
|
int samplesPerByte = (int)Math.Ceiling(period * (dataBits + (parity == "None" ? 0 : 1)));
|
||||||
|
|
||||||
|
while (pos < channel.Samples.Length)
|
||||||
|
{
|
||||||
|
//Find idle
|
||||||
|
while (pos < channel.Samples.Length && channel.Samples[pos] == zero)
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
//Find start condition
|
||||||
|
while (pos < channel.Samples.Length && channel.Samples[pos] != zero)
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
//Not found? abort
|
||||||
|
if (pos >= channel.Samples.Length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
byte value = 0;
|
||||||
|
byte val = 0;
|
||||||
|
bool parityError = false;
|
||||||
|
bool frameError = false;
|
||||||
|
int oneCount = 0;
|
||||||
|
int startPos = pos;
|
||||||
|
|
||||||
|
//If there are not enough bits for a byte end the loop
|
||||||
|
if (pos + samplesPerByte >= channel.Samples.Length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Position our sampling "pointer" on the middle of the start bit
|
||||||
|
double samplePos = pos + (period / 2) - 1; //
|
||||||
|
|
||||||
|
for (int buc = 0; buc < dataBits; buc++)
|
||||||
|
{
|
||||||
|
samplePos += period;
|
||||||
|
val = channel.Samples[(int)Math.Round(samplePos, 0)] == zero ? (byte)0 : (byte)1;
|
||||||
|
value |= (byte)(val << buc);
|
||||||
|
if (val == 1)
|
||||||
|
oneCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parity != "None")
|
||||||
|
{
|
||||||
|
samplePos += period;
|
||||||
|
val = channel.Samples[(int)Math.Round(samplePos, 0)] == zero ? (byte)0 : (byte)1;
|
||||||
|
if (val == 1)
|
||||||
|
oneCount++;
|
||||||
|
|
||||||
|
if((parity == "Even" && oneCount % 2 != 0) || (parity == "Odd" && oneCount % 2 == 0))
|
||||||
|
parityError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplePos += period;
|
||||||
|
if (samplePos >= channel.Samples.Length)
|
||||||
|
break;
|
||||||
|
val = channel.Samples[(int)Math.Round(samplePos, 0)] == zero ? (byte)0 : (byte)1;
|
||||||
|
|
||||||
|
if(val != 1)
|
||||||
|
frameError = true;
|
||||||
|
|
||||||
|
if (stopBits != 1)
|
||||||
|
{
|
||||||
|
samplePos += stopBits == 2 ? period : period * 0.75f;
|
||||||
|
if (samplePos >= channel.Samples.Length)
|
||||||
|
break;
|
||||||
|
val = channel.Samples[(int)Math.Round(samplePos, 0)] == zero ? (byte)0 : (byte)1;
|
||||||
|
|
||||||
|
if (val != 1)
|
||||||
|
frameError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int endPos = (int)Math.Round(samplePos, 0);
|
||||||
|
|
||||||
|
ProtocolAnalyzerDataSegment newSegment = new ProtocolAnalyzerDataSegment();
|
||||||
|
newSegment.Value = "0x" + value.ToString("X2") + "-'" + Encoding.ASCII.GetString(new byte[] { value }) + "'";
|
||||||
|
newSegment.FirstSample = startPos;
|
||||||
|
newSegment.LastSample = endPos;
|
||||||
|
string errors = "";
|
||||||
|
|
||||||
|
if (parityError)
|
||||||
|
errors += "P";
|
||||||
|
if(frameError)
|
||||||
|
errors += "F";
|
||||||
|
|
||||||
|
if (errors != "")
|
||||||
|
newSegment.Value += " <" + errors + ">";
|
||||||
|
|
||||||
|
segments.Add(newSegment);
|
||||||
|
|
||||||
|
pos = endPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolAnalyzedChannel aChannel = new ProtocolAnalyzedChannel(channel.SignalName, channel.ChannelIndex, renderer, segments.ToArray(), Colors.White, channel.SignalName == "TX" ? Color.FromUInt32(0x7f006400) : Color.FromUInt32(0x7f8b0000));
|
||||||
|
|
||||||
|
return aChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ValidateSettings(ProtocolAnalyzerSettingValue[] SelectedSettings, ProtocolAnalyzerSelectedChannel[] SelectedChannels)
|
||||||
|
{
|
||||||
|
if (SelectedSettings == null || SelectedSettings.Length == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (SelectedChannels == null || SelectedChannels.Length == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var setting in SelectedSettings)
|
||||||
|
if (setting.Value == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LogicAnalyzer\LogicAnalyzer.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Reference in New Issue
Block a user