├── codecov.yml ├── .github ├── FUNDING.yml └── workflows │ ├── Version-Increment.yml │ ├── codacy-analysis.yml │ ├── codeql-analysis.yml │ └── dotnet-core-desktop.yml ├── hdf5Wrapper.ico ├── hdf5Wrapper.png ├── Assets ├── HDF_logo.svg ├── HDFlogo128.png ├── hdf5Wrapper.jpg ├── hdf5Wrapper.png ├── hdf5Wrapper.xcf ├── hdf5FlatStructure.jpg └── nuget.svg ├── misc └── HDF.Pinvoke.snk ├── HDF5-CSharp ├── hdf5Wrapper.ico ├── Hdf5DotNetTools.snk ├── Knf.Utils.Hdf5.snk ├── DataTypes │ ├── Hdf5Exception.cs │ ├── Enums.cs │ ├── FileClosedArgs.cs │ ├── Hdf5Patient.cs │ ├── Hdf5Events.cs │ ├── Hdf5Channel.cs │ ├── Hdf5Channels.cs │ ├── Hdf5Recording.cs │ ├── Hdf5Event.cs │ ├── Attributes.cs │ └── DataTypes.cs ├── Interfaces │ ├── IHdf5AcquisitionFile.cs │ └── IHdf5ReaderWriter.cs ├── Hdf5Errors.cs ├── Hdf5AttributeRW.cs ├── Hdf5AcquisitionFile.cs ├── Hdf5Conversions.cs ├── Hdf5Settings.cs ├── Hdf5Groups.cs ├── DataProducerConsumer.cs ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── HDF5-CSharp.csproj └── Hdf5AcquisitionWriter.cs ├── HDF5-CSharp.UnitTests ├── testFile.H5 ├── FileStructure.h5 ├── files │ └── testCompounds_WData2_WData3.H5 ├── FilesUnitTests.cs ├── HDF5-CSharp.UnitTests.csproj ├── H5ETest.cs ├── Hdf5GroupTests.cs ├── Hdf5ObjectTests.cs ├── Hdf5StringsTests.cs └── TestUtilities.cs ├── HDF5-CSharp.Viewer ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Form1.cs ├── Program.cs ├── HDF5FileLoader.cs ├── Form1.Designer.cs ├── HDF5-CSharp.Viewer.csproj ├── HDF5FileLoader.Designer.cs ├── Form1.resx └── HDF5FileLoader.resx ├── HDF5-CSharp.Example ├── DataTypes │ ├── Enums.cs │ ├── Constants.cs │ ├── InjectionGroup.cs │ ├── ElectrodeAmpCalcConfig.cs │ ├── AcquisitionInformation.cs │ ├── ProcedureInfo.cs │ ├── UserEventRecord.cs │ ├── CalibrationsSystemInformation.cs │ ├── RPositionEvent.cs │ ├── Hdf5Events.cs │ ├── ECGFrame.cs │ ├── BlockingCollectionQueue.cs │ ├── CalibrationGroup.cs │ ├── TagsGroup.cs │ ├── ElectrodeFrame.cs │ ├── Hdf5BaseFile.cs │ ├── UserEventsGroup.cs │ ├── AssemblyInformationRecord.cs │ ├── ProcedureInformation.cs │ ├── EventGroup.cs │ ├── Patient.cs │ ├── SystemEventGroup.cs │ ├── ECGData.cs │ ├── systemEvent.cs │ ├── RPositionGroup.cs │ ├── PatientsContainer.cs │ ├── ECGCycleDescription.cs │ ├── SystemInformation.cs │ ├── EITEntry.cs │ └── RPositions.cs ├── HDF5-CSharp.Example.csproj ├── GeneralUtils.cs └── KamaAcquisitionReadOnlyFile.cs ├── .gitattributes ├── HDF5-CSharp.Example.UnitTest ├── AcquisitionScanProtocol.json └── HDF5-CSharp.Example.UnitTest.csproj ├── azure-pipelines-1.yml ├── license.md ├── azure-pipelines.yml ├── HDF5-CSharp.sln └── .gitignore /codecov.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: lior-banai 2 | -------------------------------------------------------------------------------- /hdf5Wrapper.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/hdf5Wrapper.ico -------------------------------------------------------------------------------- /hdf5Wrapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/hdf5Wrapper.png -------------------------------------------------------------------------------- /Assets/HDF_logo.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/Assets/HDF_logo.svg -------------------------------------------------------------------------------- /Assets/HDFlogo128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/Assets/HDFlogo128.png -------------------------------------------------------------------------------- /misc/HDF.Pinvoke.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/misc/HDF.Pinvoke.snk -------------------------------------------------------------------------------- /Assets/hdf5Wrapper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/Assets/hdf5Wrapper.jpg -------------------------------------------------------------------------------- /Assets/hdf5Wrapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/Assets/hdf5Wrapper.png -------------------------------------------------------------------------------- /Assets/hdf5Wrapper.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/Assets/hdf5Wrapper.xcf -------------------------------------------------------------------------------- /Assets/hdf5FlatStructure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/Assets/hdf5FlatStructure.jpg -------------------------------------------------------------------------------- /HDF5-CSharp/hdf5Wrapper.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/HDF5-CSharp/hdf5Wrapper.ico -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5DotNetTools.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/HDF5-CSharp/Hdf5DotNetTools.snk -------------------------------------------------------------------------------- /HDF5-CSharp/Knf.Utils.Hdf5.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/HDF5-CSharp/Knf.Utils.Hdf5.snk -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/testFile.H5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/HDF5-CSharp.UnitTests/testFile.H5 -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/FileStructure.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/HDF5-CSharp.UnitTests/FileStructure.h5 -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/files/testCompounds_WData2_WData3.H5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SciSharp/HDF5-CSharp/HEAD/HDF5-CSharp.UnitTests/files/testCompounds_WData2_WData3.H5 -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Exception.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HDF5CSharp.DataTypes 4 | { 5 | public class Hdf5Exception : Exception 6 | { 7 | 8 | public Hdf5Exception(string message) : base(message) 9 | { 10 | 11 | } 12 | 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | public enum AcquisitionInterface 8 | { 9 | Kalpa, 10 | Kx, 11 | Simulator 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace HDF5CSharp.DataTypes 2 | { 3 | public enum Hdf5Save 4 | { 5 | Save, 6 | DoNotSave 7 | } 8 | 9 | public enum Hdf5LogLevel 10 | { 11 | Debug, 12 | Info, 13 | Warning, 14 | Error, 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/FileClosedArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HDF5CSharp.DataTypes 4 | { 5 | public class FileClosedArgs : EventArgs 6 | { 7 | public string ClosedFile { get; } 8 | public bool CancelRequested { get; set; } 9 | 10 | public FileClosedArgs(string fileName) 11 | { 12 | ClosedFile = fileName; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/Constants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | public static class Constants 8 | { 9 | public static string SystemInformationGroupName = "system_information"; 10 | public static string EventGroupName = "events"; 11 | public static string TagGroupName = "tags"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/InjectionGroup.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace HDF5CSharp.Example.DataTypes 5 | { 6 | [Hdf5GroupName("injection")] 7 | public class InjectionGroup : Hdf5BaseFile 8 | { 9 | public InjectionGroup(in long fileId, in long groupRoot, ILogger logger) : base(fileId, groupRoot, "injection", logger) 10 | { 11 | 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /HDF5-CSharp/Interfaces/IHdf5AcquisitionFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using HDF5CSharp.DataTypes; 3 | 4 | namespace HDF5CSharp.Interfaces 5 | { 6 | public interface IHdf5AcquisitionFile 7 | { 8 | Hdf5Patient Patient { get; set; } 9 | Hdf5Recording Recording { get; set; } 10 | Hdf5Channel[] Channels { get; set; } 11 | List EventList { get; } 12 | Hdf5Events Events { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ElectrodeAmpCalcConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | public class ElectrodeAmpCalcConfig 8 | { 9 | public double BF_Limit { get; set; } 10 | public double CF_Limit { get; set; } 11 | public double CurrentAt_0_4_BF { get; set; } 12 | public double CurrentAt_0_4_CF { get; set; } 13 | } 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Hdf5DotnetWrapper.Viewer 12 | { 13 | public partial class Form1 : Form 14 | { 15 | public Form1() 16 | { 17 | InitializeComponent(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/Version-Increment.yml: -------------------------------------------------------------------------------- 1 | name: Version Increment 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | logLevel: 6 | description: 'Log level' 7 | required: true 8 | default: 'warning' 9 | tags: 10 | description: 'Test scenario tags' 11 | 12 | jobs: 13 | build: 14 | runs-on: windows-latest 15 | steps: 16 | - run: | 17 | echo "Log level: ${{ github.event.inputs.logLevel }}" 18 | echo "Tags: ${{ github.event.inputs.tags }}" 19 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Patient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HDF5CSharp.DataTypes 4 | { 5 | [Hdf5GroupName("Patient")] 6 | public class Hdf5Patient 7 | { 8 | public string Name = ""; 9 | public string Id = ""; 10 | public int RecId = -1; 11 | public string Gender = ""; 12 | public DateTime BirthDate = DateTime.Now; 13 | public double Height = double.NaN; 14 | public double Weight = double.NaN; 15 | public DateTime EditData = DateTime.Now; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HDF5CSharp.DataTypes 4 | { 5 | [Hdf5GroupName("Events")] 6 | public struct Hdf5Events 7 | { 8 | public string[] Events { get; set; } 9 | public DateTime[] Times { get; set; } 10 | public TimeSpan[] Durations { get; set; } 11 | public Hdf5Events(int length) 12 | { 13 | Events = new string[length]; 14 | Times = new DateTime[length]; 15 | Durations = new TimeSpan[length]; 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Channel.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace HDF5CSharp.DataTypes 4 | { 5 | [Hdf5GroupName("Channel")] 6 | [StructLayout(LayoutKind.Sequential)] 7 | public struct Hdf5Channel 8 | { 9 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] 10 | public string Label; 11 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)] 12 | public string Dimension; 13 | public double Amplification; 14 | public double Offset; 15 | public double SamplingRate; 16 | public ulong NrOfSamples; 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace Hdf5DotnetWrapper.Viewer 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new Form1()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /HDF5-CSharp/Interfaces/IHdf5ReaderWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace HDF5CSharp.Interfaces 5 | { 6 | public interface IHdf5ReaderWriter 7 | { 8 | (int success, long CreatedgroupId) WriteFromArray(long groupId, string name, Array dset); 9 | (bool success, Array result) ReadToArray(long groupId, string name, string alternativeName); 10 | (int success, long CreatedgroupId) WriteStrings(long groupId, string name, IEnumerable collection, string datasetName = null); 11 | (bool success, IEnumerable) ReadStrings(long groupId, string name, string alternativeName); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example.UnitTest/AcquisitionScanProtocol.json: -------------------------------------------------------------------------------- 1 | { 2 | "ElectrodeParams": { 3 | "NumOfChannels": 64, 4 | "ActiveChannels": 32, 5 | "DefaultAmplitude": 0.4000000059604645, 6 | "DefaultAmplitudeCF": 0.4000000059604645, 7 | "DefaultAmplitudeBF": 0.4000000059604645, 8 | "GroundChannel": "B6", 9 | "UseBodySurfacePadCalibration": false 10 | }, 11 | "BodySensorDescription": { 12 | "Channels": [ "A1", "A2", "A3", "A4", "A5", "A6", "B6" ], 13 | "Amplitudes": [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 0.001 ], 14 | "Frequencies": [ 15200.0, 15200.0, 16800.0, 16800.0, 18400.0, 18400.0, 20000.0 ], 15 | "Phases": [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ] 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/AcquisitionInformation.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace HDF5CSharp.Example.DataTypes 5 | { 6 | [Hdf5GroupName("acquisition_information")] 7 | public class AcquisitionInformation : Hdf5BaseFile 8 | { 9 | private string Protocol { get; set; } 10 | 11 | public AcquisitionInformation(AcquisitionProtocolParameters acquisitionProtocol, long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "acquisition_information", logger) 12 | { 13 | Protocol = acquisitionProtocol.AsJson(); 14 | } 15 | 16 | public AcquisitionInformation() 17 | { 18 | 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5Errors.cs: -------------------------------------------------------------------------------- 1 | using HDF.PInvoke; 2 | using System; 3 | 4 | namespace HDF5CSharp 5 | { 6 | public static class Hdf5Errors 7 | { 8 | internal static int ErrorDelegateMethod(long estack, IntPtr client_data) 9 | { 10 | H5E.walk(estack, H5E.direction_t.H5E_WALK_DOWNWARD, WalkDelegateMethod, IntPtr.Zero); 11 | return 0; 12 | } 13 | 14 | internal static int WalkDelegateMethod(uint n, ref H5E.error_t err_desc, IntPtr client_data) 15 | { 16 | string msg = 17 | $"{err_desc.desc}. (function: {err_desc.func_name}. Line:{err_desc.line}. File: {err_desc.file_name})"; 18 | Hdf5Utils.LogError?.Invoke(msg); 19 | return 0; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /HDF5-CSharp.Example/HDF5-CSharp.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | HDF5CSharp.Example 6 | HDF5CSharp.Example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Channels.cs: -------------------------------------------------------------------------------- 1 | namespace HDF5CSharp.DataTypes 2 | { 3 | 4 | [Hdf5GroupName("Channels")] 5 | public class Hdf5Channels 6 | { 7 | public Hdf5Channels(int length) 8 | { 9 | Labels = new string[length]; 10 | Dimensions = new string[length]; 11 | Amplifications = new double[length]; 12 | Offsets = new double[length]; 13 | SamplingRates = new double[length]; 14 | NrOfSamples = new int[length]; 15 | } 16 | public string[] Labels { get; set; } 17 | public string[] Dimensions { get; set; } 18 | public double[] Amplifications { get; set; } 19 | public double[] Offsets { get; set; } 20 | public double[] SamplingRates { get; set; } 21 | public int[] NrOfSamples { get; set; } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Assets/nuget.svg: -------------------------------------------------------------------------------- 1 | nugetnugetv1.0.5.4v1.0.5.4 2 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/HDF5FileLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using HDF5CSharp.DataTypes; 4 | 5 | namespace Hdf5DotnetWrapper.Viewer 6 | { 7 | public partial class HDF5FileLoader : UserControl 8 | { 9 | public HDF5FileLoader() 10 | { 11 | InitializeComponent(); 12 | } 13 | 14 | private void btnHDF5Browse_Click(object sender, EventArgs e) 15 | { 16 | OpenFileDialog of = new OpenFileDialog 17 | { 18 | Multiselect = false, 19 | Filter = "Hdf5 files (*.h5)|*.h5", 20 | }; 21 | if (of.ShowDialog() == DialogResult.OK) 22 | { 23 | txtbHDF5.Text = of.FileName; 24 | } 25 | } 26 | 27 | private void btnHDF5ReadFile_Click(object sender, EventArgs e) 28 | { 29 | H5File Hdf5File = new H5File(); 30 | Hdf5File.ReadFileStructure(txtbHDF5.Text); 31 | 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /azure-pipelines-1.yml: -------------------------------------------------------------------------------- 1 | # ASP.NET 2 | # Build and test ASP.NET projects. 3 | # Add steps that publish symbols, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'windows-latest' 11 | 12 | variables: 13 | solution: '**/*.sln' 14 | buildPlatform: 'Any CPU' 15 | buildConfiguration: 'Release' 16 | 17 | steps: 18 | - task: NuGetToolInstaller@1 19 | 20 | - task: NuGetCommand@2 21 | inputs: 22 | restoreSolution: '$(solution)' 23 | 24 | - task: VSBuild@1 25 | inputs: 26 | solution: '$(solution)' 27 | msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"' 28 | platform: '$(buildPlatform)' 29 | configuration: '$(buildConfiguration)' 30 | 31 | - task: VSTest@2 32 | inputs: 33 | platform: '$(buildPlatform)' 34 | configuration: '$(buildConfiguration)' 35 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ProcedureInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HDF5CSharp.Example.DataTypes 4 | { 5 | // 6 | /// Patient Information class 7 | /// 8 | public class PatientInfo 9 | { 10 | public string PatientFirstName { get; set; } 11 | 12 | public string PatientFamilyName { get; set; } 13 | 14 | 15 | } 16 | /// 17 | /// Exam information 18 | /// 19 | public class ProcedureInfo 20 | { 21 | /// 22 | /// Patient Info 23 | /// 24 | public PatientInfo Patient { get; set; } 25 | 26 | 27 | /// 28 | /// Date of the Exam 29 | /// 30 | public DateTime ExamDate { get; set; } 31 | 32 | /// 33 | /// Unique ID of the current procedure 34 | /// 35 | public string ProcedureID { get; set; } 36 | 37 | public string FirstName { get; set; } 38 | 39 | public string LastName { get; set; } 40 | 41 | public int Age { get; set; } 42 | 43 | public string Procedure { get; set; } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright (c) [2020] Lior Banai 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5AttributeRW.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HDF5CSharp.Interfaces; 4 | 5 | namespace HDF5CSharp 6 | { 7 | public class Hdf5AttributeRW : IHdf5ReaderWriter 8 | { 9 | public (bool success, Array result) ReadToArray(long groupId, string name, string alternativeName) 10 | { 11 | return Hdf5.ReadPrimitiveAttributes(groupId, name, alternativeName); 12 | } 13 | 14 | public (int success, long CreatedgroupId) WriteFromArray(long groupId, string name, Array dset) 15 | { 16 | return Hdf5.WritePrimitiveAttribute(groupId, name, dset); 17 | } 18 | 19 | public (int success, long CreatedgroupId) WriteStrings(long groupId, string name, IEnumerable collection, string datasetName = null) 20 | { 21 | return Hdf5.WriteStringAttributes(groupId, name, (string[])collection, datasetName); 22 | } 23 | 24 | 25 | public (bool success, IEnumerable) ReadStrings(long groupId, string name, string alternativeName) 26 | { 27 | return Hdf5.ReadStringAttributes(groupId, name, alternativeName); 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/UserEventRecord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using HDF5CSharp.DataTypes; 6 | 7 | namespace HDF5CSharp.Example.DataTypes 8 | { 9 | [StructLayout(LayoutKind.Sequential)] 10 | [Serializable] 11 | public struct UserEventRecord 12 | { 13 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)] 14 | [Hdf5EntryName("routes")] public string Route; 15 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] 16 | [Hdf5EntryName("events")] public string Event; 17 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 400)] 18 | [Hdf5EntryName("description")] public string Description; 19 | [Hdf5EntryName("timestamps")] public long Timestamp; 20 | public UserEventRecord(string route, string eventData, string description, long timestamp) 21 | { 22 | Route = route; 23 | Description = description; 24 | Event = eventData; 25 | Timestamp = timestamp; 26 | } 27 | public override string ToString() => $"time: {Timestamp}: {nameof(Route)}: {Route}, {nameof(Event)}: {Event}."; 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Hdf5DotnetWrapper.Viewer.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Recording.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace HDF5CSharp.DataTypes 5 | { 6 | [Hdf5GroupName("Recording")] 7 | public class Hdf5Recording 8 | { 9 | int _nrOfChannels; 10 | 11 | [Hdf5Save(Hdf5Save.DoNotSave)] 12 | public event PropertyChangedEventHandler PropertyChanged; 13 | 14 | public string Id { get; set; } = ""; 15 | public bool ActiveFilter { get; set; } = false; 16 | public DateTime StartTime { get; set; } = DateTime.Now; 17 | public DateTime EndTime { get; set; } = DateTime.Now; 18 | public ulong NrOfSamples { get; set; } = 0; 19 | public double SampleRate { get; set; } = double.NaN; 20 | public string Physician { get; set; } = ""; 21 | public string Laborant { get; set; } = ""; 22 | 23 | public int NrOfChannels 24 | { 25 | get => _nrOfChannels; 26 | set 27 | { 28 | if (_nrOfChannels != value) 29 | { 30 | _nrOfChannels = value; 31 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(NrOfChannels))); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/CalibrationsSystemInformation.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Serializable] 8 | public class CalibrationsSystemInformation 9 | { 10 | public string SystemNewHWPath { get; set; } 11 | public string SystemNewHWContent { get; set; } 12 | public string PatchBoxCalibrationPath { get; set; } 13 | public string PatchBoxCalibrationContent { get; set; } 14 | public List<(string filePath, string fileContent)> Configurations { get; set; } 15 | 16 | public CalibrationsSystemInformation() 17 | { 18 | Configurations = new List<(string filePath, string fileContent)>(); 19 | SystemNewHWContent = string.Empty; 20 | SystemNewHWPath = string.Empty; 21 | PatchBoxCalibrationPath = string.Empty; 22 | PatchBoxCalibrationContent = string.Empty; 23 | } 24 | 25 | public string ToJson() => JsonConvert.SerializeObject(this); 26 | public static CalibrationsSystemInformation FromJson(string calibrationPath) 27 | => JsonConvert.DeserializeObject(calibrationPath); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Hdf5Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace HDF5CSharp.DataTypes 5 | { 6 | /// 7 | /// 8 | /// 9 | [Hdf5GroupName("Event")] 10 | [StructLayout(LayoutKind.Sequential)] 11 | public struct Hdf5Event 12 | { 13 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 14 | public string Event; 15 | 16 | /// 17 | /// Time property. Datetimes can't be saved so the TimeTicks field gets saved 18 | /// 19 | [Hdf5Save(Hdf5Save.DoNotSave)] 20 | public DateTime Time 21 | { 22 | get => new DateTime(TimeTicks); 23 | set => TimeTicks = Hdf5Conversions.FromDatetime(value, Hdf5.Settings.DateTimeType); 24 | } 25 | 26 | public long TimeTicks; 27 | 28 | /// 29 | /// Duration property. Timespans can't be saved so the DurationTicks field gets saved 30 | /// 31 | [Hdf5Save(Hdf5Save.DoNotSave)] 32 | public TimeSpan Duration 33 | { 34 | get => new TimeSpan(DurationTicks); 35 | set => DurationTicks = value.Ticks; 36 | } 37 | 38 | public long DurationTicks; 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/RPositionEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using HDF5CSharp.DataTypes; 6 | 7 | namespace HDF5CSharp.Example.DataTypes 8 | { 9 | [StructLayout(LayoutKind.Sequential)] 10 | public struct RPositionEvent 11 | { 12 | [Hdf5EntryName("timestamp")] public ulong timestamp; 13 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] [Hdf5EntryName("name")] public string name; 14 | [Hdf5EntryName("x")] public float x; 15 | [Hdf5EntryName("y")] public float y; 16 | [Hdf5EntryName("z")] public float z; 17 | [Hdf5EntryName("direction_x")] public float direction_x; 18 | [Hdf5EntryName("direction_y")] public float direction_y; 19 | [Hdf5EntryName("direction_z")] public float direction_z; 20 | public RPositionEvent(ulong timestamp, string name, float x, float y, float z, float direction_x, float direction_y, float direction_z) 21 | { 22 | this.timestamp = timestamp; 23 | this.name = name; 24 | this.x = x; 25 | this.y = y; 26 | this.z = z; 27 | this.direction_x = direction_x; 28 | this.direction_y = direction_y; 29 | this.direction_z = direction_z; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/Hdf5Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HDF5CSharp.DataTypes; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Hdf5GroupName("system_events")] 8 | public class Hdf5Events 9 | { 10 | [Hdf5EntryName("timestamps")] public long[] timestamps; 11 | [Hdf5EntryName("type")] public string[] type; 12 | [Hdf5EntryName("description")] public string[] description; 13 | [Hdf5EntryName("data")] public string[] data; 14 | 15 | public Hdf5Events() 16 | { 17 | timestamps = Array.Empty(); 18 | type = Array.Empty(); 19 | description= Array.Empty(); 20 | data= Array.Empty(); 21 | } 22 | public Hdf5Events(List eventsData) 23 | { 24 | timestamps = new long[eventsData.Count]; 25 | type = new string[eventsData.Count]; 26 | description = new string[eventsData.Count]; 27 | data = new string[eventsData.Count]; 28 | for (int i = 0; i < eventsData.Count; i++) 29 | { 30 | timestamps[i] = eventsData[i].timestamp; 31 | type[i] = eventsData[i].type; 32 | description[i] = eventsData[i].description; 33 | data[i] = eventsData[i].data; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ECGFrame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MessagePack; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Serializable] 8 | [MessagePackObject(keyAsPropertyName: false)] 9 | 10 | public class ECGFrame 11 | { 12 | 13 | [Key("packetId")] public UInt64 PacketId { get; set; } 14 | [Key("timestamp")] public long Timestamp { get; set; } 15 | [Key("KalpaClock")] public UInt64 KalpaClock { get; set; } 16 | [Key("Data")] public List> FrameData { get; set; } 17 | [Key("DataFiltered")] public List> FilteredFrameData { get; set; } 18 | 19 | 20 | [IgnoreMember] public bool IsValid;// Prior the stabilization (normalization need to be done), the frame will be raised as invalid 21 | [IgnoreMember] public bool IsTriggerToInjection; 22 | 23 | public ECGFrame() 24 | { 25 | FrameData = new List>(); 26 | FilteredFrameData = new List>(); 27 | IsValid = true; 28 | } 29 | public ECGFrame(List> filteredData, List> unFilteredData, long timestamp, UInt64 packetId) 30 | { 31 | PacketId = packetId; 32 | FilteredFrameData = filteredData; 33 | FrameData = unFilteredData; 34 | IsTriggerToInjection = false; 35 | Timestamp = timestamp; 36 | 37 | 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/BlockingCollectionQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | 6 | namespace HDF5CSharp.Example.DataTypes 7 | { 8 | public class BlockingCollectionQueue : IDisposable 9 | { 10 | private BlockingCollection items = new BlockingCollection(); 11 | private long runningIndex; 12 | 13 | public int Count => items.Count; 14 | 15 | public void CompleteAdding() => items.CompleteAdding(); 16 | public void Enqueue(T item) 17 | { 18 | Interlocked.Increment(ref runningIndex); 19 | items.Add(item); 20 | } 21 | 22 | public long RunningIndex => runningIndex; 23 | public IEnumerable GetConsumingEnumerable(CancellationToken cancellationToken) 24 | { 25 | foreach (var item in items.GetConsumingEnumerable()) 26 | { 27 | yield return item; 28 | if (cancellationToken.IsCancellationRequested) 29 | { 30 | yield break; 31 | } 32 | } 33 | } 34 | public IEnumerable GetConsumingEnumerable() 35 | { 36 | foreach (var item in items.GetConsumingEnumerable()) 37 | { 38 | yield return item; 39 | } 40 | } 41 | 42 | public void Dispose() 43 | { 44 | items?.Dispose(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/FilesUnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | 8 | namespace HDF5CSharp.UnitTests.Core 9 | { 10 | [TestClass] 11 | public class FilesUnitTests : Hdf5BaseUnitTests 12 | { 13 | private static List Errors { get; set; } 14 | 15 | public FilesUnitTests() 16 | { 17 | Errors=new List(); 18 | } 19 | [TestMethod] 20 | public void TestReadStructure() 21 | { 22 | Hdf5.Settings.EnableErrorReporting(true); 23 | Hdf5Utils.LogWarning = (s) => Errors.Add(s); 24 | Hdf5Utils.LogError = (s) => Errors.Add(s); 25 | string fileName = @"testfile.h5"; 26 | if (File.Exists(fileName)) 27 | { 28 | var tree = Hdf5.ReadTreeFileStructure(fileName); 29 | var flat = Hdf5.ReadFlatFileStructure(fileName); 30 | File.Delete(fileName); 31 | if (Errors.Any()) 32 | { 33 | foreach (string error in Errors) 34 | { 35 | Console.WriteLine(error); 36 | } 37 | } 38 | Assert.IsFalse(File.Exists(fileName)); 39 | Assert.IsTrue(tree!=null); 40 | Assert.IsTrue(flat != null); 41 | } 42 | } 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Hdf5DotnetWrapper.Viewer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Hdf5DotnetWrapper.Viewer")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("47201833-e346-46e1-b3f3-3b137b8beb0d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/GeneralUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace HDF5CSharp.Example 7 | { 8 | 9 | public class DateTimeComparerUpToMilliseconds : IEqualityComparer 10 | { 11 | public bool Equals(DateTime x, DateTime y) => x.EqualsUpToMilliseconds(y); 12 | 13 | 14 | public int GetHashCode(DateTime obj) => (obj.Year * 397) ^ (obj.Month * 397) ^ (obj.Day * 397) ^ (obj.Hour * 397) ^ (obj.Minute * 397) ^ (obj.Second * 397) ^ (obj.Second * 397); 15 | } 16 | public static class GeneralUtils 17 | { 18 | public static DateTimeComparerUpToMilliseconds DateTimeComparerUpToMilliseconds { get; } = new DateTimeComparerUpToMilliseconds(); 19 | public static bool EqualsUpToMilliseconds(this DateTime dt1, DateTime dt2) 20 | { 21 | return dt1.Year == dt2.Year && dt1.Month == dt2.Month && dt1.Day == dt2.Day && 22 | dt1.Hour == dt2.Hour && dt1.Minute == dt2.Minute && dt1.Second == dt2.Second && dt1.Millisecond == dt2.Millisecond; 23 | } 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static (bool NonZeroFile, string Message) CheckFileSize(string filename) 26 | { 27 | FileInfo fileInfo = new FileInfo(filename); 28 | if (fileInfo.Length > 0) 29 | { 30 | string msg = $"File {filename} has size: {fileInfo.Length}"; 31 | return (true, msg); 32 | } 33 | else 34 | { 35 | string msg = $"File {filename} has zero size"; 36 | return (false, msg); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example.UnitTest/HDF5-CSharp.Example.UnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | HDF5_CSharp.Example.UnitTest 6 | 7 | false 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Always 34 | 35 | 36 | Always 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5AcquisitionFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using HDF5CSharp.DataTypes; 3 | using HDF5CSharp.Interfaces; 4 | 5 | namespace HDF5CSharp 6 | { 7 | 8 | [Hdf5Save(Hdf5Save.Save)] 9 | public class Hdf5AcquisitionFile : IHdf5AcquisitionFile 10 | { 11 | public Hdf5Patient Patient { get; set; } 12 | public Hdf5Recording Recording { get; set; } 13 | public Hdf5Channel[] Channels { get; set; } 14 | public Hdf5Events Events { get; set; } 15 | [Hdf5Save(Hdf5Save.DoNotSave)] 16 | public List EventList { get; private set; } 17 | 18 | [Hdf5Save(Hdf5Save.DoNotSave)] 19 | public short[,] Data { get; set; } 20 | 21 | public Hdf5AcquisitionFile() 22 | { 23 | Patient = new Hdf5Patient(); 24 | Recording = new Hdf5Recording(); 25 | EventList = new List(); 26 | Events = new Hdf5Events(); 27 | 28 | Recording.PropertyChanged += (sender, eventArgs) => 29 | { 30 | if (eventArgs.PropertyName == nameof(Hdf5Recording.NrOfChannels)) 31 | { 32 | Channels = new Hdf5Channel[Recording.NrOfChannels]; 33 | } 34 | }; 35 | 36 | } 37 | 38 | 39 | public void EventListToEvents() 40 | { 41 | Events = new Hdf5Events(EventList.Count); 42 | for (int i = 0; i < EventList.Count; i++) 43 | { 44 | Events.Times[i] = EventList[i].Time; 45 | Events.Durations[i] = EventList[i].Duration; 46 | Events.Events[i] = EventList[i].Event; 47 | } 48 | 49 | } 50 | 51 | } 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5Conversions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace HDF5CSharp 5 | { 6 | public static class Hdf5Conversions 7 | { 8 | private static DateTime unix = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static long FromDatetime(DateTime time, DateTimeType type) 11 | { 12 | switch (type) 13 | { 14 | case DateTimeType.Ticks: 15 | return time.Ticks; 16 | case DateTimeType.UnixTimeSeconds: 17 | return (long)(time.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, time.Kind))).TotalSeconds; 18 | case DateTimeType.UnixTimeMilliseconds: 19 | return (long)(time.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, time.Kind))).TotalMilliseconds; 20 | default: 21 | throw new ArgumentOutOfRangeException(nameof(type), type, null); 22 | } 23 | } 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static DateTime ToDateTime(long value, DateTimeType type) 26 | { 27 | 28 | switch (type) 29 | { 30 | case DateTimeType.Ticks: 31 | return new DateTime(value); 32 | break; 33 | case DateTimeType.UnixTimeSeconds: 34 | return unix.AddSeconds(value); 35 | case DateTimeType.UnixTimeMilliseconds: 36 | return unix.AddMilliseconds(value); 37 | default: 38 | throw new ArgumentOutOfRangeException(nameof(type), type, null); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5Settings.cs: -------------------------------------------------------------------------------- 1 | using HDF.PInvoke; 2 | using System; 3 | 4 | namespace HDF5CSharp 5 | { 6 | public static partial class Hdf5 7 | { 8 | public static Settings Settings { get; set; } 9 | 10 | 11 | static Hdf5() 12 | { 13 | Settings = new Settings(); 14 | 15 | } 16 | } 17 | 18 | public class Settings 19 | { 20 | public DateTimeType DateTimeType { get; set; } 21 | public bool LowerCaseNaming { get; set; } 22 | public bool ErrorLoggingEnable { get; private set; } 23 | public bool ThrowOnError { get; set; } 24 | public bool OverrideExistingData { get; set; } 25 | public float Version { get; set; } 26 | public Settings() 27 | { 28 | DateTimeType = DateTimeType.Ticks; 29 | ThrowOnError = true; 30 | OverrideExistingData = true; 31 | Version = 1.0f; 32 | } 33 | 34 | public Settings(DateTimeType dateTimeType, bool lowerCaseNaming, bool throwOnError, bool overrideExistingData) 35 | { 36 | DateTimeType = dateTimeType; 37 | LowerCaseNaming = lowerCaseNaming; 38 | ThrowOnError = throwOnError; 39 | OverrideExistingData = overrideExistingData; 40 | } 41 | public bool EnableErrorReporting(bool enable) 42 | { 43 | ErrorLoggingEnable = enable; 44 | if (enable) 45 | { 46 | return H5E.set_auto(H5E.DEFAULT, Hdf5Errors.ErrorDelegateMethod, IntPtr.Zero) >= 0; 47 | } 48 | 49 | return H5E.set_auto(H5E.DEFAULT, null, IntPtr.Zero) >= 0; 50 | 51 | } 52 | } 53 | 54 | public enum DateTimeType 55 | { 56 | Ticks, 57 | UnixTimeSeconds, 58 | UnixTimeMilliseconds 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/CalibrationGroup.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace HDF5CSharp.Example.DataTypes 5 | { 6 | [Hdf5GroupName("calibrations")] 7 | public class CalibrationGroup : Hdf5BaseFile 8 | { 9 | [Hdf5EntryName("system_new_hw_path")] 10 | public string SystemNewHWPath { get; set; } 11 | [Hdf5EntryName("system_new_hw_content")] 12 | public string SystemNewHWContent { get; set; } 13 | [Hdf5EntryName("patch_box_calibration_Path")] 14 | public string PatchBoxCalibrationPath { get; set; } 15 | [Hdf5EntryName("patch_box_calibration_content")] 16 | public string PatchBoxCalibrationContent { get; set; } 17 | 18 | public CalibrationGroup(in long fileId, in long groupRoot, ILogger logger) : base(fileId, groupRoot, "calibrations", logger) 19 | { 20 | } 21 | 22 | public void AddCalibrationsData(CalibrationsSystemInformation calibrationsSystemInformation) 23 | { 24 | SystemNewHWPath = calibrationsSystemInformation.SystemNewHWPath; 25 | SystemNewHWContent = calibrationsSystemInformation.SystemNewHWContent; 26 | PatchBoxCalibrationPath = calibrationsSystemInformation.PatchBoxCalibrationPath; 27 | PatchBoxCalibrationContent = calibrationsSystemInformation.PatchBoxCalibrationContent; 28 | int fileNum = 0; 29 | foreach ((string filePath, string fileContent) in calibrationsSystemInformation.Configurations) 30 | { 31 | string key = $"file {fileNum++}"; 32 | Hdf5.WriteStrings(GroupId, key, new[] { filePath, fileContent }); 33 | Hdf5.WriteAttribute(GroupId, key, "first entry is file name. Second is content"); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/TagsGroup.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace HDF5CSharp.Example.DataTypes 8 | { 9 | 10 | [Hdf5GroupName("tags")] 11 | public class TagsGroup : Hdf5BaseFile, IDisposable 12 | { 13 | private Hdf5Events tags; 14 | [Hdf5Save(Hdf5Save.DoNotSave)] private List TagsData { get; set; } 15 | [Hdf5Save(Hdf5Save.DoNotSave)] private bool record; 16 | public TagsGroup(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "tags", logger) 17 | { 18 | TagsData = new List(); 19 | 20 | } 21 | 22 | 23 | public void Enqueue(string tagJson) 24 | { 25 | 26 | if (record) 27 | { 28 | TagsData.Add(string.IsNullOrEmpty(tagJson) ? "[]" : tagJson); 29 | } 30 | } 31 | 32 | 33 | public Task WaitForDataWritten() 34 | { 35 | record = false; 36 | Logger.LogInformation("Start write of Tags"); 37 | var status = Hdf5.WriteObject(GroupId, TagsData.ToArray()); 38 | Logger.LogInformation("End write of Tags with status " + status); 39 | return Task.CompletedTask; 40 | } 41 | 42 | public void StopRecording() => record = false; 43 | 44 | public void StartLogging() => record = true; 45 | public void Dispose() 46 | { 47 | try 48 | { 49 | if (!Disposed) 50 | { 51 | Hdf5.CloseGroup(GroupId); 52 | } 53 | 54 | } 55 | catch (Exception) 56 | { 57 | //nothing 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/HDF5-CSharp.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | HDF5CSharp.UnitTests.Core 9 | 10 | HDF5CSharp.UnitTests.Core 11 | 12 | 13 | 14 | AnyCPU 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Always 37 | 38 | 39 | Always 40 | 41 | 42 | 43 | 44 | 45 | 46 | Always 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /.github/workflows/codacy-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow checks out code, performs a Codacy security scan 2 | # and integrates the results with the 3 | # GitHub Advanced Security code scanning feature. For more information on 4 | # the Codacy security scan action usage and parameters, see 5 | # https://github.com/codacy/codacy-analysis-cli-action. 6 | # For more information on Codacy Analysis CLI in general, see 7 | # https://github.com/codacy/codacy-analysis-cli. 8 | 9 | name: Codacy Security Scan 10 | 11 | on: 12 | push: 13 | branches: [ master ] 14 | pull_request: 15 | branches: [ master ] 16 | 17 | jobs: 18 | codacy-security-scan: 19 | name: Codacy Security Scan 20 | runs-on: ubuntu-latest 21 | steps: 22 | # Checkout the repository to the GitHub Actions runner 23 | - name: Checkout code 24 | uses: actions/checkout@v2 25 | 26 | # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis 27 | - name: Run Codacy Analysis CLI 28 | uses: codacy/codacy-analysis-cli-action@1.1.0 29 | with: 30 | # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository 31 | # You can also omit the token and run the tools that support default configurations 32 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 33 | verbose: true 34 | output: results.sarif 35 | format: sarif 36 | # Adjust severity of non-security issues 37 | gh-code-scanning-compat: true 38 | # Force 0 exit code to allow SARIF file generation 39 | # This will handover control about PR rejection to the GitHub side 40 | max-allowed-issues: 2147483647 41 | 42 | # Upload the SARIF file generated in the previous step 43 | - name: Upload SARIF results file 44 | uses: github/codeql-action/upload-sarif@v1 45 | with: 46 | sarif_file: results.sarif 47 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/Attributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HDF5CSharp.DataTypes 4 | { 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] 6 | public sealed class Hdf5GroupName : Attribute 7 | { 8 | 9 | public Hdf5GroupName(string name) 10 | { 11 | Name = name; 12 | } 13 | 14 | public string Name { get; private set; } 15 | } 16 | 17 | public sealed class Hdf5KeyValuesAttributes : Attribute 18 | { 19 | public string Key { get; set; } 20 | public string[] Values { get; private set; } 21 | public Hdf5KeyValuesAttributes(string key, string[] values) 22 | { 23 | Values = values; 24 | Key = key; 25 | } 26 | 27 | } 28 | public sealed class Hdf5Attributes : Attribute 29 | { 30 | 31 | public Hdf5Attributes(string[] names) 32 | { 33 | Names = names; 34 | } 35 | 36 | public string[] Names { get; private set; } 37 | } 38 | 39 | public sealed class Hdf5Attribute : Attribute 40 | { 41 | 42 | public Hdf5Attribute(string name) 43 | { 44 | Name = name; 45 | } 46 | 47 | public string Name { get; private set; } 48 | } 49 | 50 | 51 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] 52 | public sealed class Hdf5SaveAttribute : Attribute 53 | { 54 | public Hdf5Save SaveKind { get; } // Topic is a named parameter 55 | 56 | 57 | public Hdf5SaveAttribute(Hdf5Save saveKind) // url is a positional parameter 58 | { 59 | SaveKind = saveKind; 60 | } 61 | 62 | } 63 | 64 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] 65 | public sealed class Hdf5EntryNameAttribute : Attribute 66 | { 67 | public string Name { get; } 68 | 69 | 70 | public Hdf5EntryNameAttribute(string name) 71 | { 72 | Name = name; 73 | } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5Groups.cs: -------------------------------------------------------------------------------- 1 | using HDF.PInvoke; 2 | using HDF5CSharp.DataTypes; 3 | using System.Collections.Generic; 4 | 5 | namespace HDF5CSharp 6 | { 7 | public static partial class Hdf5 8 | { 9 | public static bool GroupExists(long groupId, string groupName) => Hdf5Utils.ItemExists(groupId, groupName, Hdf5ElementType.Group); 10 | 11 | public static int CloseGroup(long groupId) 12 | { 13 | return H5G.close(groupId); 14 | } 15 | 16 | public static long CreateOrOpenGroup(long groupId, string groupName) 17 | { 18 | 19 | return (Hdf5Utils.ItemExists(groupId, groupName, Hdf5ElementType.Group)) 20 | ? H5G.open(groupId, Hdf5Utils.NormalizedName(groupName)) 21 | : H5G.create(groupId, Hdf5Utils.NormalizedName(groupName)); 22 | } 23 | 24 | 25 | 26 | 27 | /// 28 | /// creates a structure of groups at once 29 | /// 30 | /// 31 | /// 32 | /// 33 | public static long CreateGroupRecursively(long groupOrFileId, string groupName) 34 | { 35 | IEnumerable grps = groupName.Split('/'); 36 | long gid = groupOrFileId; 37 | groupName = ""; 38 | foreach (var name in grps) 39 | { 40 | groupName = string.Concat(groupName, "/", name); 41 | gid = CreateOrOpenGroup(gid, groupName); 42 | } 43 | return gid; 44 | } 45 | 46 | public static ulong NumberOfAttributes(int groupId, string groupName) 47 | { 48 | H5O.info_t info = new H5O.info_t(); 49 | var gid = H5O.get_info(groupId, ref info); 50 | return info.num_attrs; 51 | } 52 | 53 | public static H5G.info_t GroupInfo(long groupId) 54 | { 55 | H5G.info_t info = new H5G.info_t(); 56 | var gid = H5G.get_info(groupId, ref info); 57 | return info; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ElectrodeFrame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using MessagePack; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Serializable] 8 | [MessagePackObject(keyAsPropertyName: true)] 9 | public class ElectrodeFrame 10 | { 11 | public (float Re, float Im)[] ComplexVoltageMatrix { get; set; } // CHANNELS * CHANNELS entries 12 | public (float Re, float Im)[] ComplexCurrentMatrix { get; set; } // CHANNELS * CHANNELS entries 13 | 14 | public long timestamp; // timestamp in unix time (milliseconds since 1.1.1970 00:00:00 - less accurate) 15 | 16 | public UInt64 PacketId = UInt64.MaxValue; // serial number of packet 17 | 18 | public UInt64 KalpaClock = UInt64.MaxValue; // Kalpa timestamp in msec? (the most accurate) 19 | 20 | public UInt64 SaturationMask; 21 | 22 | public void GenerateDummyData(int electrodeNum) 23 | { 24 | ComplexVoltageMatrix = new ValueTuple[electrodeNum * electrodeNum]; 25 | ComplexCurrentMatrix = new ValueTuple[electrodeNum * electrodeNum]; 26 | 27 | Random r = new Random(); 28 | 29 | for (int i = 0; i < electrodeNum * electrodeNum; i++) 30 | { 31 | ComplexVoltageMatrix[i].Re = r.Next(0, 1000) / 1000.0f; 32 | ComplexVoltageMatrix[i].Im = r.Next(0, 1000) / 1000.0f; 33 | ComplexCurrentMatrix[i].Im = r.Next(0, 1000) / 1000.0f; 34 | ComplexCurrentMatrix[i].Re = r.Next(0, 1000) / 1000.0f; 35 | } 36 | 37 | PacketId = 5; 38 | KalpaClock = 1600; 39 | SaturationMask = 0; 40 | } 41 | 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static byte[] Serialize(ElectrodeFrame fr) => MessagePackSerializer.Serialize(fr); 44 | 45 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 46 | public static ElectrodeFrame Deserialize(byte[] array) => MessagePackSerializer.Deserialize(array); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/H5ETest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using HDF.PInvoke; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace HDF5CSharp.UnitTests.Core 6 | { 7 | [TestClass] 8 | public class H5ETest 9 | { 10 | [TestMethod] 11 | public void H5EwalkTest1() 12 | { 13 | H5E.auto_t auto_cb = ErrorDelegateMethod; 14 | Assert.IsTrue( 15 | H5E.set_auto(H5E.DEFAULT, auto_cb, IntPtr.Zero) >= 0); 16 | 17 | H5E.walk_t walk_cb = WalkDelegateMethod; 18 | Assert.IsTrue( 19 | H5E.walk(H5E.DEFAULT, H5E.direction_t.H5E_WALK_DOWNWARD, 20 | walk_cb, IntPtr.Zero) >= 0); 21 | } 22 | 23 | 24 | [TestMethod] 25 | public void H5EwalkTest2() 26 | { 27 | // H5E.set_auto(H5E.DEFAULT, ErrorDelegateMethod, IntPtr.Zero); 28 | Assert.IsTrue( 29 | H5E.set_auto(H5E.DEFAULT, ErrorDelegateMethod, IntPtr.Zero) >= 0); 30 | 31 | H5E.walk_t walk_cb = WalkDelegateMethod; 32 | Assert.IsTrue( 33 | H5E.push(H5E.DEFAULT, "hello.c", "sqrt", 77, H5E.ERR_CLS, 34 | H5E.NONE_MAJOR, H5E.NONE_MINOR, "Hello, World!") >= 0); 35 | 36 | Assert.IsTrue( 37 | H5E.push(H5E.DEFAULT, "hello.c", "sqr", 78, H5E.ERR_CLS, 38 | H5E.NONE_MAJOR, H5E.NONE_MINOR, "Hello, World!") >= 0); 39 | 40 | Assert.IsTrue( 41 | H5E.walk(H5E.DEFAULT, H5E.direction_t.H5E_WALK_DOWNWARD, 42 | walk_cb, IntPtr.Zero) >= 0); 43 | 44 | } 45 | 46 | public static int ErrorDelegateMethod(long estack, IntPtr client_data) 47 | { 48 | H5E.walk(estack, H5E.direction_t.H5E_WALK_DOWNWARD, WalkDelegateMethod, IntPtr.Zero); 49 | return 0; 50 | } 51 | 52 | public static int WalkDelegateMethod(uint n, ref H5E.error_t err_desc, IntPtr client_data) 53 | { 54 | // log your error, e.g. logger.LogInformation(err_desc.desc); 55 | return 0; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataProducerConsumer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Diagnostics; 4 | using System.Threading; 5 | 6 | namespace HDF5CSharp 7 | { 8 | public class DataProducerConsumer : IDisposable 9 | { 10 | private BlockingCollection _queue = new BlockingCollection(); 11 | private readonly Action _action; 12 | 13 | public DataProducerConsumer(Action action) 14 | { 15 | _action = action; 16 | 17 | var thread = new Thread(StartConsuming) 18 | { 19 | IsBackground = true 20 | }; 21 | thread.Start(); 22 | } 23 | 24 | public void Dispose() 25 | { 26 | Dispose(true); 27 | GC.SuppressFinalize(this); 28 | } 29 | 30 | protected virtual void Dispose(bool disposing) 31 | { 32 | if (disposing) 33 | { 34 | _queue.Dispose(); 35 | } 36 | } 37 | 38 | public void Done() 39 | { 40 | _queue.CompleteAdding(); 41 | } 42 | 43 | public void Produce(T item) 44 | { 45 | _queue.Add(item); 46 | } 47 | 48 | private void StartConsuming() 49 | { 50 | while (!_queue.IsCompleted) 51 | { 52 | try 53 | { 54 | _queue.TryTake(out T data); 55 | if (data != null) 56 | { 57 | Debug.WriteLine($"item {_queue.Count + 1} in queue will be processed"); 58 | _action(data); 59 | } 60 | 61 | } 62 | catch (InvalidOperationException ex) 63 | { 64 | Debug.WriteLine($"Work queue on thread {0} has been closed. {ex}", Thread.CurrentThread.ManagedThreadId); 65 | } 66 | } 67 | IsDone?.Invoke(this, new EventArgs()); 68 | Dispose(); 69 | } 70 | 71 | public event EventHandler IsDone; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/Hdf5BaseFile.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Serializable] 8 | public abstract class Hdf5BaseFile 9 | { 10 | [Hdf5Save(Hdf5Save.DoNotSave)] private long FileId { get; } 11 | [Hdf5Save(Hdf5Save.DoNotSave)] protected long GroupRoot { get; } 12 | [Hdf5Save(Hdf5Save.DoNotSave)] protected string GroupName { get; } 13 | [Hdf5Save(Hdf5Save.DoNotSave)] protected long GroupId { get; } 14 | [Hdf5Save(Hdf5Save.DoNotSave)] protected bool Disposed { get; set; } 15 | [Hdf5Save(Hdf5Save.DoNotSave)] protected ILogger Logger { get; } 16 | protected Hdf5BaseFile(in long fileId, in long groupRoot, in string groupName, ILogger logger) 17 | { 18 | FileId = fileId; 19 | GroupRoot = groupRoot; 20 | GroupName = groupName; 21 | Logger = logger; 22 | GroupId = Hdf5.CreateOrOpenGroup(groupRoot, GroupName); 23 | 24 | } 25 | protected Hdf5BaseFile() 26 | { 27 | 28 | } 29 | 30 | public void FlushData() 31 | { 32 | if (Disposed) 33 | { 34 | return; 35 | } 36 | 37 | try 38 | { 39 | Hdf5.WriteObject(GroupRoot, this, GroupName); 40 | Hdf5.Flush(GroupId, HDF.PInvoke.H5F.scope_t.LOCAL); 41 | } 42 | catch (Exception e) 43 | { 44 | Logger?.LogError(e, $"Error FlushData: {e.Message}. Type: {GetType()}"); 45 | } 46 | } 47 | public void FlushDataAndCloseObject() 48 | { 49 | try 50 | { 51 | if (Disposed) 52 | { 53 | return; 54 | } 55 | 56 | FlushData(); 57 | Hdf5.CloseGroup(GroupId); 58 | } 59 | catch (Exception e) 60 | { 61 | Logger?.LogError(e, $"Error FlushDataAndCloseObject: {e.Message}. Type: {GetType()}"); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/UserEventsGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using HDF5CSharp.DataTypes; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace HDF5CSharp.Example.DataTypes 10 | { 11 | public class Hdf5UserEvents 12 | { 13 | [Hdf5EntryName("user_events")] public UserEventRecord[] Events { get; set; } 14 | public Hdf5UserEvents(List eventsData) 15 | { 16 | Events = eventsData.ToArray(); 17 | } 18 | 19 | public Hdf5UserEvents() 20 | { 21 | 22 | } 23 | } 24 | 25 | public class UserEventsGroup : Hdf5BaseFile, IDisposable 26 | { 27 | [Hdf5Save(Hdf5Save.DoNotSave)] private List userEventsData; 28 | 29 | public UserEventsGroup(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, Constants.EventGroupName, logger) 30 | { 31 | userEventsData = new List(); 32 | } 33 | 34 | public void Enqueue(UserEventRecord userEventRecord) 35 | { 36 | userEventsData.Add(userEventRecord); 37 | } 38 | 39 | public Task WaitForDataWritten() 40 | { 41 | if (!userEventsData.Any()) 42 | { 43 | Logger.LogWarning("No user event to write to H5 file"); 44 | return Task.CompletedTask; 45 | } 46 | var dataToWrite = userEventsData; 47 | userEventsData = new List(); 48 | Hdf5UserEvents eventsToH5 = new Hdf5UserEvents(dataToWrite); 49 | Logger.LogInformation("Start write of User Events"); 50 | var status = Hdf5.WriteObject(GroupRoot, eventsToH5, Constants.EventGroupName); 51 | Logger.LogInformation("End write of User Events with status " + status); 52 | return Task.CompletedTask; 53 | } 54 | public void Dispose() 55 | { 56 | try 57 | { 58 | if (!Disposed) 59 | { 60 | Hdf5.CloseGroup(GroupId); 61 | } 62 | 63 | } 64 | catch (Exception) 65 | { 66 | //nothing 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Hdf5DotnetWrapper.Viewer 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.hdF5FileLoader1 = new Hdf5DotnetWrapper.Viewer.HDF5FileLoader(); 32 | this.SuspendLayout(); 33 | // 34 | // hdF5FileLoader1 35 | // 36 | this.hdF5FileLoader1.Dock = System.Windows.Forms.DockStyle.Fill; 37 | this.hdF5FileLoader1.Location = new System.Drawing.Point(0, 0); 38 | this.hdF5FileLoader1.Name = "hdF5FileLoader1"; 39 | this.hdF5FileLoader1.Size = new System.Drawing.Size(800, 506); 40 | this.hdF5FileLoader1.TabIndex = 0; 41 | // 42 | // Form1 43 | // 44 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 18F); 45 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 46 | this.ClientSize = new System.Drawing.Size(800, 506); 47 | this.Controls.Add(this.hdF5FileLoader1); 48 | this.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 49 | this.Name = "Form1"; 50 | this.Text = "Form1"; 51 | this.ResumeLayout(false); 52 | 53 | } 54 | 55 | #endregion 56 | 57 | private HDF5FileLoader hdF5FileLoader1; 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/AssemblyInformationRecord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using HDF5CSharp.DataTypes; 6 | 7 | namespace HDF5CSharp.Example.DataTypes 8 | { 9 | [StructLayout(LayoutKind.Sequential)] 10 | [Serializable] 11 | public struct AssemblyInformationRecord 12 | { 13 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 120)] 14 | [Hdf5EntryName("file_name")] public readonly string FileName; 15 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 16 | [Hdf5EntryName("file_version")] public readonly string FileVersion; 17 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 18 | [Hdf5EntryName("product_version")] public readonly string ProductVersion; 19 | [Hdf5EntryName("date_modified")] public readonly long DateModified; 20 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 21 | [Hdf5EntryName("date_modified_time")] public readonly string DateModifiedDisplayName; 22 | public AssemblyInformationRecord(string filename, string fileVersion, string productVersion, long dateModified) 23 | { 24 | FileName = filename; 25 | FileVersion = fileVersion; 26 | ProductVersion = productVersion; 27 | DateModified = dateModified; 28 | DateModifiedDisplayName = DateTimeOffset.FromUnixTimeMilliseconds(dateModified).ToString(); 29 | } 30 | 31 | public bool Equals(AssemblyInformationRecord other) => FileName == other.FileName && FileVersion == other.FileVersion && ProductVersion == other.ProductVersion && DateModified == other.DateModified; 32 | 33 | public override bool Equals(object obj) => obj is AssemblyInformationRecord other && Equals(other); 34 | 35 | public override int GetHashCode() 36 | { 37 | unchecked 38 | { 39 | var hashCode = (FileName != null ? FileName.GetHashCode() : 0); 40 | hashCode = (hashCode * 397) ^ (FileVersion != null ? FileVersion.GetHashCode() : 0); 41 | hashCode = (hashCode * 397) ^ (ProductVersion != null ? ProductVersion.GetHashCode() : 0); 42 | hashCode = (hashCode * 397) ^ DateModified.GetHashCode(); 43 | return hashCode; 44 | } 45 | } 46 | 47 | public override string ToString() => $"{nameof(FileName)}: {FileName}, {nameof(FileVersion)}: {FileVersion}, {nameof(ProductVersion)}: {ProductVersion}, {nameof(DateModified)}: {DateModified}"; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ProcedureInformation.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Hdf5Attributes(new[] { "General information of the procedure" })] 8 | [Hdf5GroupName("procedure_information")] 9 | public class ProcedureInformation : Hdf5BaseFile, IEquatable 10 | { 11 | [Hdf5EntryName("procedure_directory")] 12 | public string ProcedureDirectory { get; set; } 13 | [Hdf5("the type of procedure")] 14 | [Hdf5EntryName("procedure_type")] 15 | public string ProcedureType { get; set; } 16 | [Hdf5EntryName("start_datetime")] 17 | public DateTime StartDateTime { get; set; } 18 | [Hdf5EntryName("end_datetime")] 19 | public DateTime EndDateTime { get; set; } 20 | [Hdf5EntryName("procedure_id")] 21 | public string ProcedureID { get; set; } 22 | 23 | public ProcedureInformation(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "procedure_information", logger) 24 | { 25 | ProcedureDirectory = string.Empty; 26 | ProcedureType = string.Empty; 27 | } 28 | 29 | public ProcedureInformation() 30 | { 31 | 32 | } 33 | 34 | public bool Equals(ProcedureInformation other) 35 | { 36 | if (ReferenceEquals(null, other)) 37 | { 38 | return false; 39 | } 40 | 41 | if (ReferenceEquals(this, other)) 42 | { 43 | return true; 44 | } 45 | 46 | return ProcedureDirectory == other.ProcedureDirectory && ProcedureType == other.ProcedureType && 47 | StartDateTime.EqualsUpToMilliseconds(other.StartDateTime) && EndDateTime.EqualsUpToMilliseconds(other.EndDateTime) && 48 | ProcedureID == other.ProcedureID; 49 | 50 | } 51 | 52 | public override bool Equals(object obj) 53 | { 54 | if (ReferenceEquals(null, obj)) 55 | { 56 | return false; 57 | } 58 | 59 | if (ReferenceEquals(this, obj)) 60 | { 61 | return true; 62 | } 63 | 64 | if (obj.GetType() != this.GetType()) 65 | { 66 | return false; 67 | } 68 | 69 | return Equals((ProcedureInformation)obj); 70 | } 71 | 72 | public override int GetHashCode() 73 | { 74 | return (ProcedureDirectory.GetHashCode() * 397) ^ (ProcedureType.GetHashCode() * 397) ^ 75 | (StartDateTime.GetHashCode() * 397) ^ (EndDateTime.GetHashCode() * 397) ^ 76 | (ProcedureID.GetHashCode() * 397); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/EventGroup.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace HDF5CSharp.Example.DataTypes 8 | { 9 | [Hdf5GroupName("events")] 10 | public class EventGroup : Hdf5BaseFile, IDisposable 11 | { 12 | 13 | private Hdf5Events events; 14 | [Hdf5Save(Hdf5Save.DoNotSave)] private List SystemEventSamplesData { get; set; } 15 | [Hdf5Save(Hdf5Save.DoNotSave)] private bool record; 16 | public EventGroup(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "events", logger) 17 | { 18 | SystemEventSamplesData = new List(); 19 | // SystemEvents = new ChunkedDataset("system_events", GroupId); 20 | // UserTags = new ChunkedDataset("user_tags", GroupId); 21 | // SystemTaskWriter = Task.Factory.StartNew(() => 22 | //{ 23 | 24 | // completed = false; 25 | // foreach (SystemEvent data in SystemEventSamplesData.GetConsumingEnumerable()) 26 | // { 27 | // SystemEvent[,] events = new SystemEvent[1, 1]; 28 | // events[0, 0] = data; 29 | // SystemEvents.AppendOrCreateDataset(events); 30 | // } 31 | // Flush(); //end of data sample. flush data 32 | //}); 33 | } 34 | 35 | 36 | public void Dispose() 37 | { 38 | try 39 | { 40 | if (!Disposed) 41 | { 42 | Hdf5.CloseGroup(GroupId); 43 | } 44 | 45 | } 46 | catch (Exception) 47 | { 48 | //nothing 49 | } 50 | } 51 | 52 | public void Enqueue(SystemEventModel systemEvent) 53 | { 54 | 55 | if (record) 56 | { 57 | SystemEvent hdf5SystemEvent = new SystemEvent(systemEvent.TimeStamp, systemEvent.SystemEventType.ToString(), "", systemEvent.EventData); 58 | SystemEventSamplesData.Add(hdf5SystemEvent); 59 | } 60 | } 61 | 62 | 63 | public Task WaitForDataWritten() 64 | { 65 | record = false; 66 | Logger.LogInformation("Start write of system events"); 67 | events = new Hdf5Events(SystemEventSamplesData); 68 | var status = Hdf5.WriteObject(GroupId, events); 69 | Logger.LogInformation("End write of system events with status " + status); 70 | return Task.CompletedTask; 71 | } 72 | 73 | public void StopRecording() => record = false; 74 | 75 | public void StartLogging() => record = true; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 11 * * 5' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: windows-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['csharp'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # .NET Desktop 2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'windows-latest' 11 | 12 | variables: 13 | solution: '**/*.sln' 14 | buildPlatform: 'Any CPU' 15 | buildConfiguration: 'Release' 16 | 17 | steps: 18 | - task: NuGetToolInstaller@1 19 | 20 | - task: NuGetCommand@2 21 | inputs: 22 | restoreSolution: '$(solution)' 23 | 24 | - task: VSBuild@1 25 | inputs: 26 | solution: '$(solution)' 27 | platform: '$(buildPlatform)' 28 | configuration: '$(buildConfiguration)' 29 | 30 | # Run all tests with "/p:CollectCoverage=true /p:CoverletOutputFormat=cobertura" to generate the code coverage file 31 | - task: DotNetCoreCLI@2 32 | displayName: dotnet test 33 | inputs: 34 | command: test 35 | arguments: '--configuration $(BuildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura' 36 | projects: 'HDF5-CSharp.Example.UnitTest/*.csproj' 37 | 38 | 39 | - task: DotNetCoreCLI@2 40 | displayName: dotnet test 41 | inputs: 42 | command: test 43 | arguments: '--configuration $(BuildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura' 44 | projects: 'HDF5-CSharp.UnitTests/*.csproj' 45 | 46 | # Generate the report using ReportGenerator (https://github.com/danielpalme/ReportGenerator) 47 | # First install the tool on the machine, then run it 48 | - script: | 49 | dotnet tool install -g dotnet-reportgenerator-globaltool 50 | reportgenerator -reports:$(Build.SourcesDirectory)/HDF5-CSharp.Example.UnitTest/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/CodeCoverage -reporttypes:HtmlInline_AzurePipelines;Cobertura 51 | displayName: Create Code coverage report example project 52 | 53 | 54 | # Generate the report using ReportGenerator (https://github.com/danielpalme/ReportGenerator) 55 | # First install the tool on the machine, then run it 56 | - script: | 57 | dotnet tool install -g dotnet-reportgenerator-globaltool 58 | reportgenerator -reports:$(Build.SourcesDirectory)/HDF5-CSharp.UnitTests/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/CodeCoverage -reporttypes:HtmlInline_AzurePipelines;Cobertura 59 | displayName: Create Code coverage report 60 | 61 | 62 | 63 | 64 | # Publish the code coverage result (summary and web site) 65 | # The summary allows to view the coverage percentage in the summary tab 66 | # The web site allows to view which lines are covered directly in Azure Pipeline 67 | - task: PublishCodeCoverageResults@1 68 | displayName: 'Publish code coverage' 69 | inputs: 70 | codeCoverageTool: Cobertura 71 | summaryFileLocation: '$(Build.SourcesDirectory)/CodeCoverage/Cobertura.xml' 72 | reportDirectory: '$(Build.SourcesDirectory)/CodeCoverage' 73 | -------------------------------------------------------------------------------- /HDF5-CSharp/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace HDF5CSharp.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HDF5CSharp.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /HDF5-CSharp/DataTypes/DataTypes.cs: -------------------------------------------------------------------------------- 1 | using HDF.PInvoke; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace HDF5CSharp.DataTypes 6 | { 7 | public enum Hdf5ElementType 8 | { 9 | Unknown = 0, 10 | Group, 11 | Dataset, 12 | Attribute 13 | } 14 | public abstract class Hdf5ElementBase 15 | { 16 | public string Name { get; set; } 17 | public Hdf5ElementType Type { get; set; } 18 | public bool IsLazyLoading { get; } 19 | 20 | public Hdf5ElementBase Parent { get; set; } 21 | public long Id { get; set; } 22 | protected bool HasLoadedOnce { get; set; } 23 | public abstract string GetPath(); 24 | public abstract string GetDisplayName(); 25 | public abstract IEnumerable GetChildren(); 26 | protected abstract long GetId(long fileId); 27 | protected abstract void CloseId(long id); 28 | 29 | public Hdf5ElementBase(string name, Hdf5ElementType type, Hdf5ElementBase parent,long id, bool isLazyLoading) 30 | { 31 | Name = name; 32 | Type = type; 33 | Parent = parent; 34 | IsLazyLoading = isLazyLoading; 35 | Id = id; 36 | } 37 | 38 | public override string ToString() => $"{nameof(Name)}: {Name} ({Type}) ID:{Id}"; 39 | } 40 | 41 | public class Hdf5Element : Hdf5ElementBase 42 | { 43 | private List Children { get; } 44 | public Hdf5Element(string name, Hdf5ElementType type, Hdf5ElementBase parent, long id, bool isLazyLoading) : base(name, type, parent,id, isLazyLoading) 45 | { 46 | Children = new List(); 47 | } 48 | 49 | public bool HasChildren => Children.Any(); 50 | 51 | public override string GetPath() 52 | { 53 | return Name; 54 | } 55 | 56 | public override string GetDisplayName() 57 | { 58 | return Name; 59 | } 60 | 61 | public override IEnumerable GetChildren() 62 | { 63 | return Children.ToList(); 64 | } 65 | 66 | protected override long GetId(long fileId) 67 | { 68 | return H5G.open(fileId, GetPath()); 69 | } 70 | 71 | protected override void CloseId(long id) 72 | { 73 | if (H5I.is_valid(id) > 0) 74 | { 75 | H5G.close(id); 76 | } 77 | } 78 | 79 | public void AddChild(Hdf5Element child) 80 | { 81 | Children.Add(child); 82 | } 83 | 84 | public Hdf5Element GetChildWithName(string childName) 85 | { 86 | var child = Children.FirstOrDefault(c => c.Name == childName); 87 | if (child != null) 88 | { 89 | return child; 90 | } 91 | 92 | var subChildren = Children.Where(c => c.HasChildren).Select(c => c.GetChildWithName(childName)); 93 | return subChildren.FirstOrDefault(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Hdf5DotnetWrapper.Viewer.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Hdf5DotnetWrapper.Viewer.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/Patient.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Serializable] 8 | [Hdf5GroupName("patient")] 9 | public class Patient : Hdf5BaseFile, IDisposable, IEquatable 10 | { 11 | [Hdf5EntryName("first_name")] 12 | public string FirstName { get; set; } 13 | [Hdf5EntryName("last_name")] 14 | public string LastName { get; set; } 15 | public string Id { get; set; } 16 | 17 | public string Gender { get; set; } 18 | public float Age { get; set; } 19 | public double Height { get; set; } 20 | public double Weight { get; set; } 21 | [Hdf5EntryName("exam_date")] 22 | public DateTime ExamDate { get; set; } 23 | 24 | public Patient(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "patient", logger) 25 | { 26 | FirstName = string.Empty; 27 | LastName = string.Empty; 28 | Id = string.Empty; 29 | Gender = string.Empty; 30 | 31 | } 32 | public Patient() 33 | { 34 | 35 | } 36 | 37 | public void Dispose() 38 | { 39 | try 40 | { 41 | if (!Disposed) 42 | { 43 | Hdf5.CloseGroup(GroupId); 44 | Disposed = true; 45 | } 46 | } 47 | catch (Exception e) 48 | { 49 | Logger?.LogError($"Error closing file: {e}"); 50 | } 51 | 52 | } 53 | 54 | public bool Equals(Patient other) 55 | { 56 | if (ReferenceEquals(null, other)) 57 | { 58 | return false; 59 | } 60 | 61 | if (ReferenceEquals(this, other)) 62 | { 63 | return true; 64 | } 65 | 66 | return FirstName == other.FirstName && LastName == other.LastName && Id == other.Id && 67 | Gender == other.Gender && Age.Equals(other.Age) && Height.Equals(other.Height) && 68 | Weight.Equals(other.Weight) && ExamDate.EqualsUpToMilliseconds(other.ExamDate); 69 | } 70 | 71 | public override bool Equals(object obj) 72 | { 73 | if (ReferenceEquals(null, obj)) 74 | { 75 | return false; 76 | } 77 | 78 | if (ReferenceEquals(this, obj)) 79 | { 80 | return true; 81 | } 82 | 83 | if (obj.GetType() != this.GetType()) 84 | { 85 | return false; 86 | } 87 | 88 | return Equals((Patient)obj); 89 | } 90 | 91 | public override int GetHashCode() 92 | { 93 | return (FirstName.GetHashCode() * 397) ^ (LastName.GetHashCode() * 397) ^ (Id.GetHashCode() * 397) ^ 94 | (Gender.GetHashCode() * 397) ^ (Age.GetHashCode() * 397) ^ (Height.GetHashCode() * 397) ^ 95 | (Weight.GetHashCode() * 397) ^ (ExamDate.GetHashCode() * 397); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/Hdf5GroupTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using HDF.PInvoke; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | 7 | namespace HDF5CSharp.UnitTests.Core 8 | { 9 | public partial class Hdf5UnitTests 10 | { 11 | [TestMethod] 12 | public void WriteAndReadGroupsWithDataset() 13 | { 14 | string filename = Path.Combine(folder, "testGroups.H5"); 15 | 16 | try 17 | { 18 | var fileId = Hdf5.CreateFile(filename); 19 | Assert.IsTrue(fileId > 0); 20 | var dset = dsets.First(); 21 | 22 | var groupId = H5G.create(fileId, Hdf5Utils.NormalizedName("/A")); ///B/C/D/E/F/G/H 23 | Hdf5.WriteDataset(groupId, Hdf5Utils.NormalizedName("test"), dset); 24 | var subGroupId = Hdf5.CreateOrOpenGroup(groupId, Hdf5Utils.NormalizedName("C")); 25 | var subGroupId2 = Hdf5.CreateOrOpenGroup(groupId, Hdf5Utils.NormalizedName("/D")); // will be saved at the root location 26 | dset = dsets.Skip(1).First(); 27 | Hdf5.WriteDataset(subGroupId, Hdf5Utils.NormalizedName("test2"), dset); 28 | Hdf5.CloseGroup(subGroupId); 29 | Hdf5.CloseGroup(subGroupId2); 30 | Hdf5.CloseGroup(groupId); 31 | groupId = H5G.create(fileId, Hdf5Utils.NormalizedName("/A/B")); ///B/C/D/E/F/G/H 32 | dset = dsets.Skip(1).First(); 33 | Hdf5.WriteDataset(groupId, Hdf5Utils.NormalizedName("test"), dset); 34 | Hdf5.CloseGroup(groupId); 35 | 36 | groupId = Hdf5.CreateGroupRecursively(fileId, Hdf5Utils.NormalizedName("A/B/C/D/E/F/I")); 37 | Hdf5.CloseGroup(groupId); 38 | Hdf5.CloseFile(fileId); 39 | 40 | 41 | fileId = Hdf5.OpenFile(filename); 42 | Assert.IsTrue(fileId > 0); 43 | fileId = Hdf5.OpenFile(filename); 44 | 45 | groupId = H5G.open(fileId, Hdf5Utils.NormalizedName("/A/B")); 46 | double[,] dset2 = (double[,])Hdf5.ReadDataset(groupId, Hdf5Utils.NormalizedName( "test")).result; 47 | CompareDatasets(dset, dset2); 48 | Assert.IsTrue(Hdf5.CloseGroup(groupId) >= 0); 49 | groupId = H5G.open(fileId, Hdf5Utils.NormalizedName("/A/C")); 50 | dset2 = (double[,])Hdf5.ReadDataset(groupId, Hdf5Utils.NormalizedName("test2")).result; 51 | CompareDatasets(dset, dset2); 52 | Assert.IsTrue(Hdf5.CloseGroup(groupId) >= 0); 53 | bool same = dset == dset2; 54 | dset = dsets.First(); 55 | dset2 = (double[,])Hdf5.ReadDataset(fileId, Hdf5Utils.NormalizedName("/A/test")).result; 56 | CompareDatasets(dset, dset2); 57 | Assert.IsTrue(Hdf5Utils.ItemExists(fileId, Hdf5Utils.NormalizedName( "A/B/C/D/E/F/I"),DataTypes.Hdf5ElementType.Dataset)); 58 | 59 | Assert.IsTrue(Hdf5.CloseFile(fileId) == 0); 60 | 61 | } 62 | catch (Exception ex) 63 | { 64 | CreateExceptionAssert(ex); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-core-desktop.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core Desktop 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | strategy: 14 | matrix: 15 | configuration: [Release, Debug] 16 | 17 | runs-on: windows-latest # For a list of available runner types, refer to 18 | # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on 19 | 20 | env: 21 | Solution_Name: HDF5-CSharp.sln # Replace with your solution name, i.e. MyWpfApp.sln. 22 | Test_Project_Path: HDF5-CSharp.UnitTests\HDF5-CSharp.UnitTests.csproj # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj. 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v2 27 | with: 28 | fetch-depth: 0 29 | 30 | # Install the .NET Core workload 31 | - name: Install .NET Core 32 | uses: actions/setup-dotnet@v1 33 | with: 34 | dotnet-version: 3.1.101 35 | 36 | # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild 37 | - name: Setup MSBuild.exe 38 | uses: microsoft/setup-msbuild@v1.0.2 39 | 40 | # Restore the application to populate the obj folder with RuntimeIdentifiers 41 | - name: Restore the application 42 | run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration 43 | env: 44 | Configuration: ${{ matrix.configuration }} 45 | 46 | # Buid the application 47 | - name: Build the application 48 | run: msbuild $env:Solution_Name /t:Rebuild /p:Configuration=$env:Configuration 49 | env: 50 | Configuration: ${{ matrix.configuration }} 51 | # Execute all unit tests in the solution 52 | - name: Execute unit tests 53 | run: dotnet test 54 | 55 | # Publish Artifacts 56 | - name: 'Publish Artifacts' 57 | uses: actions/upload-artifact@v1.0.0 58 | with: 59 | name: 'artifactory' 60 | path: ./HDF5-CSharp/bin/${{ matrix.configuration }} 61 | push-nuget: 62 | name: 'Push NuGet Packages' 63 | needs: build 64 | runs-on: windows-latest 65 | steps: 66 | - name: 'Download Artifact' 67 | uses: actions/download-artifact@v1 68 | with: 69 | name: 'artifactory' 70 | - name: 'Dotnet NuGet Push' 71 | run: | 72 | Get-ChildItem .\artifactory -Filter *.nupkg | 73 | Where-Object { !$_.Name.Contains('preview') } | 74 | ForEach-Object { dotnet nuget push $_ --source https://api.nuget.org/v3/index.json --skip-duplicate --api-key ${{secrets.NUGET_API_KEY}} } 75 | shell: pwsh 76 | 77 | - name: Setup NuGet.exe for use with actions 78 | uses: NuGet/setup-nuget@v1.0.5 79 | 80 | - name: Add private GitHub registry to NuGet 81 | run: nuget sources add -name "GPR" -Source https://nuget.pkg.github.com/LiorBanai/index.json -Username LiorBanai -Password ${{ secrets.GITHUB_TOKEN }} 82 | 83 | - name: 'Dotnet NuGet Push to github registry' 84 | run: | 85 | Get-ChildItem .\artifactory -Filter *.nupkg | 86 | Where-Object { !$_.Name.Contains('preview') } | 87 | ForEach-Object { nuget push $_ -Source "GPR" -SkipDuplicate } 88 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/SystemEventGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using HDF5CSharp.DataTypes; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace HDF5CSharp.Example.DataTypes 11 | { 12 | public class Hdf5SystemEvents 13 | { 14 | [Hdf5EntryName("system_events")] public SystemEvent[] Events { get; set; } 15 | public Hdf5SystemEvents(List eventsData) 16 | { 17 | Events = eventsData.ToArray(); 18 | } 19 | 20 | public Hdf5SystemEvents() 21 | { 22 | 23 | } 24 | } 25 | public class SystemEventGroup : Hdf5BaseFile, IDisposable 26 | { 27 | [Hdf5Save(Hdf5Save.DoNotSave)] private ReaderWriterLockSlim LockSlim { get; } 28 | [Hdf5Save(Hdf5Save.DoNotSave)] private List SystemEventSamplesData { get; set; } 29 | [Hdf5Save(Hdf5Save.DoNotSave)] private bool record; 30 | public SystemEventGroup(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "events", logger) 31 | { 32 | SystemEventSamplesData = new List(); 33 | LockSlim = new ReaderWriterLockSlim(); 34 | } 35 | 36 | 37 | public void Dispose() 38 | { 39 | try 40 | { 41 | if (!Disposed) 42 | { 43 | Hdf5.CloseGroup(GroupId); 44 | } 45 | 46 | } 47 | catch (Exception e) 48 | { 49 | Logger.LogError(e, $"Error closing System Event group: {e.Message}"); 50 | } 51 | } 52 | 53 | public void Enqueue(SystemEventModel systemEvent) 54 | { 55 | 56 | if (record) 57 | { 58 | SystemEvent hdf5SystemEvent = new SystemEvent(systemEvent.TimeStamp, systemEvent.SystemEventType.ToString(), "", systemEvent.EventData); 59 | LockSlim.EnterWriteLock(); 60 | SystemEventSamplesData.Add(hdf5SystemEvent); 61 | LockSlim.ExitWriteLock(); 62 | } 63 | } 64 | 65 | 66 | public Task WaitForDataWritten() 67 | { 68 | try 69 | { 70 | 71 | record = false; 72 | LockSlim.EnterWriteLock(); 73 | if (!SystemEventSamplesData.Any()) 74 | { 75 | 76 | Logger.LogWarning("No system events to write to H5 file"); 77 | return Task.CompletedTask; 78 | } 79 | 80 | var dataToWrite = SystemEventSamplesData; 81 | SystemEventSamplesData = new List(); 82 | Logger.LogInformation("Start write of system events"); 83 | Hdf5SystemEvents events = new Hdf5SystemEvents(dataToWrite); 84 | var status = Hdf5.WriteObject(GroupRoot, events, Constants.EventGroupName); 85 | Logger.LogInformation("End write of system events with status " + status); 86 | return Task.CompletedTask; 87 | } 88 | finally 89 | { 90 | LockSlim.ExitWriteLock(); 91 | 92 | 93 | } 94 | } 95 | 96 | public void StopRecording() => record = false; 97 | 98 | public void StartLogging() => record = true; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ECGData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using HDF5CSharp.DataTypes; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | public class ECGData : IEquatable 8 | { 9 | 10 | [Hdf5EntryName("start_datetime")] public DateTime StartDateTime { get; set; } 11 | [Hdf5EntryName("end_datetime")] public DateTime EndDateTime { get; set; } 12 | [Hdf5EntryName("sampling_rate")] public int SamplingRate { get; set; } 13 | [Hdf5EntryName("Signals_unfiltered")] public double[,] UnfilteredSignal { get; set; } 14 | [Hdf5EntryName("Signals_filtered")] public double[,] FilteredSignal { get; set; } 15 | [Hdf5EntryName("timestamps")] public long[,] Timestamps { get; set; } 16 | [Hdf5EntryName("packetids")] public long[,] PacketIds { get; set; } 17 | [Hdf5EntryName("kalpaclocks")] public long[,] KalpaClocks { get; set; } 18 | 19 | public ECGData() 20 | { 21 | Timestamps = new long[0, 0]; 22 | FilteredSignal = new double[0, 0]; 23 | UnfilteredSignal = new double[0, 0]; 24 | PacketIds = new long[0, 0]; 25 | KalpaClocks = new long[0, 0]; 26 | } 27 | 28 | public bool Equals(ECGData other) 29 | { 30 | if (ReferenceEquals(null, other)) 31 | { 32 | return false; 33 | } 34 | 35 | if (ReferenceEquals(this, other)) 36 | { 37 | return true; 38 | } 39 | 40 | return StartDateTime.EqualsUpToMilliseconds(other.StartDateTime) && 41 | EndDateTime.EqualsUpToMilliseconds(other.EndDateTime) && 42 | SamplingRate == other.SamplingRate && 43 | 44 | 45 | UnfilteredSignal.Rank == other.UnfilteredSignal.Rank && 46 | Enumerable.Range(0, UnfilteredSignal.Rank).All(dimension => 47 | UnfilteredSignal.GetLength(dimension) == other.UnfilteredSignal.GetLength(dimension)) && 48 | UnfilteredSignal.Cast().SequenceEqual(other.UnfilteredSignal.Cast()) && 49 | 50 | FilteredSignal.Rank == other.FilteredSignal.Rank && 51 | Enumerable.Range(0, FilteredSignal.Rank).All(dimension => 52 | FilteredSignal.GetLength(dimension) == other.FilteredSignal.GetLength(dimension)) && 53 | FilteredSignal.Cast().SequenceEqual(other.FilteredSignal.Cast()) && 54 | Timestamps.Rank == other.Timestamps.Rank && 55 | Enumerable.Range(0, Timestamps.Rank).All(dimension => 56 | Timestamps.GetLength(dimension) == other.Timestamps.GetLength(dimension)) && 57 | Timestamps.Cast().SequenceEqual(other.Timestamps.Cast()); 58 | } 59 | 60 | public override bool Equals(object obj) 61 | { 62 | if (ReferenceEquals(null, obj)) 63 | { 64 | return false; 65 | } 66 | 67 | if (ReferenceEquals(this, obj)) 68 | { 69 | return true; 70 | } 71 | 72 | if (obj.GetType() != this.GetType()) 73 | { 74 | return false; 75 | } 76 | 77 | return Equals((ECGData)obj); 78 | } 79 | 80 | public override int GetHashCode() 81 | { 82 | return (StartDateTime.GetHashCode() * 397) ^ (EndDateTime.GetHashCode() * 397) ^ (SamplingRate * 397); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/systemEvent.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using System; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | public enum SystemEventType 8 | { 9 | NewV2RModelReady = 0, 10 | NewMeshReady = 1, 11 | Saturation = 2, 12 | MissAlignment = 3, 13 | PAQConnectionError = 4, 14 | PAQConnectionOk = 5, 15 | PAQHardwareConnectionError = 6, 16 | PAQHardwareConnectionOk = 7, 17 | Dummy = 8, 18 | ECGCycleDescription = 9, 19 | SheathDetected = 10, 20 | LeakAnalysis = 11, 21 | NetworkAvailabilityOn, 22 | NetworkAvailabilityOff, 23 | ECGBodyLeadConnected, 24 | ECGBodyLeadDisconnected, 25 | FreeSpace 26 | } 27 | 28 | public class SystemEventModel : IEquatable 29 | { 30 | public SystemEventType SystemEventType { get; set; } 31 | public long TimeStamp { get; set; } 32 | public string EventData { get; set; } 33 | 34 | public SystemEventModel() 35 | { 36 | EventData = string.Empty; 37 | } 38 | 39 | public SystemEventModel(SystemEventType systemEventType, long timeStamp, string eventData) 40 | { 41 | SystemEventType = systemEventType; 42 | TimeStamp = timeStamp; 43 | EventData = eventData; 44 | } 45 | 46 | public bool Equals(SystemEventModel other) 47 | { 48 | if (ReferenceEquals(null, other)) 49 | { 50 | return false; 51 | } 52 | 53 | if (ReferenceEquals(this, other)) 54 | { 55 | return true; 56 | } 57 | 58 | return SystemEventType == other.SystemEventType && TimeStamp == other.TimeStamp && EventData == other.EventData; 59 | } 60 | 61 | public override bool Equals(object obj) 62 | { 63 | if (ReferenceEquals(null, obj)) 64 | { 65 | return false; 66 | } 67 | 68 | if (ReferenceEquals(this, obj)) 69 | { 70 | return true; 71 | } 72 | 73 | if (obj.GetType() != GetType()) 74 | { 75 | return false; 76 | } 77 | 78 | return Equals((SystemEvent)obj); 79 | } 80 | 81 | public override int GetHashCode() 82 | { 83 | unchecked 84 | { 85 | var hashCode = (int)SystemEventType; 86 | hashCode = (hashCode * 397) ^ TimeStamp.GetHashCode(); 87 | hashCode = (hashCode * 397) ^ (EventData != null ? EventData.GetHashCode() : 0); 88 | return hashCode; 89 | } 90 | } 91 | } 92 | 93 | [StructLayout(LayoutKind.Sequential)] 94 | public struct SystemEvent 95 | { 96 | [Hdf5EntryName("timestamp")] public long timestamp; 97 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 98 | [Hdf5EntryName("type")] public string type; 99 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 100 | [Hdf5EntryName("description")] public string description; 101 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 102 | [Hdf5EntryName("data")] public string data; 103 | public SystemEvent(long timestamp, string type, string description, string data) 104 | { 105 | this.timestamp = timestamp; 106 | this.type = type; 107 | this.description = description; 108 | this.data = data; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/Hdf5ObjectTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.IO; 4 | 5 | namespace HDF5CSharp.UnitTests.Core 6 | { 7 | public partial class Hdf5UnitTests 8 | { 9 | [TestMethod] 10 | public void WriteAndReadObjectWithPropertiesTest() 11 | { 12 | string filename = Path.Combine(folder, "testObjects.H5"); 13 | try 14 | { 15 | testClass.TestInteger = 2; 16 | testClass.TestDouble = 1.1; 17 | testClass.TestBoolean = true; 18 | testClass.TestString = "test string"; 19 | // 31-Oct-2003, 18:00 is 731885.75 in matlab 20 | testClass.TestTime = new DateTime(2003, 10, 31, 18, 0, 0); 21 | 22 | var fileId = Hdf5.CreateFile(filename); 23 | Assert.IsTrue(fileId > 0); 24 | 25 | Hdf5.WriteObject(fileId, testClass, "objectWithProperties"); 26 | Hdf5.CloseFile(fileId); 27 | } 28 | catch (Exception ex) 29 | { 30 | CreateExceptionAssert(ex); 31 | } 32 | 33 | try 34 | { 35 | var fileId = Hdf5.OpenFile(filename); 36 | Assert.IsTrue(fileId > 0); 37 | 38 | TestClass readObject = new TestClass(); 39 | readObject = Hdf5.ReadObject(fileId, readObject, "objectWithProperties"); 40 | Assert.IsTrue(testClass.Equals(readObject)); 41 | 42 | readObject = Hdf5.ReadObject(fileId, "objectWithProperties"); 43 | Assert.IsTrue(testClass.Equals(readObject)); 44 | 45 | Assert.IsTrue(Hdf5.CloseFile(fileId) >= 0); 46 | } 47 | catch (Exception ex) 48 | { 49 | CreateExceptionAssert(ex); 50 | } 51 | } 52 | 53 | [TestMethod] 54 | public void WriteAndReadObjectWithPropertiesAndArrayPropertyTest() 55 | { 56 | try 57 | { 58 | testClassWithArrays.TestInteger = 2; 59 | testClassWithArrays.TestDouble = 1.1; 60 | testClassWithArrays.TestBoolean = true; 61 | testClassWithArrays.TestString = "test string"; 62 | testClassWithArrays.TestDoubles = new[] { 1.1, 1.2, -1.1, -1.2 }; 63 | testClassWithArrays.TestStrings = new[] { "one", "two", "three", "four" }; 64 | testClassWithArrays.testDoublesField = new[] { 1.1, 1.2, -1.1, -1.2 }; 65 | testClassWithArrays.testStringsField = new[] { "one", "two", "three", "four" }; 66 | string filename = Path.Combine(folder, "testArrayObjects.H5"); 67 | 68 | var fileId = Hdf5.CreateFile(filename); 69 | Assert.IsTrue(fileId >= 0); 70 | 71 | Hdf5.WriteObject(fileId, testClassWithArrays, "objectWithTwoArrays"); 72 | 73 | TestClassWithArray readObject = new TestClassWithArray 74 | { 75 | TestStrings = new string[0], 76 | TestDoubles = null, 77 | TestDouble = double.NaN 78 | }; 79 | 80 | readObject = Hdf5.ReadObject(fileId, readObject, "objectWithTwoArrays"); 81 | Assert.IsTrue(testClassWithArrays.Equals(readObject)); 82 | 83 | readObject = Hdf5.ReadObject(fileId, "objectWithTwoArrays"); 84 | Assert.IsTrue(testClassWithArrays.Equals(readObject)); 85 | 86 | Assert.IsTrue(Hdf5.CloseFile(fileId) >= 0); 87 | } 88 | catch (Exception ex) 89 | { 90 | CreateExceptionAssert(ex); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /HDF5-CSharp/HDF5-CSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | HDF5CSharp 6 | HDF5CSharp 7 | false 8 | false 9 | Hdf5DotNetTools.snk 10 | AnyCPU;x86;x64 11 | SciSharp.Keras.HDF5 12 | SciSharp STACK 13 | 14 | SciSharp.Keras.HDF5 15 | C# Wrapper for HDF.PInvoke Library 16 | Apache 2.0, SciSharp STACK @2021 17 | MIT 18 | https://github.com/SciSharp/HDF5-CSharp 19 | https://avatars3.githubusercontent.com/u/44989469?s=200&v=4 20 | https://github.com/SciSharp/HDF5-CSharp 21 | git 22 | Dependents on HDF.PInvoke.1.10.500 23 | true 24 | 1.1.10.500 25 | true 26 | false 27 | snupkg 28 | 29 | false 30 | true 31 | 32 | 33 | 34 | DEBUG;TRACE;TRACE,HDF5_VER1_10 35 | 36 | 37 | 38 | TRACE;TRACE,HDF5_VER1_10 39 | 40 | 41 | 42 | TRACE;TRACE,HDF5_VER1_10 43 | 44 | 45 | 46 | TRACE;TRACE,HDF5_VER1_10 47 | 48 | 49 | 50 | TRACE;TRACE,HDF5_VER1_10 51 | 52 | 53 | 54 | TRACE;TRACE,HDF5_VER1_10 55 | 56 | 57 | 58 | 59 | 60 | all 61 | runtime; build; native; contentfiles; analyzers; buildtransitive 62 | 63 | 64 | all 65 | runtime; build; native; contentfiles; analyzers; buildtransitive 66 | 67 | 68 | 69 | 70 | 71 | 72 | True 73 | True 74 | Resources.resx 75 | 76 | 77 | 78 | 79 | 80 | ResXFileCodeGenerator 81 | Resources.Designer.cs 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/RPositionGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using HDF5CSharp.DataTypes; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace HDF5CSharp.Example.DataTypes 11 | { 12 | public class Hdf5RPositionEvents 13 | { 14 | [Hdf5EntryName("rposition_events")] public RPositionEvent[] Events { get; set; } 15 | public Hdf5RPositionEvents(List eventsData) 16 | { 17 | Events = eventsData.ToArray(); 18 | } 19 | 20 | public Hdf5RPositionEvents() 21 | { 22 | 23 | } 24 | } 25 | public class RPositionGroup : Hdf5BaseFile, IDisposable 26 | { 27 | [Hdf5Save(Hdf5Save.DoNotSave)] private ReaderWriterLockSlim LockSlim { get; } 28 | [Hdf5Save(Hdf5Save.DoNotSave)] private List RPositionSamplesData { get; set; } 29 | [Hdf5Save(Hdf5Save.DoNotSave)] private bool record; 30 | 31 | public RPositionGroup(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "events", logger) 32 | { 33 | RPositionSamplesData = new List(); 34 | LockSlim = new ReaderWriterLockSlim(); 35 | } 36 | 37 | public void Dispose() 38 | { 39 | try 40 | { 41 | if (!Disposed) 42 | { 43 | Hdf5.CloseGroup(GroupId); 44 | } 45 | 46 | } 47 | catch (Exception e) 48 | { 49 | Logger.LogError(e, $"Error closing RPosition group: {e.Message}"); 50 | } 51 | } 52 | 53 | 54 | public void Enqueue(RPositionsMessagePack rPosition) 55 | { 56 | 57 | if (record) 58 | { 59 | var positions = rPosition.NavigationData.SelectMany(r => 60 | r.Points.Select(p => new RPositionEvent(rPosition.Timestamp, r.Name, p.x, p.y, p.z, r.Trajectory.x, r.Trajectory.y, r.Trajectory.z))).ToList(); 61 | try 62 | { 63 | LockSlim.EnterWriteLock(); 64 | RPositionSamplesData.AddRange(positions); 65 | } 66 | catch (Exception e) 67 | { 68 | Logger.LogError(e, $"Error adding RPosition: {e.Message}"); 69 | } 70 | finally 71 | { 72 | LockSlim.ExitWriteLock(); 73 | } 74 | 75 | } 76 | } 77 | 78 | 79 | public Task WaitForDataWritten() 80 | { 81 | try 82 | { 83 | record = false; 84 | LockSlim.EnterWriteLock(); 85 | if (!RPositionSamplesData.Any()) 86 | { 87 | Logger.LogWarning("No R Position events to write to H5 file"); 88 | return Task.CompletedTask; 89 | } 90 | var dataToWrite = RPositionSamplesData; 91 | RPositionSamplesData = new List(); 92 | Logger.LogInformation("Start write of RPosition events"); 93 | Hdf5RPositionEvents events = new Hdf5RPositionEvents(dataToWrite); 94 | var status = Hdf5.WriteObject(GroupRoot, events, Constants.EventGroupName); 95 | Logger.LogInformation("End write of RPosition with status " + status); 96 | } 97 | catch (Exception e) 98 | { 99 | Logger.LogError(e, $"Error writing RPosition Events: {e.Message}"); 100 | } 101 | finally 102 | { 103 | LockSlim.ExitWriteLock(); 104 | } 105 | return Task.CompletedTask; 106 | } 107 | 108 | 109 | 110 | public void StopRecording() => record = false; 111 | 112 | public void StartLogging() => record = true; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/PatientsContainer.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace HDF5CSharp.Example.DataTypes 8 | { 9 | [Serializable] 10 | [Hdf5GroupName("patients")] 11 | public class PatientsContainer : Hdf5BaseFile, IDisposable, IEquatable 12 | { 13 | [Hdf5EntryName("ManyPatients")] public List Patients { get; set; } 14 | [Hdf5EntryName("ManyPatientsField")] public List PatientsField; 15 | public PatientsContainer() 16 | { 17 | 18 | } 19 | public PatientsContainer(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "patients", 20 | logger) 21 | { 22 | Patients = new List(); 23 | Patients.Add(new Patient[] 24 | { 25 | new Patient() 26 | { 27 | Age = 20, ExamDate = DateTime.Now.AddDays(-10), FirstName = "first1", Gender = "F", Height = 1.65, 28 | Id = "000", LastName = "last1", Weight = 60 29 | }, 30 | new Patient() 31 | { 32 | Age = 20, ExamDate = DateTime.Now.AddDays(-10), FirstName = "first2", Gender = "M", Height = 1.85, 33 | Id = "111", LastName = "last2", Weight = 90 34 | }, 35 | }); 36 | 37 | PatientsField = new List(); 38 | PatientsField.Add(new Patient[] 39 | { 40 | new Patient() 41 | { 42 | Age = 20, ExamDate = DateTime.Now.AddDays(-10), FirstName = "first1", Gender = "F", Height = 1.65, 43 | Id = "000", LastName = "last1", Weight = 60 44 | }, 45 | new Patient() 46 | { 47 | Age = 20, ExamDate = DateTime.Now.AddDays(-10), FirstName = "first2", Gender = "M", Height = 1.85, 48 | Id = "111", LastName = "last2", Weight = 90 49 | }, 50 | }); 51 | } 52 | 53 | public void Dispose() 54 | { 55 | try 56 | { 57 | if (!Disposed) 58 | { 59 | Hdf5.CloseGroup(GroupId); 60 | Disposed = true; 61 | } 62 | } 63 | catch (Exception e) 64 | { 65 | Logger?.LogError($"Error closing file: {e}"); 66 | } 67 | 68 | } 69 | 70 | public bool Equals(PatientsContainer other) 71 | { 72 | if (ReferenceEquals(null, other)) 73 | { 74 | return false; 75 | } 76 | 77 | if (ReferenceEquals(this, other)) 78 | { 79 | return true; 80 | } 81 | 82 | for (var i = 0; i < Patients.Count; i++) 83 | { 84 | var p = Patients[i]; 85 | if (!p.SequenceEqual(other.Patients[i])) 86 | { 87 | return false; 88 | } 89 | } 90 | for (var i = 0; i < PatientsField.Count; i++) 91 | { 92 | var p = PatientsField[i]; 93 | if (!p.SequenceEqual(other.PatientsField[i])) 94 | { 95 | return false; 96 | } 97 | } 98 | return true; 99 | } 100 | 101 | public override bool Equals(object obj) 102 | { 103 | if (ReferenceEquals(null, obj)) 104 | { 105 | return false; 106 | } 107 | 108 | if (ReferenceEquals(this, obj)) 109 | { 110 | return true; 111 | } 112 | 113 | if (obj.GetType() != this.GetType()) 114 | { 115 | return false; 116 | } 117 | 118 | return Equals((PatientsContainer)obj); 119 | } 120 | 121 | public override int GetHashCode() => (Patients != null ? Patients.GetHashCode() : 0); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/Hdf5StringsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | 7 | namespace HDF5CSharp.UnitTests.Core 8 | { 9 | public partial class Hdf5UnitTests 10 | { 11 | 12 | [TestMethod] 13 | public void WriteAndReadOneString() 14 | { 15 | try 16 | { 17 | string[] str = new[] { "test" }; 18 | 19 | string filename = Path.Combine(folder, "testOneStringList.H5"); 20 | 21 | 22 | // Open file and write the strings 23 | var fileId = Hdf5.CreateFile(filename); 24 | Assert.IsTrue(fileId > 0); 25 | Hdf5.WriteStrings(fileId, "/test", str); 26 | 27 | // Read the strings and close file 28 | Assert.IsTrue(fileId > 0); 29 | IEnumerable strs2 = Hdf5.ReadStrings(fileId, "/test", "").result; 30 | Assert.IsTrue(strs2.Count() == 1); 31 | foreach (var s in strs2) 32 | { 33 | Assert.IsTrue(str[0] == s); 34 | }; 35 | 36 | Hdf5.CloseFile(fileId); 37 | } 38 | catch (Exception ex) 39 | { 40 | CreateExceptionAssert(ex); 41 | } 42 | } 43 | 44 | [TestMethod] 45 | public void WriteAndReadListOfStrings() 46 | { 47 | try 48 | { 49 | List strs = new List 50 | { 51 | "t", 52 | "tst", 53 | "test1", 54 | "small test" 55 | }; 56 | 57 | string filename = Path.Combine(folder, "testStringList.H5"); 58 | 59 | 60 | // Open file and write the strings 61 | var fileId = Hdf5.CreateFile(filename); 62 | Assert.IsTrue(fileId > 0); 63 | Hdf5.WriteStrings(fileId, "/test", strs); 64 | 65 | // Read the strings and close file 66 | Assert.IsTrue(fileId > 0); 67 | IEnumerable strs2 = Hdf5.ReadStrings(fileId, "/test", "").result; 68 | Assert.IsTrue(strs.Count() == strs2.Count()); 69 | foreach (var item in strs2.Select((str, i) => new { i, str })) 70 | { 71 | Assert.IsTrue(item.str == strs[item.i]); 72 | } 73 | 74 | Hdf5.CloseFile(fileId); 75 | } 76 | catch (Exception ex) 77 | { 78 | CreateExceptionAssert(ex); 79 | } 80 | } 81 | 82 | [TestMethod] 83 | public void WriteAndReadOneAsciiString() 84 | { 85 | try 86 | { 87 | string test = "This is a test string"; 88 | string filename = Path.Combine(folder, "testOneString.H5"); 89 | 90 | 91 | var fileId = Hdf5.CreateFile(filename); 92 | Hdf5.WriteAsciiString(fileId, "/test", test); 93 | Assert.IsTrue(Hdf5.CloseFile(fileId) == 0); 94 | 95 | fileId = Hdf5.OpenFile(filename); 96 | string readStr = Hdf5.ReadAsciiString(fileId, "/test"); 97 | Assert.IsTrue(test == readStr); 98 | Assert.IsTrue(Hdf5.CloseFile(fileId) == 0); 99 | } 100 | catch (Exception ex) 101 | { 102 | CreateExceptionAssert(ex); 103 | } 104 | } 105 | 106 | [TestMethod] 107 | public void WriteAndReadOneUnicodeString() 108 | { 109 | try 110 | { 111 | string test = "Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο"; 112 | string filename = Path.Combine(folder, "testUnicodeString.H5"); 113 | 114 | 115 | var fileId = Hdf5.CreateFile(filename); 116 | Hdf5.WriteUnicodeString(fileId, "/test", test); 117 | Assert.IsTrue(Hdf5.CloseFile(fileId) >= 0); 118 | 119 | 120 | fileId = Hdf5.OpenFile(filename); 121 | string readStr = Hdf5.ReadUnicodeString(fileId, "/test"); 122 | //var readStr = Hdf5.ReadStrings(fileId, "/test"); 123 | Assert.IsTrue(test == readStr); 124 | Assert.IsTrue(Hdf5.CloseFile(fileId) >= 0); 125 | } 126 | catch (Exception ex) 127 | { 128 | CreateExceptionAssert(ex); 129 | } 130 | } 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/ECGCycleDescription.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace HDF5CSharp.Example.DataTypes 6 | { 7 | [Serializable] 8 | public struct ECGCycleDescription 9 | { 10 | //QRS 11 | public double StartOfQRSAmplitude;//QRS onset amplitude 12 | public double EndOfQRSAmplitude; //QRS offset amplitude 13 | public double RPeakAmplitude; //R-Peak amplitude 14 | //P-Peak 15 | public double StartOfPWaveAmplitude;//P-wave onset amplitude 16 | public double EndOfPWaveAmplitude; //P-wave offset amplitude 17 | public double PPeakAmplitude; //P-Peak amplitude 18 | //T-wave 19 | public double StartOfTWaveAmplitude;//T-wave onset amplitude 20 | public double EndOfTWaveAmplitude; //T-wave offset amplitude 21 | public double TPeakAmplitude; //T-Peak amplitude 22 | //Internal 23 | //A 24 | public byte IsAPeakExist;//0 - false; >0 - true 25 | public double APeakAmplitude;//A-peak amplitude [mkV] 26 | //V 27 | public byte IsVPeakExist;//0 - false; >0 - true 28 | public double VPeakAmplitude;//V-peak amplitude [mkV] 29 | 30 | public byte IsLumenMarkerExist; //0 - false; >0 - true 31 | public Int32 LumenPosition; //Lumen market position. 32 | 33 | 34 | public long TimestampStartOfQRSInterval; 35 | public long TimestampEndOfQRSInterval; 36 | public long TimestampRPeak; 37 | public long TimestampStartOfPWaveInterval; 38 | public long TimestampEndOfPWaveInterval; 39 | public long TimestampPPeak; 40 | public long TimestampAPeak; 41 | public long TimestampVPeak; 42 | public long TimestampTPeak; 43 | public long CurrentTimestamp; 44 | 45 | 46 | public ECGCycleDescription(ECGCycleDescription marshelledData, long currentTimestamp, double samplingRate, long currentIndex, int shiftBS, int shiftIC) 47 | { 48 | CurrentTimestamp = currentTimestamp; 49 | StartOfQRSAmplitude = marshelledData.StartOfQRSAmplitude; 50 | EndOfQRSAmplitude = marshelledData.EndOfQRSAmplitude; 51 | RPeakAmplitude = marshelledData.RPeakAmplitude; 52 | StartOfPWaveAmplitude = marshelledData.StartOfPWaveAmplitude; 53 | EndOfPWaveAmplitude = marshelledData.EndOfPWaveAmplitude; 54 | PPeakAmplitude = marshelledData.PPeakAmplitude; 55 | StartOfTWaveAmplitude = marshelledData.StartOfTWaveAmplitude; 56 | EndOfTWaveAmplitude = 0; 57 | TPeakAmplitude = marshelledData.TPeakAmplitude; 58 | IsAPeakExist = marshelledData.IsAPeakExist; 59 | APeakAmplitude = marshelledData.APeakAmplitude; 60 | IsVPeakExist = marshelledData.IsVPeakExist; 61 | VPeakAmplitude = marshelledData.VPeakAmplitude; 62 | TimestampStartOfQRSInterval = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftBS); 63 | TimestampEndOfQRSInterval = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftBS); 64 | TimestampRPeak = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftBS); 65 | TimestampStartOfPWaveInterval = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftBS); 66 | TimestampEndOfPWaveInterval = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftBS); 67 | TimestampPPeak = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftBS); 68 | TimestampAPeak = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftIC); 69 | TimestampVPeak = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftIC); 70 | //todo: check calculation 71 | TimestampTPeak = ConvertIndexToTimestamp(0, currentTimestamp, samplingRate, currentIndex, shiftIC); 72 | IsLumenMarkerExist = marshelledData.IsLumenMarkerExist; 73 | LumenPosition = marshelledData.LumenPosition; 74 | } 75 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 76 | private static long ConvertIndexToTimestamp(int relevantIndex, long currentTimestamp, double samplingRate, long currentIndex, int shift) 77 | { 78 | return (long)(currentTimestamp - (currentIndex - relevantIndex - shift) * samplingRate); 79 | } 80 | 81 | public string AsJson() => JsonConvert.SerializeObject(this); 82 | public static ECGCycleDescription FromJson(string jsonData) => JsonConvert.DeserializeObject(jsonData); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/HDF5-CSharp.Viewer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {47201833-E346-46E1-B3F3-3B137B8BEB0D} 8 | WinExe 9 | Hdf5DotnetWrapper.Viewer 10 | Hdf5DotnetWrapper.Viewer 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Form 52 | 53 | 54 | Form1.cs 55 | 56 | 57 | UserControl 58 | 59 | 60 | HDF5FileLoader.cs 61 | 62 | 63 | 64 | 65 | Form1.cs 66 | 67 | 68 | HDF5FileLoader.cs 69 | 70 | 71 | ResXFileCodeGenerator 72 | Resources.Designer.cs 73 | Designer 74 | 75 | 76 | True 77 | Resources.resx 78 | 79 | 80 | SettingsSingleFileGenerator 81 | Settings.Designer.cs 82 | 83 | 84 | True 85 | Settings.settings 86 | True 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | {7e7b1235-2d9c-4696-9ffb-cf7e14c7202a} 95 | HDF5-CSharp 96 | 97 | 98 | 99 | 100 | 1.10.610 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /HDF5-CSharp/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | text/microsoft-resx 91 | 92 | 93 | 1.3 94 | 95 | 96 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 97 | 98 | 99 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 100 | 101 | -------------------------------------------------------------------------------- /HDF5-CSharp.UnitTests/TestUtilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace HDF5CSharp.UnitTests.Core 7 | { 8 | public static class UtilsExtensions 9 | { 10 | /// 11 | /// Compares each property of an object with the fields of another object to see if they are the same 12 | /// 13 | /// generic class type 14 | /// The object to compare 15 | /// The second object 16 | /// names of fields to ignore 17 | /// 18 | public static bool PublicInstancePropertiesEqual(this T self, T to, params string[] ignore) where T : class 19 | { 20 | var equal = false; 21 | if (self != null && to != null) 22 | { 23 | var type = typeof(T); 24 | var ignoreList = new List(ignore); 25 | var unequalProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance). 26 | Where(pi => !ignoreList.Contains(pi.Name)); 27 | foreach (var pi in unequalProperties) 28 | { 29 | var selfValue = type.GetField(pi.Name).GetValue(self); 30 | var toValue = type.GetField(pi.Name).GetValue(to); 31 | Type selfType = selfValue.GetType(); 32 | TypeCode code = Type.GetTypeCode(selfType); 33 | if (code == TypeCode.DateTime) 34 | { 35 | if (DateTime.Compare((DateTime)selfValue, (DateTime)toValue) != 0) 36 | { 37 | return false; 38 | } 39 | } 40 | 41 | if (selfType == typeof(TimeSpan)) 42 | { 43 | if (TimeSpan.Compare((TimeSpan)selfValue, (TimeSpan)toValue) != 0) 44 | { 45 | return false; 46 | } 47 | } 48 | 49 | if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))) 50 | { 51 | return false; 52 | } 53 | } 54 | equal = true; 55 | } 56 | return equal; 57 | } 58 | 59 | /// 60 | /// Compares each field of an object with the fields of another object to see if they are the same 61 | /// 62 | /// generic class type 63 | /// The object to compare 64 | /// The second object 65 | /// names of fields to ignore 66 | /// 67 | public static bool PublicInstanceFieldsEqual(this T self, T to, params string[] ignore) where T : class 68 | { 69 | var equal = false; 70 | if (self != null && to != null) 71 | { 72 | var type = typeof(T); 73 | var ignoreList = new List(ignore); 74 | var unequalProperties = type.GetFields(BindingFlags.Public | BindingFlags.Instance). 75 | Where(pi => !ignoreList.Contains(pi.Name)); 76 | foreach (var pi in unequalProperties) 77 | { 78 | var selfValue = type.GetField(pi.Name).GetValue(self); 79 | var toValue = type.GetField(pi.Name).GetValue(to); 80 | Type selfType = selfValue.GetType(); 81 | TypeCode code = Type.GetTypeCode(selfType); 82 | if (code == TypeCode.DateTime) 83 | { 84 | if (DateTime.Compare((DateTime)selfValue, (DateTime)toValue) != 0) 85 | { 86 | return false; 87 | } 88 | } 89 | 90 | if (selfType == typeof(TimeSpan)) 91 | { 92 | if (TimeSpan.Compare((TimeSpan)selfValue, (TimeSpan)toValue) != 0) 93 | { 94 | return false; 95 | } 96 | } 97 | 98 | if (selfValue != toValue && (!selfValue.Equals(toValue))) 99 | { 100 | return false; 101 | } 102 | } 103 | equal = true; 104 | } 105 | return equal; 106 | } 107 | } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/HDF5FileLoader.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Hdf5DotnetWrapper.Viewer 2 | { 3 | partial class HDF5FileLoader 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label18 = new System.Windows.Forms.Label(); 32 | this.txtbHDF5 = new System.Windows.Forms.TextBox(); 33 | this.btnHDF5ReadFile = new System.Windows.Forms.Button(); 34 | this.btnHDF5Browse = new System.Windows.Forms.Button(); 35 | this.SuspendLayout(); 36 | // 37 | // label18 38 | // 39 | this.label18.AutoSize = true; 40 | this.label18.Location = new System.Drawing.Point(15, 8); 41 | this.label18.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); 42 | this.label18.Name = "label18"; 43 | this.label18.Size = new System.Drawing.Size(74, 18); 44 | this.label18.TabIndex = 10; 45 | this.label18.Text = "HDF5 File:"; 46 | // 47 | // txtbHDF5 48 | // 49 | this.txtbHDF5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 50 | | System.Windows.Forms.AnchorStyles.Right))); 51 | this.txtbHDF5.Location = new System.Drawing.Point(97, 4); 52 | this.txtbHDF5.Margin = new System.Windows.Forms.Padding(4); 53 | this.txtbHDF5.Name = "txtbHDF5"; 54 | this.txtbHDF5.Size = new System.Drawing.Size(539, 26); 55 | this.txtbHDF5.TabIndex = 11; 56 | this.txtbHDF5.Text = "D:\\Data\\9_pig.h5"; 57 | // 58 | // btnHDF5ReadFile 59 | // 60 | this.btnHDF5ReadFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 61 | this.btnHDF5ReadFile.Location = new System.Drawing.Point(722, 1); 62 | this.btnHDF5ReadFile.Margin = new System.Windows.Forms.Padding(4); 63 | this.btnHDF5ReadFile.Name = "btnHDF5ReadFile"; 64 | this.btnHDF5ReadFile.Size = new System.Drawing.Size(100, 32); 65 | this.btnHDF5ReadFile.TabIndex = 13; 66 | this.btnHDF5ReadFile.Text = "Load Data"; 67 | this.btnHDF5ReadFile.UseVisualStyleBackColor = true; 68 | this.btnHDF5ReadFile.Click += new System.EventHandler(this.btnHDF5ReadFile_Click); 69 | // 70 | // btnHDF5Browse 71 | // 72 | this.btnHDF5Browse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 73 | this.btnHDF5Browse.Location = new System.Drawing.Point(644, 1); 74 | this.btnHDF5Browse.Margin = new System.Windows.Forms.Padding(4); 75 | this.btnHDF5Browse.Name = "btnHDF5Browse"; 76 | this.btnHDF5Browse.Size = new System.Drawing.Size(69, 32); 77 | this.btnHDF5Browse.TabIndex = 12; 78 | this.btnHDF5Browse.Text = "Browse"; 79 | this.btnHDF5Browse.UseVisualStyleBackColor = true; 80 | this.btnHDF5Browse.Click += new System.EventHandler(this.btnHDF5Browse_Click); 81 | // 82 | // HDF5FileLoader 83 | // 84 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 18F); 85 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 86 | this.Controls.Add(this.label18); 87 | this.Controls.Add(this.txtbHDF5); 88 | this.Controls.Add(this.btnHDF5ReadFile); 89 | this.Controls.Add(this.btnHDF5Browse); 90 | this.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 91 | this.Name = "HDF5FileLoader"; 92 | this.Size = new System.Drawing.Size(826, 550); 93 | this.ResumeLayout(false); 94 | this.PerformLayout(); 95 | 96 | } 97 | 98 | #endregion 99 | 100 | private System.Windows.Forms.Label label18; 101 | private System.Windows.Forms.TextBox txtbHDF5; 102 | private System.Windows.Forms.Button btnHDF5ReadFile; 103 | private System.Windows.Forms.Button btnHDF5Browse; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /HDF5-CSharp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29519.87 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HDF5-CSharp", "HDF5-CSharp\HDF5-CSharp.csproj", "{7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HDF5-CSharp.Example", "HDF5-CSharp.Example\HDF5-CSharp.Example.csproj", "{5555E266-9088-4DC1-B281-F7E859CDC412}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HDF5-CSharp.Example.UnitTest", "HDF5-CSharp.Example.UnitTest\HDF5-CSharp.Example.UnitTest.csproj", "{B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HDF5-CSharp.UnitTests", "HDF5-CSharp.UnitTests\HDF5-CSharp.UnitTests.csproj", "{D8396F76-47C8-4519-A288-4519A17C3620}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Debug|x64.ActiveCfg = Debug|x64 27 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Debug|x64.Build.0 = Debug|x64 28 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Debug|x86.ActiveCfg = Debug|x86 29 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Debug|x86.Build.0 = Debug|x86 30 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Release|x64.ActiveCfg = Release|x64 33 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Release|x64.Build.0 = Release|x64 34 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Release|x86.ActiveCfg = Release|x86 35 | {7E7B1235-2D9C-4696-9FFB-CF7E14C7202A}.Release|x86.Build.0 = Release|x86 36 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Debug|x64.ActiveCfg = Debug|Any CPU 39 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Debug|x64.Build.0 = Debug|Any CPU 40 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Debug|x86.ActiveCfg = Debug|Any CPU 41 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Debug|x86.Build.0 = Debug|Any CPU 42 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Release|x64.ActiveCfg = Release|Any CPU 45 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Release|x64.Build.0 = Release|Any CPU 46 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Release|x86.ActiveCfg = Release|Any CPU 47 | {5555E266-9088-4DC1-B281-F7E859CDC412}.Release|x86.Build.0 = Release|Any CPU 48 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Debug|x64.ActiveCfg = Debug|Any CPU 51 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Debug|x64.Build.0 = Debug|Any CPU 52 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Debug|x86.ActiveCfg = Debug|Any CPU 53 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Debug|x86.Build.0 = Debug|Any CPU 54 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Release|x64.ActiveCfg = Release|Any CPU 57 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Release|x64.Build.0 = Release|Any CPU 58 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Release|x86.ActiveCfg = Release|Any CPU 59 | {B773FD82-8EAF-4BA2-93BC-6B44AFDFDF8D}.Release|x86.Build.0 = Release|Any CPU 60 | {D8396F76-47C8-4519-A288-4519A17C3620}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {D8396F76-47C8-4519-A288-4519A17C3620}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {D8396F76-47C8-4519-A288-4519A17C3620}.Debug|x64.ActiveCfg = Debug|Any CPU 63 | {D8396F76-47C8-4519-A288-4519A17C3620}.Debug|x64.Build.0 = Debug|Any CPU 64 | {D8396F76-47C8-4519-A288-4519A17C3620}.Debug|x86.ActiveCfg = Debug|Any CPU 65 | {D8396F76-47C8-4519-A288-4519A17C3620}.Debug|x86.Build.0 = Debug|Any CPU 66 | {D8396F76-47C8-4519-A288-4519A17C3620}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {D8396F76-47C8-4519-A288-4519A17C3620}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {D8396F76-47C8-4519-A288-4519A17C3620}.Release|x64.ActiveCfg = Release|Any CPU 69 | {D8396F76-47C8-4519-A288-4519A17C3620}.Release|x64.Build.0 = Release|Any CPU 70 | {D8396F76-47C8-4519-A288-4519A17C3620}.Release|x86.ActiveCfg = Release|Any CPU 71 | {D8396F76-47C8-4519-A288-4519A17C3620}.Release|x86.Build.0 = Release|Any CPU 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(ExtensibilityGlobals) = postSolution 77 | SolutionGuid = {FF170207-E294-49AB-96B4-37ACC61A6217} 78 | EndGlobalSection 79 | EndGlobal 80 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/KamaAcquisitionReadOnlyFile.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.Example.DataTypes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace HDF5CSharp.Example 7 | { 8 | public class KamaAcquisitionReadOnlyFile : IDisposable 9 | { 10 | public string FileName { get; } 11 | public ProcedureInformation ProcedureInformation { get; set; } 12 | public SystemInformation SystemInformation { get; set; } 13 | public Patient PatientInformation { get; set; } 14 | public ECGData ECG { get; set; } 15 | public List EITs { get; set; } 16 | public List Events { get; set; } 17 | public bool HasEIT => EITs.Any(); 18 | private long fileId; 19 | private string rootName = "/"; 20 | private string rootNameOld = "/root"; 21 | private string system_informationName = "/system_information"; 22 | private string procedure_informationName = "/procedure_information"; 23 | private string patient_informationName = "/patient"; 24 | private string ecgName = "/ecg"; 25 | private string eitName = "/eit"; 26 | private string eventsName = "/events/system_events"; 27 | private bool fileClosed; 28 | 29 | public KamaAcquisitionReadOnlyFile(string filename) 30 | { 31 | FileName = filename; 32 | ProcedureInformation = new ProcedureInformation(); 33 | SystemInformation = new SystemInformation(); 34 | PatientInformation = new Patient(); 35 | ECG = new ECGData(); 36 | EITs = new List(); 37 | Events = new List(); 38 | Hdf5.Settings.LowerCaseNaming = true; 39 | Hdf5.Settings.DateTimeType = DateTimeType.UnixTimeMilliseconds; 40 | fileId = Hdf5.OpenFile(filename); 41 | } 42 | 43 | public void ReadSystemInformation() 44 | { 45 | string groupName = rootName + system_informationName; 46 | if (Hdf5.GroupExists(fileId, groupName)) 47 | { 48 | SystemInformation = Hdf5.ReadObject(fileId, groupName); 49 | return; 50 | } 51 | groupName = rootNameOld + system_informationName; 52 | if (Hdf5.GroupExists(fileId, groupName)) 53 | { 54 | SystemInformation = Hdf5.ReadObject(fileId, groupName); 55 | } 56 | } 57 | public void ReadProcedureInformation() 58 | { 59 | string groupName = rootName + procedure_informationName; 60 | if (Hdf5.GroupExists(fileId, groupName)) 61 | { 62 | ProcedureInformation = Hdf5.ReadObject(fileId, groupName); 63 | return; 64 | } 65 | groupName = rootNameOld + procedure_informationName; 66 | if (Hdf5.GroupExists(fileId, groupName)) 67 | { 68 | ProcedureInformation = Hdf5.ReadObject(fileId, groupName); 69 | } 70 | } 71 | public void ReadPatientInformation() 72 | { 73 | string groupName = rootName + patient_informationName; 74 | if (Hdf5.GroupExists(fileId, groupName)) 75 | { 76 | PatientInformation = Hdf5.ReadObject(fileId, groupName); 77 | return; 78 | } 79 | groupName = rootNameOld + patient_informationName; 80 | if (Hdf5.GroupExists(fileId, groupName)) 81 | { 82 | PatientInformation = Hdf5.ReadObject(fileId, groupName); 83 | } 84 | } 85 | 86 | public void ReadECGData() 87 | { 88 | string groupName = rootName + ecgName; 89 | if (Hdf5.GroupExists(fileId, groupName)) 90 | { 91 | ECG = Hdf5.ReadObject(fileId, groupName); 92 | return; 93 | } 94 | groupName = rootNameOld + ecgName; 95 | if (Hdf5.GroupExists(fileId, groupName)) 96 | { 97 | ECG = Hdf5.ReadObject(fileId, groupName); 98 | } 99 | } 100 | public void ReadEITData() 101 | { 102 | 103 | int index = 1; 104 | string rootGroup = rootName + eitName; 105 | if (!Hdf5.GroupExists(fileId, rootGroup)) 106 | { 107 | rootGroup = rootNameOld + eitName; 108 | } 109 | 110 | while (Hdf5.GroupExists(fileId, rootGroup + "/d" + index)) 111 | { 112 | var entry = Hdf5.ReadObject(fileId, rootGroup + "/d" + index); 113 | EITs.Add(entry); 114 | index++; 115 | } 116 | } 117 | 118 | public void ReadSystemEvents() 119 | { 120 | string groupName = rootName + eventsName; 121 | if (Hdf5.GroupExists(fileId, groupName)) 122 | { 123 | var e = Hdf5.ReadCompounds(fileId, groupName, ""); 124 | Events.AddRange(e); 125 | } 126 | 127 | 128 | } 129 | 130 | public void Dispose() 131 | { 132 | if (!fileClosed) 133 | { 134 | Hdf5.CloseFile(fileId); 135 | fileClosed = true; 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/SystemInformation.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.NetworkInformation; 7 | using System.Net.Sockets; 8 | using System.Reflection; 9 | 10 | namespace HDF5CSharp.Example.DataTypes 11 | { 12 | [Hdf5GroupName("system_information")] 13 | public class SystemInformation : Hdf5BaseFile, IEquatable 14 | { 15 | [Hdf5EntryName("system_id")] public string SystemId { get; set; } 16 | [Hdf5EntryName("boards_id")] public string[] BoardIds { get; set; } 17 | [Hdf5EntryName("data_format_version")] public string DataFormatVersion { get; set; } 18 | [Hdf5EntryName("software_version")] public string SoftwareVersion { get; set; } 19 | [Hdf5EntryName("hdf5_version")] public string H5Version { get; set; } 20 | [Hdf5EntryName("hostname")] public string MachineName { get; set; } 21 | [Hdf5EntryName("mac_address")] public string MacAddress { get; set; } 22 | [Hdf5EntryName("ip_address")] public string IPAddress { get; set; } 23 | [Hdf5EntryName("assemblies_information")] public AssemblyInformationRecord[] Assemblies { get; set; } 24 | [Hdf5EntryName("system_type")] public string SystemType { get; set; } 25 | public SystemInformation(long fileId, long groupRoot, ILogger logger) : base(fileId, groupRoot, "system_information", logger) 26 | { 27 | Assemblies = new AssemblyInformationRecord[0]; 28 | SystemId = "N/A"; 29 | BoardIds = new[] { "N/A", "N/A" }; 30 | DataFormatVersion = "3.0"; //v3 - ecg format changes 31 | H5Version = "4.1"; //v4 - ecg format changes, V4.1: add System type 32 | SoftwareVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 33 | MachineName = Environment.MachineName; 34 | MacAddress = GetMacAddress(); 35 | IPAddress = GetLocalIPAddress(); 36 | SystemType = string.Empty; 37 | } 38 | 39 | 40 | public SystemInformation() 41 | { 42 | BoardIds = Array.Empty(); 43 | } 44 | 45 | private static string GetLocalIPAddress() 46 | { 47 | try 48 | { 49 | var host = Dns.GetHostEntry(Dns.GetHostName()); 50 | foreach (var ip in host.AddressList) 51 | { 52 | if (ip.AddressFamily == AddressFamily.InterNetwork) 53 | { 54 | return ip.ToString(); 55 | } 56 | } 57 | } 58 | catch (Exception) 59 | { 60 | return "0.0.0.0"; 61 | } 62 | 63 | return "0.0.0.0"; 64 | } 65 | 66 | /// 67 | /// Finds the MAC address of the NIC with maximum speed. 68 | /// 69 | /// The MAC address. 70 | private string GetMacAddress() 71 | { 72 | const int MIN_MAC_ADDR_LENGTH = 12; 73 | string macAddress = string.Empty; 74 | long maxSpeed = -1; 75 | 76 | foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) 77 | { 78 | string tempMac = nic.GetPhysicalAddress().ToString(); 79 | if (nic.Speed > maxSpeed && 80 | !string.IsNullOrEmpty(tempMac) && 81 | tempMac.Length >= MIN_MAC_ADDR_LENGTH) 82 | { 83 | maxSpeed = nic.Speed; 84 | macAddress = tempMac; 85 | } 86 | } 87 | 88 | return macAddress; 89 | } 90 | 91 | public bool Equals(SystemInformation other) 92 | { 93 | if (ReferenceEquals(null, other)) 94 | { 95 | return false; 96 | } 97 | 98 | if (ReferenceEquals(this, other)) 99 | { 100 | return true; 101 | } 102 | 103 | return SystemId == other.SystemId && BoardIds.SequenceEqual(other.BoardIds) && 104 | DataFormatVersion == other.DataFormatVersion && SoftwareVersion == other.SoftwareVersion && 105 | MachineName == other.MachineName && MacAddress == other.MacAddress && IPAddress == other.IPAddress && 106 | SystemType == other.SystemType; 107 | 108 | } 109 | 110 | public override bool Equals(object obj) 111 | { 112 | if (ReferenceEquals(null, obj)) 113 | { 114 | return false; 115 | } 116 | 117 | if (ReferenceEquals(this, obj)) 118 | { 119 | return true; 120 | } 121 | 122 | if (obj.GetType() != this.GetType()) 123 | { 124 | return false; 125 | } 126 | 127 | return Equals((SystemInformation)obj); 128 | } 129 | 130 | public override int GetHashCode() 131 | { 132 | 133 | return (SystemId.GetHashCode() * 397) ^ (DataFormatVersion.GetHashCode() * 397) ^ 134 | (SoftwareVersion.GetHashCode() * 397) ^ (MachineName.GetHashCode() * 397) ^ 135 | (MacAddress.GetHashCode() * 397) ^ (IPAddress.GetHashCode() * 397); 136 | } 137 | 138 | public override string ToString() => $"{nameof(SystemId)}: {SystemId}, {nameof(DataFormatVersion)}: {DataFormatVersion}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(MachineName)}: {MachineName}, {nameof(MacAddress)}: {MacAddress}, {nameof(IPAddress)}: {IPAddress}. {nameof(SystemType)}: {SystemType}"; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/EITEntry.cs: -------------------------------------------------------------------------------- 1 | using HDF5CSharp.DataTypes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace HDF5CSharp.Example.DataTypes 7 | { 8 | public class EITEntry : IEquatable 9 | { 10 | private IReadOnlyList _timestampsRaw; 11 | [Hdf5EntryName("configuration")] public string Configuration { get; set; } 12 | [Hdf5EntryName("start_datetime")] public DateTime StartDateTime { get; set; } 13 | [Hdf5EntryName("end_datetime")] public DateTime EndDateTime { get; set; } 14 | [Hdf5EntryName("voltages.re")] public float[,] VoltagesReal { get; set; } 15 | [Hdf5EntryName("voltages.im")] public float[,] VoltagesIm { get; set; } 16 | [Hdf5EntryName("currents.re")] public float[,] CurrentsReal { get; set; } 17 | [Hdf5EntryName("currents.im")] public float[,] CurrentsIm { get; set; } 18 | [Hdf5EntryName("saturations")] public ulong[,] Saturation { get; set; } 19 | [Hdf5EntryName("timestamps")] public long[,] Timestamps { get; set; } 20 | [Hdf5EntryName("packetids")] public ulong[,] PacketIds { get; set; } 21 | [Hdf5EntryName("kalpaclocks")] public ulong[,] KalpaClocks { get; set; } 22 | 23 | public EITEntry() 24 | { 25 | Configuration = string.Empty; 26 | _timestampsRaw = Array.Empty(); 27 | } 28 | 29 | public bool Equals(EITEntry other) 30 | { 31 | if (ReferenceEquals(null, other)) 32 | { 33 | return false; 34 | } 35 | 36 | if (ReferenceEquals(this, other)) 37 | { 38 | return true; 39 | } 40 | 41 | var equal = Configuration == other.Configuration && 42 | StartDateTime.EqualsUpToMilliseconds(other.StartDateTime) && 43 | EndDateTime.EqualsUpToMilliseconds(other.EndDateTime) && 44 | 45 | VoltagesReal.Rank == other.VoltagesReal.Rank && 46 | Enumerable.Range(0, VoltagesReal.Rank).All(dimension => 47 | VoltagesReal.GetLength(dimension) == other.VoltagesReal.GetLength(dimension)) && 48 | VoltagesReal.Cast().SequenceEqual(other.VoltagesReal.Cast()) && 49 | 50 | VoltagesIm.Rank == other.VoltagesIm.Rank && 51 | Enumerable.Range(0, VoltagesIm.Rank).All(dimension => 52 | VoltagesIm.GetLength(dimension) == other.VoltagesIm.GetLength(dimension)) && 53 | VoltagesIm.Cast().SequenceEqual(other.VoltagesIm.Cast()) && 54 | 55 | CurrentsReal.Rank == other.CurrentsReal.Rank && 56 | Enumerable.Range(0, VoltagesIm.Rank).All(dimension => 57 | CurrentsReal.GetLength(dimension) == other.CurrentsReal.GetLength(dimension)) && 58 | CurrentsReal.Cast().SequenceEqual(other.CurrentsReal.Cast()) && 59 | 60 | CurrentsIm.Rank == other.CurrentsIm.Rank && 61 | Enumerable.Range(0, CurrentsIm.Rank).All(dimension => 62 | CurrentsIm.GetLength(dimension) == other.CurrentsIm.GetLength(dimension)) && 63 | CurrentsIm.Cast().SequenceEqual(other.CurrentsIm.Cast()) && 64 | 65 | Saturation.Rank == other.Saturation.Rank && 66 | Enumerable.Range(0, Saturation.Rank).All(dimension => 67 | Saturation.GetLength(dimension) == other.Saturation.GetLength(dimension)) && 68 | Saturation.Cast().SequenceEqual(other.Saturation.Cast()) && 69 | 70 | 71 | Timestamps.Rank == other.Timestamps.Rank && 72 | Enumerable.Range(0, Timestamps.Rank).All(dimension => 73 | Timestamps.GetLength(dimension) == other.Timestamps.GetLength(dimension)) && 74 | Timestamps.Cast().SequenceEqual(other.Timestamps.Cast()); 75 | 76 | if (PacketIds != null && other.PacketIds != null) 77 | { 78 | equal = equal && PacketIds.Rank == other.PacketIds.Rank && 79 | Enumerable.Range(0, PacketIds.Rank).All(dimension => 80 | PacketIds.GetLength(dimension) == other.PacketIds.GetLength(dimension)) && 81 | PacketIds.Cast().SequenceEqual(other.PacketIds.Cast()); 82 | } 83 | if (KalpaClocks != null && other.KalpaClocks != null) 84 | { 85 | equal = equal && KalpaClocks.Rank == other.KalpaClocks.Rank && 86 | Enumerable.Range(0, KalpaClocks.Rank).All(dimension => 87 | KalpaClocks.GetLength(dimension) == other.KalpaClocks.GetLength(dimension)) && 88 | KalpaClocks.Cast().SequenceEqual(other.KalpaClocks.Cast()); 89 | 90 | } 91 | return equal; 92 | } 93 | 94 | public override bool Equals(object obj) 95 | { 96 | if (ReferenceEquals(null, obj)) 97 | { 98 | return false; 99 | } 100 | 101 | if (ReferenceEquals(this, obj)) 102 | { 103 | return true; 104 | } 105 | 106 | if (obj.GetType() != this.GetType()) 107 | { 108 | return false; 109 | } 110 | 111 | return Equals((EITEntry)obj); 112 | } 113 | 114 | public override int GetHashCode() 115 | { 116 | return (Configuration.GetHashCode() * 397) ^ (StartDateTime.GetHashCode() * 397) ^ 117 | (EndDateTime.GetHashCode() * 397); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /HDF5-CSharp/Hdf5AcquisitionWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using HDF.PInvoke; 7 | using HDF5CSharp.DataTypes; 8 | 9 | namespace HDF5CSharp 10 | { 11 | 12 | 13 | public class Hdf5AcquisitionFileWriter : IDisposable 14 | { 15 | long fileId; 16 | readonly string _groupName, _filename; 17 | ChunkedDataset dset; 18 | ulong _nrOfRecords, _sampleCount; 19 | long _groupId; 20 | 21 | // private readonly ReaderWriterLockSlim lock_ = new ReaderWriterLockSlim(); 22 | 23 | public Hdf5AcquisitionFileWriter(string filename, string groupName = "ROOT") 24 | { 25 | H5E.set_auto(H5E.DEFAULT, null, IntPtr.Zero); 26 | //lock_.EnterWriteLock(); 27 | _filename = filename; 28 | fileId = Hdf5.CreateFile(filename); 29 | _groupName = groupName; 30 | _groupId = Hdf5.CreateOrOpenGroup(fileId, Hdf5Utils.NormalizedName(_groupName)); 31 | 32 | Header = new Hdf5AcquisitionFile(); 33 | _nrOfRecords = 0; 34 | _sampleCount = 0; 35 | //lock_.ExitWriteLock(); 36 | 37 | } 38 | 39 | public void Dispose() 40 | { 41 | Dispose(true); 42 | GC.SuppressFinalize(this); 43 | FileClosed?.Invoke(this, new FileClosedArgs(_filename)); 44 | } 45 | 46 | protected virtual void Dispose(bool disposing) 47 | { 48 | if (disposing) 49 | { 50 | SaveHeader(); 51 | dset?.Dispose(); 52 | _groupId = Hdf5.CloseGroup(_groupId); 53 | fileId = Hdf5.CloseFile(fileId); 54 | } 55 | } 56 | 57 | public void SaveHeader() 58 | { 59 | //lock_.EnterWriteLock(); 60 | Trace.WriteLine($"saving file {Header.Patient.Name} samples: {_sampleCount}; fileId: {fileId}"); 61 | Header.Recording.EndTime = Header.Recording.StartTime + TimeSpan.FromSeconds(_sampleCount / Header.Recording.SampleRate); 62 | Header.Recording.NrOfSamples = _sampleCount; 63 | Header.EventListToEvents(); 64 | for (int i = 0; i < Header.Channels.Count(); i++) 65 | { 66 | Header.Channels[i].NrOfSamples = _sampleCount; 67 | } 68 | Trace.WriteLine($"writing file {Header.Patient.Name} groupId: {_groupId}; fileId: {fileId}"); 69 | Hdf5.WriteObject(_groupId, Header); 70 | //lock_.ExitWriteLock(); 71 | } 72 | 73 | /// 74 | /// Writes data to the hdf5 file. 75 | /// 76 | public void Write(IEnumerable signals) 77 | { 78 | //lock_.EnterWriteLock(); 79 | int cols = signals.Count(); 80 | if (cols == 0) 81 | { 82 | return; 83 | } 84 | 85 | int rows = signals.First().Length; 86 | if (rows == 0) 87 | { 88 | return; 89 | } 90 | //double sr = _header.Recording.SampleRate; 91 | 92 | var data = new short[rows, cols]; 93 | //var byteLength = rows * sizeof(short); 94 | int i = 0; 95 | foreach (var sig in signals) 96 | { 97 | for (int j = 0; j < rows; j++) 98 | { 99 | data[j, i] = Convert2Short(sig[j], i); 100 | } 101 | 102 | i++; 103 | } 104 | Write(data); 105 | //lock_.ExitWriteLock(); 106 | } 107 | 108 | /// 109 | /// Writes data asynchronously to the hdf5 file. 110 | /// 111 | public async void WriteAsync(IEnumerable signals) 112 | { 113 | Task writeTask = new Task(() => Write(signals)); 114 | writeTask.Start(); 115 | await writeTask; 116 | } 117 | 118 | /// 119 | /// Writes data to the hdf5 file. 120 | /// 121 | public void Write(short[,] data) 122 | { 123 | //lock_.EnterWriteLock(); 124 | if (_nrOfRecords == 0) 125 | { 126 | Header.Recording.StartTime = DateTime.Now; 127 | var dataName = "Data"; 128 | dset = new ChunkedDataset(dataName, _groupId, data); 129 | } 130 | else 131 | { 132 | dset.AppendDataset(data); 133 | } 134 | 135 | _sampleCount += (ulong)data.GetLongLength(0); 136 | _nrOfRecords++; 137 | //lock_.ExitWriteLock(); 138 | } 139 | 140 | /// 141 | /// Writes data asynchronously to the hdf5 file. 142 | /// 143 | public async void WriteAsync(short[,] data) 144 | { 145 | Task writeTask = new Task(() => Write(data)); 146 | writeTask.Start(); 147 | await writeTask; 148 | } 149 | 150 | public short Convert2Short(double val, int channelNr) 151 | { 152 | val = (val - Header.Channels[channelNr].Offset) / Header.Channels[channelNr].Amplification; 153 | //val = val * short.MaxValue; 154 | if (val > short.MaxValue) 155 | { 156 | val = short.MaxValue; 157 | } 158 | 159 | if (val < short.MinValue) 160 | { 161 | val = short.MinValue; 162 | } 163 | 164 | return Convert.ToInt16(Math.Round(val, MidpointRounding.AwayFromZero)); 165 | 166 | } 167 | 168 | public Hdf5AcquisitionFile Header { get; } 169 | 170 | public event EventHandler FileClosed; 171 | 172 | } 173 | 174 | 175 | } 176 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /HDF5-CSharp.Viewer/HDF5FileLoader.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /HDF5-CSharp.Example/DataTypes/RPositions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using MessagePack; 8 | using Newtonsoft.Json; 9 | using UnityEngine; 10 | namespace HDF5CSharp.Example.DataTypes 11 | { 12 | [Serializable] 13 | [MessagePackObject()] 14 | public class RPositionsMessagePack 15 | { 16 | [Key("timestamp")] public ulong Timestamp { get; set; } 17 | [Key("nav")] public List NavigationData { get; set; } 18 | 19 | public RPositionsMessagePack() 20 | { 21 | NavigationData = new List(); 22 | } 23 | 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static RPositionsMessagePack Deserialize(byte[] data) 26 | { 27 | try 28 | { 29 | return MessagePackSerializer.Deserialize(data); 30 | } 31 | catch (Exception e) 32 | { 33 | string path = $@"RPosition_Error_{DateTime.Now.Ticks}.bin"; 34 | File.WriteAllBytes(path, data); 35 | var fallback = RPositionsOld.Deserialize(data); 36 | RPositionsMessagePack msg = new RPositionsMessagePack(); 37 | msg.Timestamp = fallback.Timestamp; 38 | msg.NavigationData = new List(fallback.Data.Count); 39 | foreach (var rpos in fallback.Data) 40 | { 41 | msg.NavigationData.Add(new NavigationData { Name = rpos.Name, Points = rpos.Points.ToList() }); 42 | } 43 | return msg; 44 | } 45 | } 46 | 47 | public void AddNavigationData(NavigationData navData) => NavigationData.Add(navData); 48 | 49 | public string ToJson() => JsonConvert.SerializeObject(this); 50 | } 51 | [Serializable] 52 | [MessagePackObject()] 53 | public class NavigationData 54 | { 55 | [Key("name")] public string Name { get; set; } 56 | [Key("position")] public List Points { get; set; } 57 | [Key("trajectory")] public Vector3 Trajectory { get; set; } 58 | 59 | public NavigationData() 60 | { 61 | Points = new List(); 62 | } 63 | 64 | public void AddPoint(float x, float y, float z) => Points.Add(new Vector3(x, y, z)); 65 | } 66 | 67 | 68 | [Serializable] 69 | [MessagePackObject(keyAsPropertyName: false)] 70 | internal class RPositionsOld 71 | { 72 | [Key("timestamp")] internal ulong Timestamp { get; set; } 73 | 74 | [Key("nav")] //keys are coming from Python code 75 | //public Dictionary Data { get; set; } 76 | internal List Data; 77 | 78 | [IgnoreMember] public DateTime Time => DateTime.FromBinary(Convert.ToInt64(Timestamp)); 79 | 80 | //[IgnoreMember] 81 | //public string AsJson => JsonConvert.SerializeObject(this); 82 | internal static RPositionsOld Deserialize(byte[] data) => 83 | TranslateDictionary(MessagePackSerializer.Deserialize>(data)); 84 | 85 | 86 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 87 | private static RPositionsOld TranslateDictionary(Dictionary data) 88 | { 89 | 90 | IEnumerable<(string Key, object Value)> IterateOver(KeyValuePair item) 91 | { 92 | var key = string.Empty; 93 | if (item.Key is byte[] bytes) //pre python 3 it is byte array. can be removed post moving to 3 94 | { 95 | key = Encoding.Default.GetString(bytes); 96 | } 97 | else if (item.Key is string value) //python 3 is string 98 | { 99 | key = value; 100 | } 101 | 102 | object val = item.Value; 103 | if (val is Dictionary dic) 104 | { 105 | List<(string Key, object Value)> innerItems = new List<(string Key, object Value)>(0); 106 | foreach (KeyValuePair itm in dic) 107 | { 108 | innerItems.AddRange(IterateOver(itm).ToList()); 109 | 110 | } 111 | 112 | yield return (key, innerItems); 113 | } 114 | else 115 | { 116 | yield return (key, val); 117 | } 118 | } 119 | 120 | Dictionary result = new Dictionary(); 121 | foreach (KeyValuePair itm in data) 122 | { 123 | var converted = IterateOver(itm).ToList(); 124 | foreach ((string key, object value) in converted) 125 | { 126 | result.Add(key, value); 127 | } 128 | 129 | } 130 | 131 | RPositionsOld p = new RPositionsOld(); 132 | p.Timestamp = (ulong)result["timestamp"]; 133 | ///////////////////////////////////////////////////////// 134 | p.Data = (result["nav"] as List<(string, object)>) 135 | .Select(e => new RpositionsDataPoints(e.Item1, e.Item2 as object[])).ToList(); 136 | return p; 137 | } 138 | } 139 | 140 | [MessagePackObject(keyAsPropertyName: false)] 141 | [Serializable] 142 | internal class RpositionsDataPoints 143 | { 144 | [Key("name")] public string Name; 145 | [Key("points")] public List Points; 146 | 147 | public RpositionsDataPoints() 148 | { 149 | 150 | } 151 | 152 | public RpositionsDataPoints(string name, object[] points) 153 | { 154 | Name = name; 155 | Points = new List(); 156 | foreach (object[] p in points) 157 | { 158 | Points.Add(new Vector3(Convert.ToSingle(p[0]), Convert.ToSingle(p[1]), Convert.ToSingle(p[2]))); 159 | } 160 | 161 | 162 | } 163 | 164 | public RpositionsDataPoints(string name, List points) 165 | { 166 | Name = name; 167 | Points = points; 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | *.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.pfx 193 | *.publishsettings 194 | node_modules/ 195 | orleans.codegen.cs 196 | 197 | # Since there are multiple workflows, uncomment next line to ignore bower_components 198 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 199 | #bower_components/ 200 | 201 | # RIA/Silverlight projects 202 | Generated_Code/ 203 | 204 | # Backup & report files from converting an old project file 205 | # to a newer Visual Studio version. Backup files are not needed, 206 | # because we have git ;-) 207 | _UpgradeReport_Files/ 208 | Backup*/ 209 | UpgradeLog*.XML 210 | UpgradeLog*.htm 211 | 212 | # SQL Server files 213 | *.mdf 214 | *.ldf 215 | 216 | # Business Intelligence projects 217 | *.rdl.data 218 | *.bim.layout 219 | *.bim_*.settings 220 | 221 | # Microsoft Fakes 222 | FakesAssemblies/ 223 | 224 | # GhostDoc plugin setting file 225 | *.GhostDoc.xml 226 | 227 | # Node.js Tools for Visual Studio 228 | .ntvs_analysis.dat 229 | 230 | # Visual Studio 6 build log 231 | *.plg 232 | 233 | # Visual Studio 6 workspace options file 234 | *.opt 235 | 236 | # Visual Studio LightSwitch build output 237 | **/*.HTMLClient/GeneratedArtifacts 238 | **/*.DesktopClient/GeneratedArtifacts 239 | **/*.DesktopClient/ModelManifest.xml 240 | **/*.Server/GeneratedArtifacts 241 | **/*.Server/ModelManifest.xml 242 | _Pvt_Extensions 243 | 244 | # Paket dependency manager 245 | .paket/paket.exe 246 | paket-files/ 247 | 248 | # FAKE - F# Make 249 | .fake/ 250 | 251 | # JetBrains Rider 252 | .idea/ 253 | *.sln.iml 254 | 255 | # Windows image file caches 256 | Thumbs.db 257 | ehthumbs.db 258 | 259 | # Folder config file 260 | Desktop.ini 261 | 262 | # Recycle Bin used on file shares 263 | $RECYCLE.BIN/ 264 | 265 | # Windows Installer files 266 | *.cab 267 | *.msi 268 | *.msm 269 | *.msp 270 | 271 | # Windows shortcuts 272 | *.lnk 273 | 274 | # ========================= 275 | # Operating System Files 276 | # ========================= 277 | 278 | # OSX 279 | # ========================= 280 | 281 | .DS_Store 282 | .AppleDouble 283 | .LSOverride 284 | 285 | # Thumbnails 286 | ._* 287 | 288 | # Files that might appear in the root of a volume 289 | .DocumentRevisions-V100 290 | .fseventsd 291 | .Spotlight-V100 292 | .TemporaryItems 293 | .Trashes 294 | .VolumeIcon.icns 295 | 296 | # Directories potentially created on remote AFP share 297 | .AppleDB 298 | .AppleDesktop 299 | Network Trash Folder 300 | Temporary Items 301 | .apdisk 302 | /nuget.exe 303 | *.nuspec 304 | /Hdf5DotnetWrapper/cov-int 305 | /Hdf5DotnetWrapper/cov-int.zip 306 | /HDF5-CSharp.UnitTests/coverage.json 307 | /HDF5-CSharp/Properties/launchSettings.json 308 | --------------------------------------------------------------------------------