From 8fa287026ea4ff894b549aaa60411fb51864c555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Teixeira?= Date: Wed, 28 Jan 2026 17:41:42 +0000 Subject: [PATCH] Update interface based on Harp.Generators 0.4.0 --- Generators/Generators.csproj | 2 +- .../Harp.LedArray/AsyncDevice.Generated.cs | 7 +- Interface/Harp.LedArray/Device.Generated.cs | 152 +++++++++++++++++- Interface/Harp.LedArray/Harp.LedArray.csproj | 2 +- 4 files changed, 158 insertions(+), 5 deletions(-) diff --git a/Generators/Generators.csproj b/Generators/Generators.csproj index 9e36287..9323234 100644 --- a/Generators/Generators.csproj +++ b/Generators/Generators.csproj @@ -15,7 +15,7 @@ ..\Firmware\Harp.LedArray - + diff --git a/Interface/Harp.LedArray/AsyncDevice.Generated.cs b/Interface/Harp.LedArray/AsyncDevice.Generated.cs index 4df5654..d32c5fb 100644 --- a/Interface/Harp.LedArray/AsyncDevice.Generated.cs +++ b/Interface/Harp.LedArray/AsyncDevice.Generated.cs @@ -14,15 +14,18 @@ public partial class Device /// /// The name of the serial port used to communicate with the Harp device. /// + /// + /// A which can be used to cancel the operation. + /// /// /// A task that represents the asynchronous initialization operation. The value of /// the parameter contains a new instance of /// the class. /// - public static async Task CreateAsync(string portName) + public static async Task CreateAsync(string portName, CancellationToken cancellationToken = default) { var device = new AsyncDevice(portName); - var whoAmI = await device.ReadWhoAmIAsync(); + var whoAmI = await device.ReadWhoAmIAsync(cancellationToken); if (whoAmI != Device.WhoAmI) { var errorMessage = string.Format( diff --git a/Interface/Harp.LedArray/Device.Generated.cs b/Interface/Harp.LedArray/Device.Generated.cs index a154781..b480947 100644 --- a/Interface/Harp.LedArray/Device.Generated.cs +++ b/Interface/Harp.LedArray/Device.Generated.cs @@ -93,7 +93,7 @@ static string GetDeviceMetadata() /// describing the device registers. /// [Description("Returns the contents of the metadata file describing the LedArray device registers.")] - public partial class GetMetadata : Source + public partial class GetDeviceMetadata : Source { /// /// Returns an observable sequence with the contents of the metadata file @@ -130,6 +130,156 @@ public override IObservable> Process(IObse } } + /// + /// Represents an operator that writes the sequence of " messages + /// to the standard Harp storage format. + /// + [Description("Writes the sequence of LedArray messages to the standard Harp storage format.")] + public partial class DeviceDataWriter : Sink, INamedElement + { + const string BinaryExtension = ".bin"; + const string MetadataFileName = "device.yml"; + readonly Bonsai.Harp.MessageWriter writer = new(); + + string INamedElement.Name => nameof(LedArray) + "DataWriter"; + + /// + /// Gets or sets the relative or absolute path on which to save the message data. + /// + [Description("The relative or absolute path of the directory on which to save the message data.")] + [Editor("Bonsai.Design.SaveFileNameEditor, Bonsai.Design", DesignTypes.UITypeEditor)] + public string Path + { + get => System.IO.Path.GetDirectoryName(writer.FileName); + set => writer.FileName = System.IO.Path.Combine(value, nameof(LedArray) + BinaryExtension); + } + + /// + /// Gets or sets a value indicating whether element writing should be buffered. If , + /// the write commands will be queued in memory as fast as possible and will be processed + /// by the writer in a different thread. Otherwise, writing will be done in the same + /// thread in which notifications arrive. + /// + [Description("Indicates whether writing should be buffered.")] + public bool Buffered + { + get => writer.Buffered; + set => writer.Buffered = value; + } + + /// + /// Gets or sets a value indicating whether to overwrite the output file if it already exists. + /// + [Description("Indicates whether to overwrite the output file if it already exists.")] + public bool Overwrite + { + get => writer.Overwrite; + set => writer.Overwrite = value; + } + + /// + /// Gets or sets a value specifying how the message filter will use the matching criteria. + /// + [Description("Specifies how the message filter will use the matching criteria.")] + public FilterType FilterType + { + get => writer.FilterType; + set => writer.FilterType = value; + } + + /// + /// Gets or sets a value specifying the expected message type. If no value is + /// specified, all messages will be accepted. + /// + [Description("Specifies the expected message type. If no value is specified, all messages will be accepted.")] + public MessageType? MessageType + { + get => writer.MessageType; + set => writer.MessageType = value; + } + + private IObservable WriteDeviceMetadata(IObservable source) + { + var basePath = Path; + if (string.IsNullOrEmpty(basePath)) + return source; + + var metadataPath = System.IO.Path.Combine(basePath, MetadataFileName); + return Observable.Create(observer => + { + Bonsai.IO.PathHelper.EnsureDirectory(metadataPath); + if (System.IO.File.Exists(metadataPath) && !Overwrite) + { + throw new System.IO.IOException(string.Format("The file '{0}' already exists.", metadataPath)); + } + + System.IO.File.WriteAllText(metadataPath, Device.Metadata); + return source.SubscribeSafe(observer); + }); + } + + /// + /// Writes each Harp message in the sequence to the specified binary file, and the + /// contents of the device metadata file to a separate text file. + /// + /// The sequence of messages to write to the file. + /// + /// An observable sequence that is identical to the + /// sequence but where there is an additional side effect of writing the + /// messages to a raw binary file, and the contents of the device metadata file + /// to a separate text file. + /// + public override IObservable Process(IObservable source) + { + return source.Publish(ps => ps.Merge( + WriteDeviceMetadata(writer.Process(ps.GroupBy(message => message.Address))) + .IgnoreElements() + .Cast())); + } + + /// + /// Writes each Harp message in the sequence of observable groups to the + /// corresponding binary file, where the name of each file is generated from + /// the common group register address. The contents of the device metadata file are + /// written to a separate text file. + /// + /// + /// A sequence of observable groups, each of which corresponds to a unique register + /// address. + /// + /// + /// An observable sequence that is identical to the + /// sequence but where there is an additional side effect of writing the Harp + /// messages in each group to the corresponding file, and the contents of the device + /// metadata file to a separate text file. + /// + public IObservable> Process(IObservable> source) + { + return WriteDeviceMetadata(writer.Process(source)); + } + + /// + /// Writes each Harp message in the sequence of observable groups to the + /// corresponding binary file, where the name of each file is generated from + /// the common group register name. The contents of the device metadata file are + /// written to a separate text file. + /// + /// + /// A sequence of observable groups, each of which corresponds to a unique register + /// type. + /// + /// + /// An observable sequence that is identical to the + /// sequence but where there is an additional side effect of writing the Harp + /// messages in each group to the corresponding file, and the contents of the device + /// metadata file to a separate text file. + /// + public IObservable> Process(IObservable> source) + { + return WriteDeviceMetadata(writer.Process(source)); + } + } + /// /// Represents an operator that filters register-specific messages /// reported by the device. diff --git a/Interface/Harp.LedArray/Harp.LedArray.csproj b/Interface/Harp.LedArray/Harp.LedArray.csproj index 1adb6c6..f3a7968 100644 --- a/Interface/Harp.LedArray/Harp.LedArray.csproj +++ b/Interface/Harp.LedArray/Harp.LedArray.csproj @@ -18,7 +18,7 @@ LICENSE ..\bin\$(Configuration) net462;netstandard2.0 - 0.2.0 + 0.3.0 9.0