From 37886f72455b8388f021129901e5cc117a06202c Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 20 Aug 2025 11:29:56 +0200 Subject: [PATCH 001/203] ui: a bit of cleanup --- .../Converters/ChannelToStringConverter.cs | 2 +- app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs | 27 ++----------------- .../TRION-SDK-UI/Models/BoardPropertyModel.cs | 25 +++++++++++++++-- .../TRION-SDK-UI/Models/Channel.cs | 1 + .../TRION-SDK-UI/Models/Enclosure.cs | 17 ++++++++---- .../Models/ScanDescriptorDecoder.cs | 7 +---- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 9 +++---- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Converters/ChannelToStringConverter.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Converters/ChannelToStringConverter.cs index 59e3c7a..b788a4b 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Converters/ChannelToStringConverter.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Converters/ChannelToStringConverter.cs @@ -12,7 +12,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture var channel = value as Channel; if (channel == null) return string.Empty; - return $"Board {channel.BoardID} - {channel.Name}"; + return $"{channel.BoardName} - {channel.Name}"; } public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs index 5410057..38d993d 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs @@ -15,41 +15,18 @@ public enum BoardType Digital = 2, Counter = 3 } - public class Board(BoardPropertyModel BoardProperties) + public class Board() { public int Id { get; set; } public string? Name { get; set; } public bool IsActive { get; set; } - public BoardPropertyModel BoardProperties { get; set; } = BoardProperties; + public BoardPropertyModel? BoardProperties { get; set; } public List Channels { get; set; } = []; public uint ScanSizeBytes { get; set; } public ScanDescriptorDecoder? ScanDescriptorDecoder { get; set; } public string ScanDescriptorXml { get; set; } = string.Empty; - public void ReadScanDescriptor(string scanDescriptorXml) - { - if (string.IsNullOrWhiteSpace(scanDescriptorXml)) - { - System.Diagnostics.Debug.WriteLine($"Return Early"); - return; - } - System.Diagnostics.Debug.WriteLine($"BoardID {Id}"); - - ScanDescriptorDecoder = new ScanDescriptorDecoder(scanDescriptorXml); - Channels = [.. ScanDescriptorDecoder.Channels - .Select(c => new Channel - { - BoardID = Id, - Name = c.Name ?? string.Empty, - ChannelType = c.Type, - Index = c.Index, - SampleSize = c.SampleSize, - SampleOffset = c.SampleOffset - })]; - ScanSizeBytes = ScanDescriptorDecoder.ScanSizeBytes; - } - public void SetBoardProperties() { Id = BoardProperties.GetBoardID(); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/BoardPropertyModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/BoardPropertyModel.cs index 7fd3e79..7718f68 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/BoardPropertyModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/BoardPropertyModel.cs @@ -1,5 +1,6 @@ using System.Reflection.Metadata; using System.Xml.XPath; +using TRION_SDK_UI.Models; public class BoardPropertyModel { @@ -23,14 +24,34 @@ public List GetChannelNames() var channelNav = iterator.Current; if (channelNav != null) { - string channel = channelNav.Name; - channelNames.Add(channel); + channelNames.Add(channelNav.Name); } } return channelNames; } + public List GetChannels() + { + var channels = new List(); + var iterator = _navigator.Select("Properties/ChannelProperties/*"); + while (iterator.MoveNext()) + { + var channelNav = iterator.Current; + if (channelNav != null) + { + var channel = new Channel() + { + BoardID = GetBoardID(), + BoardName = GetBoardName(), + Name = channelNav.Name + }; + channels.Add(channel); + } + } + return channels; + } + public string GetBoardName() { var boardName = _navigator.SelectSingleNode("/Properties/BoardInfo/BoardName"); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs index c5281b3..e31a2a2 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs @@ -9,6 +9,7 @@ namespace TRION_SDK_UI.Models public class Channel { public int BoardID { get; set; } + public string? BoardName { get; set; } public string? Name { get; set; } public string? ChannelType { get; set; } public uint Index { get; set; } diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs index a2a8030..da00e31 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using System.Diagnostics; using Trion; using TRION_SDK_UI.Models; @@ -18,12 +19,18 @@ public void AddBoard(int boardId) var boardPropertiesXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "boardproperties").value; var boardPropertiesModel = new BoardPropertyModel(boardPropertiesXml); + var test = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "ScanDescriptor").value; + Debug.WriteLine($"This is a test: {test}"); - var newBoard = new Board(boardPropertiesModel); - - string scanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "ScanDescriptor").value; - newBoard.SetBoardProperties(); - newBoard.ReadScanDescriptor(scanDescriptorXml); + var newBoard = new Board() + { + Id = boardId, + Name = boardPropertiesModel.GetBoardName(), + IsActive = true, + BoardProperties = boardPropertiesModel, + Channels = boardPropertiesModel.GetChannels(), + ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "ScanDescriptor_V3").value + }; Boards.Add(newBoard); } diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs index 92b8006..a0a7f40 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs @@ -27,12 +27,7 @@ private void ParseScanDescriptor(string scanDescriptorXML) var doc = new XPathDocument(new System.IO.StringReader(scanDescriptorXML)); var nav = doc.CreateNavigator(); - var scanDescNode = nav.SelectSingleNode("ScanDescriptor/*/ScanDescription"); - if (scanDescNode == null) - { - throw new Exception("ScanDescriptor unexpected element"); - } - + var scanDescNode = nav.SelectSingleNode("ScanDescriptor/*/ScanDescription") ?? throw new Exception("ScanDescriptor unexpected element"); ScanSizeBytes = uint.Parse(scanDescNode.GetAttribute("scan_size", "")) / 8; var channelNodes = scanDescNode.Select("Channel"); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 7037e50..bb46231 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -147,12 +147,9 @@ public MainViewModel() foreach (var board in MyEnc.Boards) { LogMessages.Add($"Board: {board.Name} (ID: {board.Id})"); - foreach (var channel in board.Channels) + foreach (var channel in board.BoardProperties.GetChannels()) { - if (channel.Name != null) - { - Channels.Add(channel); - } + Channels.Add(channel); } } @@ -198,6 +195,8 @@ private void AcquireDataLoop(Channel selectedChannel) var board_id = selectedChannel.BoardID; var channel_name = selectedChannel.Name; + Debug.WriteLine($"Board ID: {board_id} channel name: {channel_name} "); + TrionApi.DeWeSetParamStruct($"BoardID{board_id}/AIAll", "Used", "False"); TrionApi.DeWeSetParamStruct($"BoardID{board_id}/{channel_name}", "Used", "True"); TrionApi.DeWeSetParamStruct($"BoardID{board_id}/{channel_name}", "Range", "10 V"); From 08cbc2082b4600e5feb09101851a663ccef86dd1 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 20 Aug 2025 12:42:33 +0200 Subject: [PATCH 002/203] ui: select the channels. no functionality --- .../TRION-SDK-UI/Models/Channel.cs | 1 + .../TRION-SDK-UI/Models/Enclosure.cs | 2 -- .../Models/ScanDescriptorDecoder.cs | 2 ++ .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 22 +++++++++++++++++-- .../TRION-SDK-UI/Views/MainPage.xaml | 17 +++++++------- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs index e31a2a2..10d3062 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Channel.cs @@ -15,5 +15,6 @@ public class Channel public uint Index { get; set; } public uint SampleSize { get; set; } public uint SampleOffset { get; set; } + public bool IsSelected { get; set; } } } diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs index da00e31..c1c2699 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs @@ -19,8 +19,6 @@ public void AddBoard(int boardId) var boardPropertiesXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "boardproperties").value; var boardPropertiesModel = new BoardPropertyModel(boardPropertiesXml); - var test = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "ScanDescriptor").value; - Debug.WriteLine($"This is a test: {test}"); var newBoard = new Board() { diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs index a0a7f40..f1ddabd 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ScanDescriptorDecoder.cs @@ -10,6 +10,7 @@ public class ChannelInfo public string? Name { get; set; } public string? Type { get; set; } public uint Index { get; set; } + public uint SamplePos { get; set; } public uint SampleSize { get; set; } public uint SampleOffset { get; set; } } @@ -48,6 +49,7 @@ private void ParseScanDescriptor(string scanDescriptorXML) Name = channel.GetAttribute("name", ""), Type = channel.GetAttribute("type", ""), Index = uint.Parse(channel.GetAttribute("index", "")), + SamplePos = uint.Parse(sample.GetAttribute("pos", "")), SampleSize = uint.Parse(sample.GetAttribute("size", "")), SampleOffset = uint.Parse(sample.GetAttribute("offset", "")) }); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index bb46231..bb819e2 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -203,8 +203,26 @@ private void AcquireDataLoop(Channel selectedChannel) MyEnc.Boards[board_id].SetAcquisitionProperties(sampleRate: "2000", buffer_block_size: 200, buffer_block_count: 50); MyEnc.Boards[board_id].UpdateBoard(); - - var (adcDelayError, adc_delay) = TrionApi.DeWeGetParam_i32(board_id, Trion.TrionCommand.BOARD_ADC_DELAY); + // --- Scan Descriptor Integration --- + var scanDescriptorResult = TrionApi.DeWeGetParamStruct_String($"BoardID{board_id}", "ScanDescriptor_V3"); + string scanDescriptorXml = scanDescriptorResult.value; + var decoder = new ScanDescriptorDecoder(scanDescriptorXml); + uint scanSizeBytes = decoder.ScanSizeBytes; + var channelInfo = decoder.Channels.FirstOrDefault(c => c.Name == channel_name); + + Debug.WriteLine( "#-------------------------------------------------"); + Debug.WriteLine($"#Board: {MyEnc.Boards[board_id]} {channel_name} "); + Debug.WriteLine($"#XML {scanDescriptorXml} "); + Debug.WriteLine($"#Channel Name {channelInfo.Name} "); + Debug.WriteLine($"#Channel Type {channelInfo.Type} "); + Debug.WriteLine($"#Channel Index {channelInfo.Index} "); + Debug.WriteLine($"#Scan Size {decoder.ScanSizeBytes} "); + Debug.WriteLine($"#SamplePos {channelInfo.SamplePos} "); + Debug.WriteLine($"#SampleSize {channelInfo.SampleSize} "); + Debug.WriteLine($"#SampleOffset {channelInfo.SampleOffset} "); + Debug.WriteLine( "#-------------------------------------------------"); + + var (adcDelayError, adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); CircularBuffer buffer = new(board_id); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml index e3fb2fb..1083af9 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml @@ -70,7 +70,7 @@ + HeightRequest="200"> From 5c13a8df9ea7cbee7b295ef3376eb5cbd3798b4d Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Tue, 26 Aug 2025 07:23:02 +0200 Subject: [PATCH 003/203] aligning the checkbox with the channel names --- app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml index 1083af9..5289f51 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml @@ -97,14 +97,15 @@ ItemsSource="{Binding Channels}" BackgroundColor="LightGray" SelectionMode="None" - Margin="8,0,0,0"> + Margin="10,0,0,0"> - - + + From f2c47d36a8bd505f3d6ae10ea5511fc7d1f9a99e Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Tue, 26 Aug 2025 08:09:03 +0200 Subject: [PATCH 004/203] ui: formatting changes --- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 198 +++++++++--------- 1 file changed, 102 insertions(+), 96 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index bb819e2..76d26c8 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -10,9 +10,9 @@ public class MainViewModel : BaseViewModel, IDisposable { public ChartRecorder Recorder { get; } = new(); - public ISeries[] MeasurementSeries { get; set; } = []; - + public ObservableCollection Channels { get; } = []; + public ObservableCollection LogMessages { get; } = []; public ObservableCollection ChartWindowData => Recorder.Window; public int WindowSize { @@ -39,88 +39,50 @@ public int ScrollIndex } } } + public Axis[]? YAxes { get; set; } public int MaxScrollIndex => Recorder.MaxScrollIndex; - - public ObservableCollection Channels { get; } = []; - public ObservableCollection LogMessages { get; } = []; - - private bool _isScrollingLocked = true; - - public Enclosure MyEnc { get; } = new Enclosure - { - Name = "MyEnc", - Boards = [] - }; - - private CancellationTokenSource? _cts; - private Task? _acquisitionTask; - private double _yAxisMin = -10; - public double YAxisMin + public ICommand ChannelSelectedCommand { get; private set; } + public ICommand StartAcquisitionCommand { get; private set; } + public ICommand StopAcquisitionCommand { get; private set; } + public ICommand LockScrollingCommand { get; private set; } + public double YAxisMax { - get => _yAxisMin; + get => _yAxisMax; set { - if (_yAxisMin != value) + if (_yAxisMax != value) { - _yAxisMin = value; + _yAxisMax = value; UpdateYAxes(); OnPropertyChanged(); } } } - private void StartAcquisition() - { - LogMessages.Add("Starting acquisition..."); - } - - private void StopAcquisition() - { - LogMessages.Add("Stopping acquisition..."); - } - private void LockScrolling() - { - _isScrollingLocked = !_isScrollingLocked; - LogMessages.Add(_isScrollingLocked ? "Scrolling locked." : "Scrolling unlocked."); - - if (_isScrollingLocked) - { - ScrollIndex = MaxScrollIndex; - } - } - - private double _yAxisMax = 10; - public double YAxisMax + public double YAxisMin { - get => _yAxisMax; + get => _yAxisMin; set { - if (_yAxisMax != value) + if (_yAxisMin != value) { - _yAxisMax = value; + _yAxisMin = value; UpdateYAxes(); OnPropertyChanged(); } } } - - public Axis[]? YAxes { get; set; } - private void UpdateYAxes() + public void Dispose() { - YAxes = [ - new Axis - { - MinLimit = YAxisMin, - MaxLimit = YAxisMax, - Name = "Voltage" - } - ]; - OnPropertyChanged(nameof(YAxes)); - } + TrionApi.DeWeSetParam_i32(0, TrionCommand.CLOSE_BOARD_ALL, 0); - public ICommand ChannelSelectedCommand { get; private set; } - public ICommand StartAcquisitionCommand { get; private set; } - public ICommand StopAcquisitionCommand { get; private set; } - public ICommand LockScrollingCommand { get; private set; } + // Call your uninitialize function here + TrionApi.Uninitialize(); + } + public Enclosure MyEnc { get; } = new Enclosure + { + Name = "MyEnc", + Boards = [] + }; public MainViewModel() { LogMessages.Add("App started."); @@ -154,43 +116,87 @@ public MainViewModel() } OnPropertyChanged(nameof(Channels)); - ChannelSelectedCommand = new Command(OnChannelSelected); StartAcquisitionCommand = new Command(StartAcquisition); StopAcquisitionCommand = new Command(StopAcquisition); LockScrollingCommand = new Command(LockScrolling); UpdateYAxes(); } - public void Dispose() + private readonly CancellationTokenSource? _cts; + private readonly Task? _acquisitionTask; + private List _acquisitionTasks = []; + private readonly List _ctsList = []; + private bool _isScrollingLocked = true; + private double _yAxisMin = -10; + private void StartAcquisition() { - TrionApi.DeWeSetParam_i32(0, TrionCommand.CLOSE_BOARD_ALL, 0); + LogMessages.Add("Starting acquisition..."); - // Call your uninitialize function here - TrionApi.Uninitialize(); - } + StopAcquisition(); - private void OnChannelSelected(Channel selectedChannel) - { - _cts?.Cancel(); - _acquisitionTask?.Wait(); - Recorder.Data.Clear(); - Recorder.Window.Clear(); + _acquisitionTasks.Clear(); + _ctsList.Clear(); - MeasurementSeries = [ - new LineSeries - { - Values = ChartWindowData, - Name = $"{selectedChannel.Name}", - AnimationsSpeed = TimeSpan.Zero, - GeometrySize = 0 - }]; + var selectedChannels = Channels.Where(c => c.IsSelected).ToList(); + if (selectedChannels.Count == 0) + { + LogMessages.Add("No channels selected."); + return; + } + + MeasurementSeries = selectedChannels.Select(ch => new LineSeries + { + Values = ChartWindowData, + Name = ch.Name, + AnimationsSpeed = TimeSpan.Zero, + GeometrySize = 0 + }).ToArray(); OnPropertyChanged(nameof(MeasurementSeries)); - _cts = new CancellationTokenSource(); - _acquisitionTask = Task.Run(() => AcquireDataLoop(selectedChannel), _cts.Token); + foreach (var channel in selectedChannels) + { + Debug.WriteLine($"Channel selected: {channel.Name}"); + var cts = new CancellationTokenSource(); + _ctsList.Add(cts); + var task = Task.Run(() => AcquireDataLoop(channel, cts.Token), cts.Token); + _acquisitionTasks.Add(task); + } + } + private void StopAcquisition() + { + LogMessages.Add("Stopping acquisition..."); + foreach (var cts in _ctsList) + { + cts.Cancel(); + } + Task.WaitAll(_acquisitionTasks.ToArray(), 1000); + _acquisitionTasks.Clear(); + _ctsList.Clear(); } + private void LockScrolling() + { + _isScrollingLocked = !_isScrollingLocked; + LogMessages.Add(_isScrollingLocked ? "Scrolling locked." : "Scrolling unlocked."); - private void AcquireDataLoop(Channel selectedChannel) + if (_isScrollingLocked) + { + ScrollIndex = MaxScrollIndex; + } + } + private double _yAxisMax = 10; + private void UpdateYAxes() + { + YAxes = [ + new Axis + { + MinLimit = YAxisMin, + MaxLimit = YAxisMax, + Name = "Voltage" + } + ]; + OnPropertyChanged(nameof(YAxes)); + } + private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) { var board_id = selectedChannel.BoardID; var channel_name = selectedChannel.Name; @@ -211,22 +217,22 @@ private void AcquireDataLoop(Channel selectedChannel) var channelInfo = decoder.Channels.FirstOrDefault(c => c.Name == channel_name); Debug.WriteLine( "#-------------------------------------------------"); - Debug.WriteLine($"#Board: {MyEnc.Boards[board_id]} {channel_name} "); - Debug.WriteLine($"#XML {scanDescriptorXml} "); - Debug.WriteLine($"#Channel Name {channelInfo.Name} "); - Debug.WriteLine($"#Channel Type {channelInfo.Type} "); - Debug.WriteLine($"#Channel Index {channelInfo.Index} "); - Debug.WriteLine($"#Scan Size {decoder.ScanSizeBytes} "); - Debug.WriteLine($"#SamplePos {channelInfo.SamplePos} "); - Debug.WriteLine($"#SampleSize {channelInfo.SampleSize} "); - Debug.WriteLine($"#SampleOffset {channelInfo.SampleOffset} "); + Debug.WriteLine($"#Board: {MyEnc.Boards[board_id]} {channel_name}"); + Debug.WriteLine($"#XML {scanDescriptorXml}"); + Debug.WriteLine($"#Channel Name {channelInfo.Name}"); + Debug.WriteLine($"#Channel Type {channelInfo.Type}"); + Debug.WriteLine($"#Channel Index {channelInfo.Index}"); + Debug.WriteLine($"#Scan Size {decoder.ScanSizeBytes}"); + Debug.WriteLine($"#SamplePos {channelInfo.SamplePos}"); + Debug.WriteLine($"#SampleSize {channelInfo.SampleSize}"); + Debug.WriteLine($"#SampleOffset {channelInfo.SampleOffset}"); Debug.WriteLine( "#-------------------------------------------------"); var (adcDelayError, adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); CircularBuffer buffer = new(board_id); - while (_cts != null && !_cts.IsCancellationRequested) + while (!token.IsCancellationRequested) { var (available_samples_error, available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_WAIT_AVAIL_NO_SAMPLE); available_samples -= adc_delay; From 419463ec69a647935bf506fdae005d373170fd2e Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Tue, 26 Aug 2025 13:34:26 +0200 Subject: [PATCH 005/203] ui: very bad way to select channels and enable the ones we want --- app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs | 36 ++++++- .../TRION-SDK-UI/Models/ChartRecorder.cs | 60 ++++++++--- .../TRION-SDK-UI/Models/Enclosure.cs | 1 + .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 102 ++++++++++++------ .../TRION-SDK-UI/Views/MainPage.xaml | 14 +++ 5 files changed, 163 insertions(+), 50 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs index 38d993d..4bfb302 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -18,7 +19,6 @@ public enum BoardType public class Board() { public int Id { get; set; } - public string? Name { get; set; } public bool IsActive { get; set; } public BoardPropertyModel? BoardProperties { get; set; } @@ -46,12 +46,42 @@ public void SetAcquisitionProperties(string operationMode = "Slave", error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "ExtClk", externalClock); error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "SampleRate", sampleRate); - error |= TrionApi.DeWeSetParam_i32(Id, Trion.TrionCommand.BUFFER_BLOCK_SIZE, buffer_block_size); - error |= TrionApi.DeWeSetParam_i32(Id, Trion.TrionCommand.BUFFER_BLOCK_COUNT, buffer_block_count); + error |= TrionApi.DeWeSetParam_i32(Id, TrionCommand.BUFFER_BLOCK_SIZE, buffer_block_size); + error |= TrionApi.DeWeSetParam_i32(Id, TrionCommand.BUFFER_BLOCK_COUNT, buffer_block_count); Utils.CheckErrorCode(error, $"Failed to set acquisition properties for board {Id}"); } + public void ActivateChannels(IEnumerable channelsToActivate) + { + // First, deactivate all channels on this board + var error = TrionApi.DeWeSetParamStruct($"BoardID{Id}/AIAll", "Used", "False"); + + // Then, activate only the specified channels + foreach (var channel in channelsToActivate) + { + Debug.WriteLine($"TEST channelsToActivate {channel.Name}"); + if (channel.BoardID != Id) + { + return; + } + error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/{channel.Name}", "Used", "True"); + Debug.WriteLine($"TEST Used: BoardID{Id}/{channel.Name}"); + error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/{channel.Name}", "Range", "10 V"); + error |= TrionApi.DeWeSetParam_i32(Id, TrionCommand.RESET_BOARD, 0); + + } + ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{Id}", "ScanDescriptor_V3").value; + Debug.WriteLine($"TEST XML {ScanDescriptorXml}"); + ScanDescriptorDecoder = new ScanDescriptorDecoder(ScanDescriptorXml); + ScanSizeBytes = ScanDescriptorDecoder.ScanSizeBytes; + + + SetAcquisitionProperties(sampleRate: "2000", buffer_block_size: 200, buffer_block_count: 50); + UpdateBoard(); + Utils.CheckErrorCode(error, $"Failed to activate channels for board {Id}"); + } + public void ResetBoard() { var error = TrionApi.DeWeSetParam_i32(Id, TrionCommand.RESET_BOARD, 0); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs index 225bc5c..b0f4716 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs @@ -2,9 +2,10 @@ public class ChartRecorder { - public List Data { get; } = []; - public ObservableCollection Window { get; } = []; - + // Store all data per channel + private readonly Dictionary> _data = []; + // Store windowed data per channel for UI binding + private readonly Dictionary> _windows = []; private int _windowSize = 800; public int WindowSize { @@ -14,7 +15,7 @@ public int WindowSize if (_windowSize != value) { _windowSize = value; - UpdateWindow(); + UpdateAllWindows(); } } } @@ -28,29 +29,60 @@ public int ScrollIndex if (_scrollIndex != value) { _scrollIndex = value; - UpdateWindow(); + UpdateAllWindows(); } } } - public int MaxScrollIndex => Math.Max(0, Data.Count - WindowSize); + // Get the window for a specific channel (for binding) + public ObservableCollection GetWindow(string channel) + { + if (!_windows.ContainsKey(channel)) + { + _windows[channel] = []; + } + return _windows[channel]; + } - public void AddSamples(IEnumerable samples) + // Add samples to a specific channel + public void AddSamples(string channel, IEnumerable samples) { - Data.AddRange(samples); - UpdateWindow(); + if (!_data.ContainsKey(channel)) + { + _data[channel] = []; + } + _data[channel].AddRange(samples); + UpdateWindow(channel); } - public void UpdateWindow() + // Update the window for a specific channel + private void UpdateWindow(string channel) { - Window.Clear(); - foreach (var v in Data.Skip(ScrollIndex).Take(WindowSize)) - Window.Add(v); + var data = _data[channel]; + var window = GetWindow(channel); + window.Clear(); + foreach (var v in data.Skip(ScrollIndex).Take(WindowSize)) + { + window.Add(v); + } } + // Update all windows (e.g., when window size or scroll index changes) + public void UpdateAllWindows() + { + foreach (var channel in _data.Keys) + { + UpdateWindow(channel); + } + } + + // Auto-scroll all channels public void AutoScroll() { ScrollIndex = MaxScrollIndex; - UpdateWindow(); + UpdateAllWindows(); } + + // Get max scroll index for a specific channel + public int MaxScrollIndex => _data.Values.Select(d => Math.Max(0, d.Count - WindowSize)).DefaultIfEmpty(0).Max(); } \ No newline at end of file diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs index c1c2699..1a2ba1e 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using Trion; using TRION_SDK_UI.Models; +using TrionApiUtils; public class Enclosure diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 76d26c8..68b6698 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -11,9 +11,9 @@ public class MainViewModel : BaseViewModel, IDisposable { public ChartRecorder Recorder { get; } = new(); public ISeries[] MeasurementSeries { get; set; } = []; + public ObservableCollection ChannelSeries { get; } = new(); public ObservableCollection Channels { get; } = []; public ObservableCollection LogMessages { get; } = []; - public ObservableCollection ChartWindowData => Recorder.Window; public int WindowSize { get => Recorder.WindowSize; @@ -138,21 +138,70 @@ private void StartAcquisition() _ctsList.Clear(); var selectedChannels = Channels.Where(c => c.IsSelected).ToList(); - if (selectedChannels.Count == 0) + var selectedBoardIds = selectedChannels.Select(c => c.BoardID).Distinct(); + var selectedBoards = MyEnc.Boards.Where(b => selectedBoardIds.Contains(b.Id)).ToList(); + + foreach (var ch in selectedChannels) + { + Debug.WriteLine($"TEST selected channel: {ch.Name}"); + } + foreach (var bid in selectedBoardIds) + { + Debug.WriteLine($"TEST selected board ids: {bid}"); + } + foreach (var selb in selectedBoards) + { + Debug.WriteLine($"TEST selected boads: {selb.Name}"); + } + + // Reset boards + foreach (var selected_board in selectedBoards) + { + selected_board.ResetBoard(); + } + // set board properties + // set buffer properties + foreach (var selected_board in selectedBoards) + { + selected_board.SetAcquisitionProperties(); + } + // disable all channels + foreach (var selected_board in selectedBoards) + { + TrionApi.DeWeSetParamStruct($"BoardID{selected_board.Id}/AIAll", "Used", "False"); + } + // enable selected channels + foreach (var selected_channel in selectedChannels) + { + TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Used", "True"); + TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Range", "10 V"); + } + // update parameters + foreach (var selected_board in selectedBoards) { - LogMessages.Add("No channels selected."); - return; + selected_board.UpdateBoard(); } + + + MeasurementSeries = selectedChannels.Select(ch => new LineSeries { - Values = ChartWindowData, + Values = Recorder.GetWindow(ch.Name), Name = ch.Name, AnimationsSpeed = TimeSpan.Zero, GeometrySize = 0 }).ToArray(); OnPropertyChanged(nameof(MeasurementSeries)); + foreach (var board in MyEnc.Boards) + { + board.ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3").value; + board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); + board.ScanSizeBytes = board.ScanDescriptorDecoder.ScanSizeBytes; + Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); + } + foreach (var channel in selectedChannels) { Debug.WriteLine($"Channel selected: {channel.Name}"); @@ -161,6 +210,19 @@ private void StartAcquisition() var task = Task.Run(() => AcquireDataLoop(channel, cts.Token), cts.Token); _acquisitionTasks.Add(task); } + ChannelSeries.Clear(); + foreach (var ch in Channels.Where(c => c.IsSelected)) + { + var series = new LineSeries + { + Values = Recorder.GetWindow(ch.Name), + Name = ch.Name, + AnimationsSpeed = TimeSpan.Zero, + GeometrySize = 0 + }; + ChannelSeries.Add([series]); + } + OnPropertyChanged(nameof(ChannelSeries)); } private void StopAcquisition() { @@ -201,33 +263,6 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) var board_id = selectedChannel.BoardID; var channel_name = selectedChannel.Name; - Debug.WriteLine($"Board ID: {board_id} channel name: {channel_name} "); - - TrionApi.DeWeSetParamStruct($"BoardID{board_id}/AIAll", "Used", "False"); - TrionApi.DeWeSetParamStruct($"BoardID{board_id}/{channel_name}", "Used", "True"); - TrionApi.DeWeSetParamStruct($"BoardID{board_id}/{channel_name}", "Range", "10 V"); - - MyEnc.Boards[board_id].SetAcquisitionProperties(sampleRate: "2000", buffer_block_size: 200, buffer_block_count: 50); - MyEnc.Boards[board_id].UpdateBoard(); - // --- Scan Descriptor Integration --- - var scanDescriptorResult = TrionApi.DeWeGetParamStruct_String($"BoardID{board_id}", "ScanDescriptor_V3"); - string scanDescriptorXml = scanDescriptorResult.value; - var decoder = new ScanDescriptorDecoder(scanDescriptorXml); - uint scanSizeBytes = decoder.ScanSizeBytes; - var channelInfo = decoder.Channels.FirstOrDefault(c => c.Name == channel_name); - - Debug.WriteLine( "#-------------------------------------------------"); - Debug.WriteLine($"#Board: {MyEnc.Boards[board_id]} {channel_name}"); - Debug.WriteLine($"#XML {scanDescriptorXml}"); - Debug.WriteLine($"#Channel Name {channelInfo.Name}"); - Debug.WriteLine($"#Channel Type {channelInfo.Type}"); - Debug.WriteLine($"#Channel Index {channelInfo.Index}"); - Debug.WriteLine($"#Scan Size {decoder.ScanSizeBytes}"); - Debug.WriteLine($"#SamplePos {channelInfo.SamplePos}"); - Debug.WriteLine($"#SampleSize {channelInfo.SampleSize}"); - Debug.WriteLine($"#SampleOffset {channelInfo.SampleOffset}"); - Debug.WriteLine( "#-------------------------------------------------"); - var (adcDelayError, adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); CircularBuffer buffer = new(board_id); @@ -254,6 +289,7 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) float value = Marshal.ReadInt32((IntPtr)read_pos); value = (float)((float)value / 0x7FFFFF00 * 10.0); tempValues[i] = value; + //Debug.WriteLine($"TEST: Value {value}"); read_pos += sizeof(uint); } @@ -261,7 +297,7 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) MainThread.BeginInvokeOnMainThread(() => { - Recorder.AddSamples(tempValues); + Recorder.AddSamples(selectedChannel.Name, tempValues); if (_isScrollingLocked) { diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml index 5289f51..6484e78 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml @@ -77,6 +77,20 @@ + + + + + + + + + From aca4cfecb1ab0b02d7b014a3233387572204ba42 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Tue, 26 Aug 2025 14:31:17 +0200 Subject: [PATCH 006/203] graph data almost fixed. still an error at 0 and very slow to start the acquisition. mulitple channels still dont work --- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 68b6698..86c206c 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -141,33 +141,11 @@ private void StartAcquisition() var selectedBoardIds = selectedChannels.Select(c => c.BoardID).Distinct(); var selectedBoards = MyEnc.Boards.Where(b => selectedBoardIds.Contains(b.Id)).ToList(); - foreach (var ch in selectedChannels) - { - Debug.WriteLine($"TEST selected channel: {ch.Name}"); - } - foreach (var bid in selectedBoardIds) - { - Debug.WriteLine($"TEST selected board ids: {bid}"); - } - foreach (var selb in selectedBoards) - { - Debug.WriteLine($"TEST selected boads: {selb.Name}"); - } - // Reset boards foreach (var selected_board in selectedBoards) { selected_board.ResetBoard(); - } - // set board properties - // set buffer properties - foreach (var selected_board in selectedBoards) - { selected_board.SetAcquisitionProperties(); - } - // disable all channels - foreach (var selected_board in selectedBoards) - { TrionApi.DeWeSetParamStruct($"BoardID{selected_board.Id}/AIAll", "Used", "False"); } // enable selected channels @@ -183,8 +161,6 @@ private void StartAcquisition() } - - MeasurementSeries = selectedChannels.Select(ch => new LineSeries { Values = Recorder.GetWindow(ch.Name), @@ -199,12 +175,12 @@ private void StartAcquisition() board.ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3").value; board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); board.ScanSizeBytes = board.ScanDescriptorDecoder.ScanSizeBytes; - Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); + //Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); } foreach (var channel in selectedChannels) { - Debug.WriteLine($"Channel selected: {channel.Name}"); + //Debug.WriteLine($"Channel selected: {channel.Name}"); var cts = new CancellationTokenSource(); _ctsList.Add(cts); var task = Task.Run(() => AcquireDataLoop(channel, cts.Token), cts.Token); @@ -260,9 +236,13 @@ private void UpdateYAxes() } private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) { - var board_id = selectedChannel.BoardID; - var channel_name = selectedChannel.Name; + var board = MyEnc.Boards.First(b => b.Id == selectedChannel.BoardID); + var scanSize = (int)board.ScanSizeBytes; + var scanDescriptor = board.ScanDescriptorDecoder; + var channelInfo = scanDescriptor.Channels.FirstOrDefault(c => c.Name == selectedChannel.Name); + if (channelInfo == null) return; + var board_id = selectedChannel.BoardID; var (adcDelayError, adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); CircularBuffer buffer = new(board_id); @@ -277,21 +257,35 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) continue; } var (read_pos_error, read_pos) = TrionApi.DeWeGetParam_i64(board_id, TrionCommand.BUFFER_0_ACT_SAMPLE_POS); - read_pos += adc_delay * sizeof(uint); - List tempValues = [.. new double[available_samples]]; + read_pos += adc_delay * scanSize; + + List tempValues = new List(available_samples); for (int i = 0; i < available_samples; ++i) { - if (read_pos >= buffer.EndPosition) + var offset_bytes = (int)channelInfo.SampleOffset / 8; + var samplePos = read_pos + offset_bytes; + int raw = Marshal.ReadInt32((IntPtr)samplePos); + + // Apply bitmask for sample size + int bitmask = (1 << (int)channelInfo.SampleSize) - 1; + raw &= bitmask; + + // Sign extension if needed + if ((raw & (1 << ((int)channelInfo.SampleSize - 1))) != 0) { - read_pos -= buffer.Size; + raw |= ~bitmask; } - float value = Marshal.ReadInt32((IntPtr)read_pos); - value = (float)((float)value / 0x7FFFFF00 * 10.0); - tempValues[i] = value; - //Debug.WriteLine($"TEST: Value {value}"); + // Scale value (adjust scaling for your hardware/range) + double value = (double)raw / 0x7FFFFF * 10.0; + + tempValues.Add(value); - read_pos += sizeof(uint); + read_pos += scanSize; + if (read_pos >= buffer.EndPosition) + { + read_pos -= buffer.Size; + } } TrionApi.DeWeSetParam_i32(board_id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); From c2e447e77229d6f2ad15bd9452c731935b1c882c Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Tue, 26 Aug 2025 14:45:56 +0200 Subject: [PATCH 007/203] ui: some changes to the data processing --- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 86c206c..9e65a65 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -260,27 +260,33 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) read_pos += adc_delay * scanSize; List tempValues = new List(available_samples); + // loop over available samples for (int i = 0; i < available_samples; ++i) { + // calculate the position of the sample in memory var offset_bytes = (int)channelInfo.SampleOffset / 8; var samplePos = read_pos + offset_bytes; + + // read the raw data int raw = Marshal.ReadInt32((IntPtr)samplePos); - // Apply bitmask for sample size - int bitmask = (1 << (int)channelInfo.SampleSize) - 1; + // extract the actual sample bits + int sampleSize = (int)channelInfo.SampleSize; + int bitmask = (1 << sampleSize) - 1; raw &= bitmask; - // Sign extension if needed - if ((raw & (1 << ((int)channelInfo.SampleSize - 1))) != 0) - { + // general sign extension for N-bit signed value + int signBit = 1 << (sampleSize - 1); + if ((raw & signBit) != 0) raw |= ~bitmask; - } - // Scale value (adjust scaling for your hardware/range) - double value = (double)raw / 0x7FFFFF * 10.0; + // scale to engineering units (i guess the range needs to be adjustable) + double value = (double)raw / (double)(signBit - 1) * 10.0; + // store the result tempValues.Add(value); + // move to the next sample in the buffer read_pos += scanSize; if (read_pos >= buffer.EndPosition) { From 23b9eb781b1105152d8f83d3a45aa7164b2532dc Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Tue, 26 Aug 2025 15:48:05 +0200 Subject: [PATCH 008/203] ui: almost able to show multiple channels --- .../TRION-SDK-UI/Models/ChartRecorder.cs | 6 ++++ .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 5 ++++ .../TRION-SDK-UI/Views/MainPage.xaml | 29 ++++++++++--------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs index b0f4716..fae7232 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs @@ -40,6 +40,11 @@ public ObservableCollection GetWindow(string channel) if (!_windows.ContainsKey(channel)) { _windows[channel] = []; + //System.Diagnostics.Debug.WriteLine($"Created new window for channel: {channel} (HashCode: {_windows[channel].GetHashCode()})"); + } + else + { + //System.Diagnostics.Debug.WriteLine($"Returning existing window for channel: {channel} (HashCode: {_windows[channel].GetHashCode()})"); } return _windows[channel]; } @@ -47,6 +52,7 @@ public ObservableCollection GetWindow(string channel) // Add samples to a specific channel public void AddSamples(string channel, IEnumerable samples) { + System.Diagnostics.Debug.WriteLine($"AddSamples called for channel: {channel}, sample count: {samples.Count()}"); if (!_data.ContainsKey(channel)) { _data[channel] = []; diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 9e65a65..6089d62 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -189,6 +189,9 @@ private void StartAcquisition() ChannelSeries.Clear(); foreach (var ch in Channels.Where(c => c.IsSelected)) { + var window = Recorder.GetWindow(ch.Name); + System.Diagnostics.Debug.WriteLine($"Channel: {ch.Name}, Window HashCode: {window.GetHashCode()}, Count: {window.Count}"); + var series = new LineSeries { Values = Recorder.GetWindow(ch.Name), @@ -247,6 +250,8 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); CircularBuffer buffer = new(board_id); + System.Diagnostics.Debug.WriteLine($"AcquireDataLoop started for channel: {selectedChannel.Name}"); + while (!token.IsCancellationRequested) { var (available_samples_error, available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_WAIT_AVAIL_NO_SAMPLE); diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml index 6484e78..136f92b 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml @@ -2,6 +2,7 @@ @@ -67,27 +68,27 @@ Value="{Binding ScrollIndex, Mode=TwoWay}" Margin="0,10,0,0"/> - - - - - - - + VerticalOptions="Fill"> + YAxes="{Binding YAxes}" + HeightRequest="300" + VerticalOptions="Fill"/> + + + + + + + + From 04e2f17dda042c8e1e8866f7ef983b108c28d3ad Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 10:10:53 +0200 Subject: [PATCH 009/203] ui: little error checks changes --- app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs | 12 +++- .../TRION-SDK-UI/Models/ChartRecorder.cs | 2 +- .../TRION-SDK-UI/Models/Enclosure.cs | 9 ++- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 68 +++++++++++++------ .../TRION-SDK-UI/Views/MainPage.xaml | 7 +- trion_api/CS/TrionApi/TrionApi.cs | 3 +- 6 files changed, 68 insertions(+), 33 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs index 4bfb302..c538f81 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs @@ -26,6 +26,9 @@ public class Board() public uint ScanSizeBytes { get; set; } public ScanDescriptorDecoder? ScanDescriptorDecoder { get; set; } public string ScanDescriptorXml { get; set; } = string.Empty; + public int BufferBlockSize { get; set; } + public int SamplingRate { get; set; } + public int BufferBlockCount { get; set; } public void SetBoardProperties() { @@ -37,14 +40,17 @@ public void SetBoardProperties() public void SetAcquisitionProperties(string operationMode = "Slave", string externalTrigger = "False", string externalClock = "False", - string sampleRate = "2000", + int sampleRate = 2000, int buffer_block_size = 200, int buffer_block_count = 50) { + SamplingRate = sampleRate; + BufferBlockCount = buffer_block_count; + BufferBlockSize = buffer_block_size; var error = TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "OperationMode", operationMode); error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "ExtTrigger", externalTrigger); error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "ExtClk", externalClock); - error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "SampleRate", sampleRate); + error |= TrionApi.DeWeSetParamStruct($"BoardID{Id}/AcqProp", "SampleRate", sampleRate.ToString()); error |= TrionApi.DeWeSetParam_i32(Id, TrionCommand.BUFFER_BLOCK_SIZE, buffer_block_size); error |= TrionApi.DeWeSetParam_i32(Id, TrionCommand.BUFFER_BLOCK_COUNT, buffer_block_count); @@ -77,7 +83,7 @@ public void ActivateChannels(IEnumerable channelsToActivate) ScanSizeBytes = ScanDescriptorDecoder.ScanSizeBytes; - SetAcquisitionProperties(sampleRate: "2000", buffer_block_size: 200, buffer_block_count: 50); + SetAcquisitionProperties(sampleRate: 2000, buffer_block_size: 200, buffer_block_count: 50); UpdateBoard(); Utils.CheckErrorCode(error, $"Failed to activate channels for board {Id}"); } diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs index fae7232..1b54937 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/ChartRecorder.cs @@ -52,7 +52,7 @@ public ObservableCollection GetWindow(string channel) // Add samples to a specific channel public void AddSamples(string channel, IEnumerable samples) { - System.Diagnostics.Debug.WriteLine($"AddSamples called for channel: {channel}, sample count: {samples.Count()}"); + //System.Diagnostics.Debug.WriteLine($"AddSamples called for channel: {channel}, sample count: {samples.Count()}"); if (!_data.ContainsKey(channel)) { _data[channel] = []; diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs index 1a2ba1e..3db2520 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs @@ -12,15 +12,12 @@ public class Enclosure public void AddBoard(int boardId) { var error = TrionApi.DeWeSetParam_i32(boardId, TrionCommand.OPEN_BOARD, 0); - if (error != TrionError.NONE) - { - System.Diagnostics.Debug.WriteLine($"TRION_API: OpenBoard failed for board {boardId}"); - return; - } + Utils.CheckErrorCode(error, "Failed to open board"); var boardPropertiesXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "boardproperties").value; var boardPropertiesModel = new BoardPropertyModel(boardPropertiesXml); + var newBoard = new Board() { Id = boardId, @@ -32,6 +29,8 @@ public void AddBoard(int boardId) }; Boards.Add(newBoard); + error = TrionApi.DeWeSetParam_i32(boardId, TrionCommand.CLOSE_BOARD, 0); + Utils.CheckErrorCode(error, "Failed to close board"); } public void Init(int numberOfBoards) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 6089d62..75babfe 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -1,11 +1,12 @@ using LiveChartsCore; using LiveChartsCore.SkiaSharpView; using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Runtime.InteropServices; using System.Windows.Input; using Trion; using TRION_SDK_UI.Models; -using System.Runtime.InteropServices; -using System.Diagnostics; +using TrionApiUtils; public class MainViewModel : BaseViewModel, IDisposable { @@ -90,15 +91,15 @@ public MainViewModel() var numberOfBoards = TrionApi.Initialize(); if (numberOfBoards < 0) { - LogMessages.Add($"Number of simulated Boards found: {Math.Abs(numberOfBoards)}"); + Debug.WriteLine($"Number of simulated Boards found: {Math.Abs(numberOfBoards)}"); } else if (numberOfBoards > 0) { - LogMessages.Add($"Number of real Boards found: {numberOfBoards}"); + Debug.WriteLine($"Number of real Boards found: {numberOfBoards}"); } else { - LogMessages.Add("No Trion Boards found."); + Debug.WriteLine("No Trion Boards found."); } numberOfBoards = Math.Abs(numberOfBoards); @@ -120,8 +121,10 @@ public MainViewModel() StopAcquisitionCommand = new Command(StopAcquisition); LockScrollingCommand = new Command(LockScrolling); UpdateYAxes(); + } + private readonly AcquisitionManager _acquisitionManager; private readonly CancellationTokenSource? _cts; private readonly Task? _acquisitionTask; private List _acquisitionTasks = []; @@ -140,24 +143,31 @@ private void StartAcquisition() var selectedChannels = Channels.Where(c => c.IsSelected).ToList(); var selectedBoardIds = selectedChannels.Select(c => c.BoardID).Distinct(); var selectedBoards = MyEnc.Boards.Where(b => selectedBoardIds.Contains(b.Id)).ToList(); + TrionError error; // Reset boards foreach (var selected_board in selectedBoards) { selected_board.ResetBoard(); selected_board.SetAcquisitionProperties(); - TrionApi.DeWeSetParamStruct($"BoardID{selected_board.Id}/AIAll", "Used", "False"); + error = TrionApi.DeWeSetParamStruct($"BoardID{selected_board.Id}/AIAll", "Used", "False"); + Utils.CheckErrorCode(error, "Failed to reset board"); + Debug.WriteLine($"TEST: Board: {selected_board.Name} Reset"); } // enable selected channels foreach (var selected_channel in selectedChannels) { - TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Used", "True"); - TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Range", "10 V"); + error = TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Used", "True"); + Utils.CheckErrorCode(error, $"Failed to set channel used {selected_channel.Name}"); + error = TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Range", "10 V"); + Utils.CheckErrorCode(error, $"Failed to set channel range {selected_channel.Name}"); + Debug.WriteLine($"TEST: Channel: {selected_channel.Name} enabled"); } // update parameters foreach (var selected_board in selectedBoards) { selected_board.UpdateBoard(); + Debug.WriteLine($"TEST: Board: {selected_board.Name} Updated"); } @@ -172,7 +182,8 @@ private void StartAcquisition() foreach (var board in MyEnc.Boards) { - board.ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3").value; + (error, board.ScanDescriptorXml) = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3"); + Utils.CheckErrorCode(error, $"Failed to get scan descriptor {board.Id}"); board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); board.ScanSizeBytes = board.ScanDescriptorDecoder.ScanSizeBytes; //Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); @@ -190,7 +201,7 @@ private void StartAcquisition() foreach (var ch in Channels.Where(c => c.IsSelected)) { var window = Recorder.GetWindow(ch.Name); - System.Diagnostics.Debug.WriteLine($"Channel: {ch.Name}, Window HashCode: {window.GetHashCode()}, Count: {window.Count}"); + Debug.WriteLine($"TEST: Channel: {ch.Name}, Window HashCode: {window.GetHashCode()}, Count: {window.Count}"); var series = new LineSeries { @@ -243,28 +254,44 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) var scanSize = (int)board.ScanSizeBytes; var scanDescriptor = board.ScanDescriptorDecoder; var channelInfo = scanDescriptor.Channels.FirstOrDefault(c => c.Name == selectedChannel.Name); + var polling_interval = (int)(board.BufferBlockSize / (double)board.SamplingRate * 1000); + + TrionError error; if (channelInfo == null) return; var board_id = selectedChannel.BoardID; - var (adcDelayError, adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); - TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); + (error, var adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); + Utils.CheckErrorCode(error, $"Failed to get ADC Delay {board_id}"); + + error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); + Utils.CheckErrorCode(error, $"Failed start acquisition {board_id}"); + CircularBuffer buffer = new(board_id); - System.Diagnostics.Debug.WriteLine($"AcquireDataLoop started for channel: {selectedChannel.Name}"); + Debug.WriteLine($"AcquireDataLoop started for channel: {selectedChannel.Name}"); + Debug.WriteLine($"Sample Size {(int)channelInfo.SampleSize}, Sample Offset {(int)channelInfo.SampleOffset / 8}"); while (!token.IsCancellationRequested) { - var (available_samples_error, available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_WAIT_AVAIL_NO_SAMPLE); + (error, var available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_AVAIL_NO_SAMPLE); + Utils.CheckErrorCode(error, $"Failed to get available samples {board_id}, {available_samples}"); + if (available_samples <= 0) + { + Thread.Sleep(polling_interval); + } + available_samples -= adc_delay; if (available_samples <= 0) { Thread.Sleep(10); continue; } - var (read_pos_error, read_pos) = TrionApi.DeWeGetParam_i64(board_id, TrionCommand.BUFFER_0_ACT_SAMPLE_POS); + (error, var read_pos) = TrionApi.DeWeGetParam_i64(board_id, TrionCommand.BUFFER_0_ACT_SAMPLE_POS); + Utils.CheckErrorCode(error, $"Failed to get actual sample position {board_id}"); + read_pos += adc_delay * scanSize; - List tempValues = new List(available_samples); + List tempValues = new(available_samples); // loop over available samples for (int i = 0; i < available_samples; ++i) { @@ -277,8 +304,8 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) // extract the actual sample bits int sampleSize = (int)channelInfo.SampleSize; - int bitmask = (1 << sampleSize) - 1; - raw &= bitmask; + int bitmask = (1 << sampleSize) - 1; // = 0xFFFFFF + raw &= bitmask; // keeps only the lower 24 bits // general sign extension for N-bit signed value int signBit = 1 << (sampleSize - 1); @@ -312,6 +339,9 @@ private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) OnPropertyChanged(nameof(MaxScrollIndex)); }); } - TrionApi.DeWeSetParam_i32(board_id, TrionCommand.STOP_ACQUISITION, 0); + error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.STOP_ACQUISITION, 0); + Utils.CheckErrorCode(error, $"Failed stop acquisition {board_id}"); + error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.CLOSE_BOARD, 0); + Utils.CheckErrorCode(error, $"Failed close board {board_id}"); } } \ No newline at end of file diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml index 136f92b..2828f84 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml @@ -2,7 +2,6 @@ @@ -77,12 +76,12 @@ - + diff --git a/trion_api/CS/TrionApi/TrionApi.cs b/trion_api/CS/TrionApi/TrionApi.cs index 8b3583d..1467eb2 100644 --- a/trion_api/CS/TrionApi/TrionApi.cs +++ b/trion_api/CS/TrionApi/TrionApi.cs @@ -1,5 +1,6 @@ using System; using Trion; +using TrionApiUtils; public class TrionApi @@ -31,7 +32,7 @@ public static void CloseBoards() var error = TrionApi.DeWeSetParam_i32(0, Trion.TrionCommand.CLOSE_BOARD_ALL, 0); if (error != TrionError.NONE) { - System.Diagnostics.Debug.WriteLine($"TRION API CloseBoards failed: {Trion.API.DeWeErrorConstantToString(error)}"); + System.Diagnostics.Debug.WriteLine($"TRION API CloseBoards failed"); } } From 6d605b518950b1570a2ab48f1d3a853b339a1d36 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 11:44:17 +0200 Subject: [PATCH 010/203] wip --- app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs | 4 +- .../TRION-SDK-UI/Models/Enclosure.cs | 1 - .../Services/AcquisitionManager.cs | 184 ++++++++++++++++++ .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 166 ++-------------- trion_api/CS/TrionApi/TrionApi.cs | 2 +- 5 files changed, 205 insertions(+), 152 deletions(-) create mode 100644 app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs index c538f81..429b733 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Board.cs @@ -20,7 +20,7 @@ public class Board() { public int Id { get; set; } public string? Name { get; set; } - public bool IsActive { get; set; } + public bool IsOpen { get; set; } public BoardPropertyModel? BoardProperties { get; set; } public List Channels { get; set; } = []; public uint ScanSizeBytes { get; set; } @@ -29,12 +29,12 @@ public class Board() public int BufferBlockSize { get; set; } public int SamplingRate { get; set; } public int BufferBlockCount { get; set; } + public bool IsAcquiring { get; set; } public void SetBoardProperties() { Id = BoardProperties.GetBoardID(); Name = BoardProperties.GetBoardName(); - IsActive = true; } public void SetAcquisitionProperties(string operationMode = "Slave", diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs index 3db2520..147f973 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs @@ -22,7 +22,6 @@ public void AddBoard(int boardId) { Id = boardId, Name = boardPropertiesModel.GetBoardName(), - IsActive = true, BoardProperties = boardPropertiesModel, Channels = boardPropertiesModel.GetChannels(), ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "ScanDescriptor_V3").value diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs new file mode 100644 index 0000000..48782c8 --- /dev/null +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Trion; +using TRION_SDK_UI.Models; +using TrionApiUtils; + +public class AcquisitionManager : IDisposable +{ + private readonly Enclosure _enclosure; + private readonly List _acquisitionTasks = []; + private readonly List _ctsList = []; + public bool _isRunning = false; + + public AcquisitionManager(Enclosure enclosure) + { + _enclosure = enclosure; + } + + public void StartAcquisition(IEnumerable selectedChannels, Action> onSamplesReceived) + { + if (_isRunning) + StopAcquisition(); + + _acquisitionTasks.Clear(); + _ctsList.Clear(); + + var selectedBoardIds = selectedChannels.Select(c => c.BoardID).Distinct(); + var selectedBoards = _enclosure.Boards.Where(b => selectedBoardIds.Contains(b.Id)).ToList(); + + // Board and channel setup + foreach (var board in selectedBoards) + { + if (!board.IsOpen) + { + Utils.CheckErrorCode(TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.OPEN_BOARD, 0), "Failed to open board"); + board.IsOpen = true; + } + board.ResetBoard(); + board.SetAcquisitionProperties(); + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{board.Id}/AIAll", "Used", "False"), $"Failed to reset board {board.Id}"); + } + foreach (var channel in selectedChannels) + { + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Used", "True"), $"Failed to set channel used {channel.Name}"); + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Range", "10 V"), $"Failed to set channel range {channel.Name}"); + } + foreach (var board in selectedBoards) + { + board.UpdateBoard(); + } + + foreach (var board in selectedBoards) + { + (var error, board.ScanDescriptorXml) = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3"); + Utils.CheckErrorCode(error, $"Failed to get scan descriptor {board.Id}"); + board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); + board.ScanSizeBytes = board.ScanDescriptorDecoder.ScanSizeBytes; + //Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); + } + + // Start acquisition tasks + foreach (var channel in selectedChannels) + { + var cts = new CancellationTokenSource(); + _ctsList.Add(cts); + var task = Task.Run(() => AcquireDataLoop(channel, onSamplesReceived, cts.Token), cts.Token); + _acquisitionTasks.Add(task); + } + + _isRunning = true; + } + + public void StopAcquisition() + { + foreach (var cts in _ctsList) + { + cts.Cancel(); + } + Task.WaitAll(_acquisitionTasks.ToArray(), 1000); + _acquisitionTasks.Clear(); + _ctsList.Clear(); + TrionApi.DeWeSetParam_i32(0, TrionCommand.CLOSE_BOARD_ALL, 0); + _isRunning = false; + } + + private void AcquireDataLoop(Channel selectedChannel, Action> onSamplesReceived, CancellationToken token) + { + var board = _enclosure.Boards.First(b => b.Id == selectedChannel.BoardID); + var scanSize = (int)board.ScanSizeBytes; + var scanDescriptor = board.ScanDescriptorDecoder; + var channelInfo = scanDescriptor.Channels.FirstOrDefault(c => c.Name == selectedChannel.Name); + var polling_interval = (int)(board.BufferBlockSize / (double)board.SamplingRate * 1000); + + TrionError error; + if (channelInfo == null) return; + + var board_id = selectedChannel.BoardID; + (error, var adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); + Utils.CheckErrorCode(error, $"Failed to get ADC Delay {board_id}"); + + if (board.IsAcquiring) + { + error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); + Utils.CheckErrorCode(error, $"Failed start acquisition {board_id}"); + } + + CircularBuffer buffer = new(board_id); + + Debug.WriteLine($"AcquireDataLoop started for channel: {selectedChannel.Name}"); + Debug.WriteLine($"Sample Size {(int)channelInfo.SampleSize}, Sample Offset {(int)channelInfo.SampleOffset / 8}"); + + while (!token.IsCancellationRequested) + { + (error, var available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_AVAIL_NO_SAMPLE); + Utils.CheckErrorCode(error, $"Failed to get available samples {board_id}, {available_samples}"); + if (available_samples <= 0) + { + Thread.Sleep(polling_interval); + } + + available_samples -= adc_delay; + if (available_samples <= 0) + { + Thread.Sleep(10); + continue; + } + (error, var read_pos) = TrionApi.DeWeGetParam_i64(board_id, TrionCommand.BUFFER_0_ACT_SAMPLE_POS); + Utils.CheckErrorCode(error, $"Failed to get actual sample position {board_id}"); + + read_pos += adc_delay * scanSize; + + List tempValues = new(available_samples); + // loop over available samples + for (int i = 0; i < available_samples; ++i) + { + if (read_pos >= buffer.EndPosition) + { + read_pos -= buffer.Size; + } + // calculate the position of the sample in memory + var offset_bytes = (int)channelInfo.SampleOffset / 8; + var samplePos = read_pos + offset_bytes; + + // read the raw data + int raw = Marshal.ReadInt32((IntPtr)samplePos); + + // extract the actual sample bits + int sampleSize = (int)channelInfo.SampleSize; + int bitmask = (1 << sampleSize) - 1; // = 0xFFFFFF + raw &= bitmask; // keeps only the lower 24 bits + + // general sign extension for N-bit signed value + int signBit = 1 << (sampleSize - 1); + if ((raw & signBit) != 0) + raw |= ~bitmask; + + // scale to engineering units (i guess the range needs to be adjustable) + double value = (double)raw / (double)(signBit - 1) * 10.0; + + // store the result + tempValues.Add(value); + + // move to the next sample in the buffer + read_pos += scanSize; + } + TrionApi.DeWeSetParam_i32(board_id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); + + Debug.WriteLine("TEST"); + onSamplesReceived(selectedChannel.Name, tempValues); + } + StopAcquisition(); + } + + public void Dispose() + { + StopAcquisition(); + Utils.CheckErrorCode(TrionApi.DeWeSetParam_i32(0, TrionCommand.CLOSE_BOARD_ALL, 0), "Failed to close Boards"); + } +} \ No newline at end of file diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 75babfe..9023f73 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -116,6 +116,7 @@ public MainViewModel() } } + _acquisitionManager = new AcquisitionManager(MyEnc); OnPropertyChanged(nameof(Channels)); StartAcquisitionCommand = new Command(StartAcquisition); StopAcquisitionCommand = new Command(StopAcquisition); @@ -135,41 +136,9 @@ private void StartAcquisition() { LogMessages.Add("Starting acquisition..."); - StopAcquisition(); - - _acquisitionTasks.Clear(); - _ctsList.Clear(); - var selectedChannels = Channels.Where(c => c.IsSelected).ToList(); - var selectedBoardIds = selectedChannels.Select(c => c.BoardID).Distinct(); - var selectedBoards = MyEnc.Boards.Where(b => selectedBoardIds.Contains(b.Id)).ToList(); - TrionError error; - - // Reset boards - foreach (var selected_board in selectedBoards) - { - selected_board.ResetBoard(); - selected_board.SetAcquisitionProperties(); - error = TrionApi.DeWeSetParamStruct($"BoardID{selected_board.Id}/AIAll", "Used", "False"); - Utils.CheckErrorCode(error, "Failed to reset board"); - Debug.WriteLine($"TEST: Board: {selected_board.Name} Reset"); - } - // enable selected channels - foreach (var selected_channel in selectedChannels) - { - error = TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Used", "True"); - Utils.CheckErrorCode(error, $"Failed to set channel used {selected_channel.Name}"); - error = TrionApi.DeWeSetParamStruct($"BoardID{selected_channel.BoardID}/{selected_channel.Name}", "Range", "10 V"); - Utils.CheckErrorCode(error, $"Failed to set channel range {selected_channel.Name}"); - Debug.WriteLine($"TEST: Channel: {selected_channel.Name} enabled"); - } - // update parameters - foreach (var selected_board in selectedBoards) - { - selected_board.UpdateBoard(); - Debug.WriteLine($"TEST: Board: {selected_board.Name} Updated"); - } + _acquisitionManager.StartAcquisition(selectedChannels, OnSamplesReceived); MeasurementSeries = selectedChannels.Select(ch => new LineSeries { @@ -180,23 +149,6 @@ private void StartAcquisition() }).ToArray(); OnPropertyChanged(nameof(MeasurementSeries)); - foreach (var board in MyEnc.Boards) - { - (error, board.ScanDescriptorXml) = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3"); - Utils.CheckErrorCode(error, $"Failed to get scan descriptor {board.Id}"); - board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); - board.ScanSizeBytes = board.ScanDescriptorDecoder.ScanSizeBytes; - //Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); - } - - foreach (var channel in selectedChannels) - { - //Debug.WriteLine($"Channel selected: {channel.Name}"); - var cts = new CancellationTokenSource(); - _ctsList.Add(cts); - var task = Task.Run(() => AcquireDataLoop(channel, cts.Token), cts.Token); - _acquisitionTasks.Add(task); - } ChannelSeries.Clear(); foreach (var ch in Channels.Where(c => c.IsSelected)) { @@ -217,13 +169,12 @@ private void StartAcquisition() private void StopAcquisition() { LogMessages.Add("Stopping acquisition..."); - foreach (var cts in _ctsList) - { - cts.Cancel(); - } - Task.WaitAll(_acquisitionTasks.ToArray(), 1000); - _acquisitionTasks.Clear(); - _ctsList.Clear(); + _acquisitionManager.StopAcquisition(); + MeasurementSeries = Array.Empty(); + ChannelSeries.Clear(); + OnPropertyChanged(nameof(MeasurementSeries)); + OnPropertyChanged(nameof(ChannelSeries)); + } private void LockScrolling() { @@ -248,100 +199,19 @@ private void UpdateYAxes() ]; OnPropertyChanged(nameof(YAxes)); } - private void AcquireDataLoop(Channel selectedChannel, CancellationToken token) + private void OnSamplesReceived(string channelName, IEnumerable samples) { - var board = MyEnc.Boards.First(b => b.Id == selectedChannel.BoardID); - var scanSize = (int)board.ScanSizeBytes; - var scanDescriptor = board.ScanDescriptorDecoder; - var channelInfo = scanDescriptor.Channels.FirstOrDefault(c => c.Name == selectedChannel.Name); - var polling_interval = (int)(board.BufferBlockSize / (double)board.SamplingRate * 1000); - - TrionError error; - if (channelInfo == null) return; - - var board_id = selectedChannel.BoardID; - (error, var adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); - Utils.CheckErrorCode(error, $"Failed to get ADC Delay {board_id}"); - - error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); - Utils.CheckErrorCode(error, $"Failed start acquisition {board_id}"); - - CircularBuffer buffer = new(board_id); - - Debug.WriteLine($"AcquireDataLoop started for channel: {selectedChannel.Name}"); - Debug.WriteLine($"Sample Size {(int)channelInfo.SampleSize}, Sample Offset {(int)channelInfo.SampleOffset / 8}"); - - while (!token.IsCancellationRequested) + MainThread.BeginInvokeOnMainThread(() => { - (error, var available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_AVAIL_NO_SAMPLE); - Utils.CheckErrorCode(error, $"Failed to get available samples {board_id}, {available_samples}"); - if (available_samples <= 0) - { - Thread.Sleep(polling_interval); - } - - available_samples -= adc_delay; - if (available_samples <= 0) - { - Thread.Sleep(10); - continue; - } - (error, var read_pos) = TrionApi.DeWeGetParam_i64(board_id, TrionCommand.BUFFER_0_ACT_SAMPLE_POS); - Utils.CheckErrorCode(error, $"Failed to get actual sample position {board_id}"); - - read_pos += adc_delay * scanSize; - - List tempValues = new(available_samples); - // loop over available samples - for (int i = 0; i < available_samples; ++i) + Recorder.AddSamples(channelName, samples); + if (_isScrollingLocked) { - // calculate the position of the sample in memory - var offset_bytes = (int)channelInfo.SampleOffset / 8; - var samplePos = read_pos + offset_bytes; - - // read the raw data - int raw = Marshal.ReadInt32((IntPtr)samplePos); - - // extract the actual sample bits - int sampleSize = (int)channelInfo.SampleSize; - int bitmask = (1 << sampleSize) - 1; // = 0xFFFFFF - raw &= bitmask; // keeps only the lower 24 bits - - // general sign extension for N-bit signed value - int signBit = 1 << (sampleSize - 1); - if ((raw & signBit) != 0) - raw |= ~bitmask; - - // scale to engineering units (i guess the range needs to be adjustable) - double value = (double)raw / (double)(signBit - 1) * 10.0; - - // store the result - tempValues.Add(value); - - // move to the next sample in the buffer - read_pos += scanSize; - if (read_pos >= buffer.EndPosition) - { - read_pos -= buffer.Size; - } + Recorder.AutoScroll(); + OnPropertyChanged(nameof(ScrollIndex)); } - TrionApi.DeWeSetParam_i32(board_id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); - - MainThread.BeginInvokeOnMainThread(() => - { - Recorder.AddSamples(selectedChannel.Name, tempValues); - - if (_isScrollingLocked) - { - Recorder.AutoScroll(); - OnPropertyChanged(nameof(ScrollIndex)); - } - OnPropertyChanged(nameof(MaxScrollIndex)); - }); - } - error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.STOP_ACQUISITION, 0); - Utils.CheckErrorCode(error, $"Failed stop acquisition {board_id}"); - error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.CLOSE_BOARD, 0); - Utils.CheckErrorCode(error, $"Failed close board {board_id}"); + OnPropertyChanged(nameof(MaxScrollIndex)); + OnPropertyChanged(nameof(MeasurementSeries)); + OnPropertyChanged(nameof(ChannelSeries)); + }); } } \ No newline at end of file diff --git a/trion_api/CS/TrionApi/TrionApi.cs b/trion_api/CS/TrionApi/TrionApi.cs index 1467eb2..dc3433d 100644 --- a/trion_api/CS/TrionApi/TrionApi.cs +++ b/trion_api/CS/TrionApi/TrionApi.cs @@ -41,7 +41,7 @@ public static void Uninitialize() TrionError nErrorCode = Trion.API.DeWeDriverDeInit(); if (nErrorCode != TrionError.NONE) { - System.Diagnostics.Debug.WriteLine($"TRION API Uninit failed: {Trion.API.DeWeErrorConstantToString(nErrorCode)}"); + System.Diagnostics.Debug.WriteLine($"TRION API Uninit failed:"); } else { From d22862ff523250bfb3641485beee4766505d3580 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 11:48:40 +0200 Subject: [PATCH 011/203] ui: multiple channels kinda work --- .../Services/AcquisitionManager.cs | 105 +++++++++--------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs index 48782c8..c3d880e 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -64,11 +64,13 @@ public void StartAcquisition(IEnumerable selectedChannels, Action c.BoardID); + foreach (var boardGroup in channelsByBoard) { + var board = _enclosure.Boards.First(b => b.Id == boardGroup.Key); var cts = new CancellationTokenSource(); _ctsList.Add(cts); - var task = Task.Run(() => AcquireDataLoop(channel, onSamplesReceived, cts.Token), cts.Token); + var task = Task.Run(() => AcquireDataLoop(board, boardGroup.ToList(), onSamplesReceived, cts.Token), cts.Token); _acquisitionTasks.Add(task); } @@ -88,39 +90,29 @@ public void StopAcquisition() _isRunning = false; } - private void AcquireDataLoop(Channel selectedChannel, Action> onSamplesReceived, CancellationToken token) + private void AcquireDataLoop(Board board, List selectedChannels, Action> onSamplesReceived, CancellationToken token) { - var board = _enclosure.Boards.First(b => b.Id == selectedChannel.BoardID); var scanSize = (int)board.ScanSizeBytes; var scanDescriptor = board.ScanDescriptorDecoder; - var channelInfo = scanDescriptor.Channels.FirstOrDefault(c => c.Name == selectedChannel.Name); var polling_interval = (int)(board.BufferBlockSize / (double)board.SamplingRate * 1000); TrionError error; - if (channelInfo == null) return; - - var board_id = selectedChannel.BoardID; - (error, var adc_delay) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BOARD_ADC_DELAY); - Utils.CheckErrorCode(error, $"Failed to get ADC Delay {board_id}"); - - if (board.IsAcquiring) - { - error = TrionApi.DeWeSetParam_i32(board_id, TrionCommand.START_ACQUISITION, 0); - Utils.CheckErrorCode(error, $"Failed start acquisition {board_id}"); - } + (error, var adc_delay) = TrionApi.DeWeGetParam_i32(board.Id, TrionCommand.BOARD_ADC_DELAY); + Utils.CheckErrorCode(error, $"Failed to get ADC Delay {board.Id}"); - CircularBuffer buffer = new(board_id); + error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.START_ACQUISITION, 0); + Utils.CheckErrorCode(error, $"Failed start acquisition {board.Id}"); - Debug.WriteLine($"AcquireDataLoop started for channel: {selectedChannel.Name}"); - Debug.WriteLine($"Sample Size {(int)channelInfo.SampleSize}, Sample Offset {(int)channelInfo.SampleOffset / 8}"); + CircularBuffer buffer = new(board.Id); while (!token.IsCancellationRequested) { - (error, var available_samples) = TrionApi.DeWeGetParam_i32(board_id, TrionCommand.BUFFER_0_AVAIL_NO_SAMPLE); - Utils.CheckErrorCode(error, $"Failed to get available samples {board_id}, {available_samples}"); + (error, var available_samples) = TrionApi.DeWeGetParam_i32(board.Id, TrionCommand.BUFFER_0_AVAIL_NO_SAMPLE); + Utils.CheckErrorCode(error, $"Failed to get available samples {board.Id}, {available_samples}"); if (available_samples <= 0) { Thread.Sleep(polling_interval); + continue; } available_samples -= adc_delay; @@ -129,51 +121,54 @@ private void AcquireDataLoop(Channel selectedChannel, Action tempValues = new(available_samples); - // loop over available samples + // Prepare a dictionary to collect samples for each channel + var channelSamples = new Dictionary>(); + foreach (var channel in selectedChannels) + channelSamples[channel.Name] = new List(available_samples); + for (int i = 0; i < available_samples; ++i) { if (read_pos >= buffer.EndPosition) - { read_pos -= buffer.Size; - } - // calculate the position of the sample in memory - var offset_bytes = (int)channelInfo.SampleOffset / 8; - var samplePos = read_pos + offset_bytes; - - // read the raw data - int raw = Marshal.ReadInt32((IntPtr)samplePos); - // extract the actual sample bits - int sampleSize = (int)channelInfo.SampleSize; - int bitmask = (1 << sampleSize) - 1; // = 0xFFFFFF - raw &= bitmask; // keeps only the lower 24 bits - - // general sign extension for N-bit signed value - int signBit = 1 << (sampleSize - 1); - if ((raw & signBit) != 0) - raw |= ~bitmask; - - // scale to engineering units (i guess the range needs to be adjustable) - double value = (double)raw / (double)(signBit - 1) * 10.0; - - // store the result - tempValues.Add(value); - - // move to the next sample in the buffer - read_pos += scanSize; + foreach (var channel in selectedChannels) + { + var channelInfo = scanDescriptor.Channels.FirstOrDefault(c => c.Name == channel.Name); + if (channelInfo == null) continue; + + var offset_bytes = (int)channelInfo.SampleOffset / 8; + var samplePos = read_pos + offset_bytes; + int raw = Marshal.ReadInt32((IntPtr)samplePos); + + int sampleSize = (int)channelInfo.SampleSize; + int bitmask = (1 << sampleSize) - 1; + raw &= bitmask; + int signBit = 1 << (sampleSize - 1); + if ((raw & signBit) != 0) + raw |= ~bitmask; + double value = (double)raw / (double)(signBit - 1) * 10.0; + + channelSamples[channel.Name].Add(value); + } + read_pos += scanSize; } - TrionApi.DeWeSetParam_i32(board_id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); - Debug.WriteLine("TEST"); - onSamplesReceived(selectedChannel.Name, tempValues); + TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); + + // Call the callback for each channel + foreach (var kvp in channelSamples) + onSamplesReceived(kvp.Key, kvp.Value); } - StopAcquisition(); + + error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.STOP_ACQUISITION, 0); + Utils.CheckErrorCode(error, $"Failed stop acquisition {board.Id}"); + error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.CLOSE_BOARD, 0); + Utils.CheckErrorCode(error, $"Failed close board {board.Id}"); } public void Dispose() From 8e1332fe8f1f8d2f544004d0a5c9e137e4dd9432 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 12:14:41 +0200 Subject: [PATCH 012/203] ui: chagned the StartAcquisition logic a bit --- .../Services/AcquisitionManager.cs | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs index c3d880e..2fb274e 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -36,31 +36,25 @@ public void StartAcquisition(IEnumerable selectedChannels, Action c.BoardID == board.Id).ToList(); + foreach (var channel in selectedChannelsForBoard) + { + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Used", "True"), $"Failed to set channel used {channel.Name}"); + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Range", "10 V"), $"Failed to set channel range {channel.Name}"); + } board.UpdateBoard(); - } - foreach (var board in selectedBoards) - { (var error, board.ScanDescriptorXml) = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3"); Utils.CheckErrorCode(error, $"Failed to get scan descriptor {board.Id}"); board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); board.ScanSizeBytes = board.ScanDescriptorDecoder.ScanSizeBytes; - //Debug.WriteLine($"TEST XML: {board.ScanDescriptorXml}"); } // Start acquisition tasks From 270a5dce45a1eb2c04b7f8ac4fca30e947140344 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 12:16:09 +0200 Subject: [PATCH 013/203] using primary constructor --- .../TRION-SDK-UI/Services/AcquisitionManager.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs index 2fb274e..85777f0 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -9,18 +9,13 @@ using TRION_SDK_UI.Models; using TrionApiUtils; -public class AcquisitionManager : IDisposable +public class AcquisitionManager(Enclosure enclosure) : IDisposable { - private readonly Enclosure _enclosure; + private readonly Enclosure _enclosure = enclosure; private readonly List _acquisitionTasks = []; private readonly List _ctsList = []; public bool _isRunning = false; - public AcquisitionManager(Enclosure enclosure) - { - _enclosure = enclosure; - } - public void StartAcquisition(IEnumerable selectedChannels, Action> onSamplesReceived) { if (_isRunning) @@ -64,7 +59,7 @@ public void StartAcquisition(IEnumerable selectedChannels, Action b.Id == boardGroup.Key); var cts = new CancellationTokenSource(); _ctsList.Add(cts); - var task = Task.Run(() => AcquireDataLoop(board, boardGroup.ToList(), onSamplesReceived, cts.Token), cts.Token); + var task = Task.Run(() => AcquireDataLoop(board, [.. boardGroup], onSamplesReceived, cts.Token), cts.Token); _acquisitionTasks.Add(task); } From 9895ecbc731ed85190058a02f0add15d8eb049ad Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 12:41:48 +0200 Subject: [PATCH 014/203] light clean up --- .../Services/AcquisitionManager.cs | 24 +++++++++---------- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 12 +++------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs index 85777f0..b0c9fab 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using Trion; using TRION_SDK_UI.Models; using TrionApiUtils; @@ -68,6 +62,14 @@ public void StartAcquisition(IEnumerable selectedChannels, Action b.IsOpen)) + { + var error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.STOP_ACQUISITION, 0); + Utils.CheckErrorCode(error, $"Failed stop acquisition {board.Id}"); + error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.CLOSE_BOARD, 0); + Utils.CheckErrorCode(error, $"Failed close board {board.Id}"); + board.IsOpen = false; + } foreach (var cts in _ctsList) { cts.Cancel(); @@ -75,7 +77,6 @@ public void StopAcquisition() Task.WaitAll(_acquisitionTasks.ToArray(), 1000); _acquisitionTasks.Clear(); _ctsList.Clear(); - TrionApi.DeWeSetParam_i32(0, TrionCommand.CLOSE_BOARD_ALL, 0); _isRunning = false; } @@ -147,17 +148,14 @@ private void AcquireDataLoop(Board board, List selectedChannels, Action read_pos += scanSize; } - TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); + Utils.CheckErrorCode(TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples), "Failed to free buffer"); + // Call the callback for each channel foreach (var kvp in channelSamples) onSamplesReceived(kvp.Key, kvp.Value); } - - error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.STOP_ACQUISITION, 0); - Utils.CheckErrorCode(error, $"Failed stop acquisition {board.Id}"); - error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.CLOSE_BOARD, 0); - Utils.CheckErrorCode(error, $"Failed close board {board.Id}"); + StopAcquisition(); } public void Dispose() diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 9023f73..9989cb0 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -2,11 +2,9 @@ using LiveChartsCore.SkiaSharpView; using System.Collections.ObjectModel; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Windows.Input; using Trion; using TRION_SDK_UI.Models; -using TrionApiUtils; public class MainViewModel : BaseViewModel, IDisposable { @@ -126,10 +124,6 @@ public MainViewModel() } private readonly AcquisitionManager _acquisitionManager; - private readonly CancellationTokenSource? _cts; - private readonly Task? _acquisitionTask; - private List _acquisitionTasks = []; - private readonly List _ctsList = []; private bool _isScrollingLocked = true; private double _yAxisMin = -10; private void StartAcquisition() @@ -140,13 +134,13 @@ private void StartAcquisition() _acquisitionManager.StartAcquisition(selectedChannels, OnSamplesReceived); - MeasurementSeries = selectedChannels.Select(ch => new LineSeries + MeasurementSeries = [.. selectedChannels.Select(ch => new LineSeries { Values = Recorder.GetWindow(ch.Name), Name = ch.Name, AnimationsSpeed = TimeSpan.Zero, GeometrySize = 0 - }).ToArray(); + })]; OnPropertyChanged(nameof(MeasurementSeries)); ChannelSeries.Clear(); @@ -170,7 +164,7 @@ private void StopAcquisition() { LogMessages.Add("Stopping acquisition..."); _acquisitionManager.StopAcquisition(); - MeasurementSeries = Array.Empty(); + MeasurementSeries = []; ChannelSeries.Clear(); OnPropertyChanged(nameof(MeasurementSeries)); OnPropertyChanged(nameof(ChannelSeries)); From aaec0ad553a25d33275253aec6fd618af71007e6 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 14:01:55 +0200 Subject: [PATCH 015/203] again: multiple channels kinda work --- .../TRION-SDK-UI/Models/Enclosure.cs | 1 + .../Services/AcquisitionManager.cs | 50 ++++++++++++------- trion_api/CS/TrionApi/utils.cs | 6 ++- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs index 147f973..8859ef6 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Models/Enclosure.cs @@ -24,6 +24,7 @@ public void AddBoard(int boardId) Name = boardPropertiesModel.GetBoardName(), BoardProperties = boardPropertiesModel, Channels = boardPropertiesModel.GetChannels(), + IsOpen = false, ScanDescriptorXml = TrionApi.DeWeGetParamStruct_String($"BoardID{boardId}", "ScanDescriptor_V3").value }; diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs index b0c9fab..def1b9d 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Runtime.InteropServices; using Trion; using TRION_SDK_UI.Models; @@ -12,6 +13,7 @@ public class AcquisitionManager(Enclosure enclosure) : IDisposable public void StartAcquisition(IEnumerable selectedChannels, Action> onSamplesReceived) { + Debug.WriteLine($"TEST: StartAcquisition called with channels: {string.Join(", ", selectedChannels.Select(c => c.Name))}"); if (_isRunning) StopAcquisition(); @@ -32,14 +34,19 @@ public void StartAcquisition(IEnumerable selectedChannels, Action c.BoardID == board.Id).ToList(); - foreach (var channel in selectedChannelsForBoard) - { - Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Used", "True"), $"Failed to set channel used {channel.Name}"); - Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Range", "10 V"), $"Failed to set channel range {channel.Name}"); - } + } + foreach (var channel in selectedChannels) + { + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Used", "True"), $"Failed to set channel used {channel.Name}"); + Utils.CheckErrorCode(TrionApi.DeWeSetParamStruct($"BoardID{channel.BoardID}/{channel.Name}", "Range", "10 V"), $"Failed to set channel range {channel.Name}"); + } + foreach (var board in selectedBoards) + { board.UpdateBoard(); + } + foreach (var board in selectedBoards) + { (var error, board.ScanDescriptorXml) = TrionApi.DeWeGetParamStruct_String($"BoardID{board.Id}", "ScanDescriptor_V3"); Utils.CheckErrorCode(error, $"Failed to get scan descriptor {board.Id}"); board.ScanDescriptorDecoder = new ScanDescriptorDecoder(board.ScanDescriptorXml); @@ -53,7 +60,7 @@ public void StartAcquisition(IEnumerable selectedChannels, Action b.Id == boardGroup.Key); var cts = new CancellationTokenSource(); _ctsList.Add(cts); - var task = Task.Run(() => AcquireDataLoop(board, [.. boardGroup], onSamplesReceived, cts.Token), cts.Token); + var task = Task.Run(() => AcquireDataLoop(board, boardGroup.ToList(), onSamplesReceived, cts.Token), cts.Token); _acquisitionTasks.Add(task); } @@ -62,6 +69,14 @@ public void StartAcquisition(IEnumerable selectedChannels, Action b.IsOpen)) { var error = TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.STOP_ACQUISITION, 0); @@ -70,18 +85,12 @@ public void StopAcquisition() Utils.CheckErrorCode(error, $"Failed close board {board.Id}"); board.IsOpen = false; } - foreach (var cts in _ctsList) - { - cts.Cancel(); - } - Task.WaitAll(_acquisitionTasks.ToArray(), 1000); - _acquisitionTasks.Clear(); - _ctsList.Clear(); _isRunning = false; } private void AcquireDataLoop(Board board, List selectedChannels, Action> onSamplesReceived, CancellationToken token) { + Debug.WriteLine($"TEST: AcquireDataLoop started for Board ID: {board.Id} with channels: {string.Join(", ", selectedChannels.Select(c => c.Name))}"); var scanSize = (int)board.ScanSizeBytes; var scanDescriptor = board.ScanDescriptorDecoder; var polling_interval = (int)(board.BufferBlockSize / (double)board.SamplingRate * 1000); @@ -148,19 +157,24 @@ private void AcquireDataLoop(Board board, List selectedChannels, Action read_pos += scanSize; } - Utils.CheckErrorCode(TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples), "Failed to free buffer"); - + TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.BUFFER_0_FREE_NO_SAMPLE, available_samples); // Call the callback for each channel foreach (var kvp in channelSamples) onSamplesReceived(kvp.Key, kvp.Value); } - StopAcquisition(); } public void Dispose() { StopAcquisition(); - Utils.CheckErrorCode(TrionApi.DeWeSetParam_i32(0, TrionCommand.CLOSE_BOARD_ALL, 0), "Failed to close Boards"); + foreach (var board in _enclosure.Boards) + { + if (board.IsOpen) + { + Utils.CheckErrorCode(TrionApi.DeWeSetParam_i32(board.Id, TrionCommand.CLOSE_BOARD, 0), $"Failed to close board {board.Id}"); + board.IsOpen = false; + } + } } } \ No newline at end of file diff --git a/trion_api/CS/TrionApi/utils.cs b/trion_api/CS/TrionApi/utils.cs index 3050825..35df8d8 100644 --- a/trion_api/CS/TrionApi/utils.cs +++ b/trion_api/CS/TrionApi/utils.cs @@ -19,12 +19,16 @@ public static void CheckErrorCode(Trion.TrionError error_code, String user_messa } if ((int)error_code == 0) { + //Console.ForegroundColor = ConsoleColor.Green; + //System.Diagnostics.Debug.WriteLine($"TRION API Success: {user_message} {error_code}"); + //Console.ResetColor(); return; } if ((int)error_code > 0) { Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"TRION API Error: {user_message} {error_code}"); + System.Diagnostics.Debug.WriteLine($"TRION API Error: {user_message} {error_code}"); + Environment.Exit((int)error_code); Console.ResetColor(); TrionApi.CloseBoards(); TrionApi.Uninitialize(); From f9461a976b3078ea8044dc73196af10835f29241 Mon Sep 17 00:00:00 2001 From: Bernhard Pregetter Date: Wed, 27 Aug 2025 14:47:24 +0200 Subject: [PATCH 016/203] ui: only first time selecting channels do all get shown in ui --- .../TRION-SDK-UI/Services/AcquisitionManager.cs | 8 ++++++-- .../TRION-SDK-UI/ViewModels/MainViewModel.cs | 1 + app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml | 14 +------------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs index def1b9d..8175b6b 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Services/AcquisitionManager.cs @@ -39,6 +39,7 @@ public void StartAcquisition(IEnumerable selectedChannels, Action selectedChannels, Action b.Id == boardGroup.Key); var cts = new CancellationTokenSource(); _ctsList.Add(cts); - var task = Task.Run(() => AcquireDataLoop(board, boardGroup.ToList(), onSamplesReceived, cts.Token), cts.Token); + var task = Task.Run(() => AcquireDataLoop(board, [.. boardGroup], onSamplesReceived, cts.Token), cts.Token); _acquisitionTasks.Add(task); } @@ -88,7 +89,7 @@ public void StopAcquisition() _isRunning = false; } - private void AcquireDataLoop(Board board, List selectedChannels, Action> onSamplesReceived, CancellationToken token) + private static void AcquireDataLoop(Board board, List selectedChannels, Action> onSamplesReceived, CancellationToken token) { Debug.WriteLine($"TEST: AcquireDataLoop started for Board ID: {board.Id} with channels: {string.Join(", ", selectedChannels.Select(c => c.Name))}"); var scanSize = (int)board.ScanSizeBytes; @@ -162,11 +163,14 @@ private void AcquireDataLoop(Board board, List selectedChannels, Action // Call the callback for each channel foreach (var kvp in channelSamples) onSamplesReceived(kvp.Key, kvp.Value); + + //Debug.WriteLine($"Received {available_samples} samples for {string.Join(", ", selectedChannels.Select(c => c.Name))} at {DateTime.Now}"); } } public void Dispose() { + GC.SuppressFinalize(_ctsList); StopAcquisition(); foreach (var board in _enclosure.Boards) { diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs index 9989cb0..4d8a237 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs +++ b/app/TRION-SDK-UI/TRION-SDK-UI/ViewModels/MainViewModel.cs @@ -197,6 +197,7 @@ private void OnSamplesReceived(string channelName, IEnumerable samples) { MainThread.BeginInvokeOnMainThread(() => { + //Debug.WriteLine($"got sample {channelName} {samples.Count()}"); Recorder.AddSamples(channelName, samples); if (_isScrollingLocked) { diff --git a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml index 2828f84..5cb65f8 100644 --- a/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml +++ b/app/TRION-SDK-UI/TRION-SDK-UI/Views/MainPage.xaml @@ -25,19 +25,7 @@ Style="{StaticResource SubHeadline}" SemanticProperties.HeadingLevel="Level2" HorizontalOptions="Start" /> - - - - - +