From e584fd24ae588e25d6e4d652949eb492b0087c5c 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 | 23 +- Interface/Harp.LedArray/Device.Generated.cs | 232 ++++++++++++++---- Interface/Harp.LedArray/Harp.LedArray.csproj | 2 +- device.yml | 2 +- 5 files changed, 207 insertions(+), 54 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..cab6dce 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( @@ -1278,7 +1281,7 @@ public async Task> ReadTimestampedLed1PwmRealAsync(Cancellati } /// - /// Asynchronously reads the contents of the LedD1PwmDutyCycleReal register. + /// Asynchronously reads the contents of the Led1PwmDutyCycleReal register. /// /// /// A which can be used to cancel the operation. @@ -1287,14 +1290,14 @@ public async Task> ReadTimestampedLed1PwmRealAsync(Cancellati /// A task that represents the asynchronous read operation. The /// property contains the register payload. /// - public async Task ReadLedD1PwmDutyCycleRealAsync(CancellationToken cancellationToken = default) + public async Task ReadLed1PwmDutyCycleRealAsync(CancellationToken cancellationToken = default) { - var reply = await CommandAsync(HarpCommand.ReadSingle(LedD1PwmDutyCycleReal.Address), cancellationToken); - return LedD1PwmDutyCycleReal.GetPayload(reply); + var reply = await CommandAsync(HarpCommand.ReadSingle(Led1PwmDutyCycleReal.Address), cancellationToken); + return Led1PwmDutyCycleReal.GetPayload(reply); } /// - /// Asynchronously reads the timestamped contents of the LedD1PwmDutyCycleReal register. + /// Asynchronously reads the timestamped contents of the Led1PwmDutyCycleReal register. /// /// /// A which can be used to cancel the operation. @@ -1303,10 +1306,10 @@ public async Task ReadLedD1PwmDutyCycleRealAsync(CancellationToken cancel /// A task that represents the asynchronous read operation. The /// property contains the timestamped register payload. /// - public async Task> ReadTimestampedLedD1PwmDutyCycleRealAsync(CancellationToken cancellationToken = default) + public async Task> ReadTimestampedLed1PwmDutyCycleRealAsync(CancellationToken cancellationToken = default) { - var reply = await CommandAsync(HarpCommand.ReadSingle(LedD1PwmDutyCycleReal.Address), cancellationToken); - return LedD1PwmDutyCycleReal.GetTimestampedPayload(reply); + var reply = await CommandAsync(HarpCommand.ReadSingle(Led1PwmDutyCycleReal.Address), cancellationToken); + return Led1PwmDutyCycleReal.GetTimestampedPayload(reply); } /// diff --git a/Interface/Harp.LedArray/Device.Generated.cs b/Interface/Harp.LedArray/Device.Generated.cs index a154781..0bde045 100644 --- a/Interface/Harp.LedArray/Device.Generated.cs +++ b/Interface/Harp.LedArray/Device.Generated.cs @@ -65,7 +65,7 @@ public Device() : base(WhoAmI) { } { 57, typeof(Led0PwmReal) }, { 58, typeof(Led0PwmDutyCycleReal) }, { 59, typeof(Led1PwmReal) }, - { 60, typeof(LedD1PwmDutyCycleReal) }, + { 60, typeof(Led1PwmDutyCycleReal) }, { 61, typeof(AuxDigitalOutputState) }, { 62, typeof(AuxLedPower) }, { 63, typeof(DigitalOutputState) }, @@ -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. @@ -162,7 +312,7 @@ public override IObservable> Process(IObse /// /// /// - /// + /// /// /// /// @@ -195,7 +345,7 @@ public override IObservable> Process(IObse [XmlInclude(typeof(Led0PwmReal))] [XmlInclude(typeof(Led0PwmDutyCycleReal))] [XmlInclude(typeof(Led1PwmReal))] - [XmlInclude(typeof(LedD1PwmDutyCycleReal))] + [XmlInclude(typeof(Led1PwmDutyCycleReal))] [XmlInclude(typeof(AuxDigitalOutputState))] [XmlInclude(typeof(AuxLedPower))] [XmlInclude(typeof(DigitalOutputState))] @@ -249,7 +399,7 @@ string INamedElement.Name /// /// /// - /// + /// /// /// /// @@ -282,7 +432,7 @@ string INamedElement.Name [XmlInclude(typeof(Led0PwmReal))] [XmlInclude(typeof(Led0PwmDutyCycleReal))] [XmlInclude(typeof(Led1PwmReal))] - [XmlInclude(typeof(LedD1PwmDutyCycleReal))] + [XmlInclude(typeof(Led1PwmDutyCycleReal))] [XmlInclude(typeof(AuxDigitalOutputState))] [XmlInclude(typeof(AuxLedPower))] [XmlInclude(typeof(DigitalOutputState))] @@ -315,7 +465,7 @@ string INamedElement.Name [XmlInclude(typeof(TimestampedLed0PwmReal))] [XmlInclude(typeof(TimestampedLed0PwmDutyCycleReal))] [XmlInclude(typeof(TimestampedLed1PwmReal))] - [XmlInclude(typeof(TimestampedLedD1PwmDutyCycleReal))] + [XmlInclude(typeof(TimestampedLed1PwmDutyCycleReal))] [XmlInclude(typeof(TimestampedAuxDigitalOutputState))] [XmlInclude(typeof(TimestampedAuxLedPower))] [XmlInclude(typeof(TimestampedDigitalOutputState))] @@ -366,7 +516,7 @@ public Parse() /// /// /// - /// + /// /// /// /// @@ -399,7 +549,7 @@ public Parse() [XmlInclude(typeof(Led0PwmReal))] [XmlInclude(typeof(Led0PwmDutyCycleReal))] [XmlInclude(typeof(Led1PwmReal))] - [XmlInclude(typeof(LedD1PwmDutyCycleReal))] + [XmlInclude(typeof(Led1PwmDutyCycleReal))] [XmlInclude(typeof(AuxDigitalOutputState))] [XmlInclude(typeof(AuxLedPower))] [XmlInclude(typeof(DigitalOutputState))] @@ -3165,25 +3315,25 @@ public static Timestamped GetPayload(HarpMessage message) /// Represents a register that get the real duty cycle (%) of LED1 when in Pwm mode. /// [Description("Get the real duty cycle (%) of LED1 when in Pwm mode.")] - public partial class LedD1PwmDutyCycleReal + public partial class Led1PwmDutyCycleReal { /// - /// Represents the address of the register. This field is constant. + /// Represents the address of the register. This field is constant. /// public const int Address = 60; /// - /// Represents the payload type of the register. This field is constant. + /// Represents the payload type of the register. This field is constant. /// public const PayloadType RegisterType = PayloadType.Float; /// - /// Represents the length of the register. This field is constant. + /// Represents the length of the register. This field is constant. /// public const int RegisterLength = 1; /// - /// Returns the payload data for register messages. + /// Returns the payload data for register messages. /// /// A object representing the register message. /// A value representing the message payload. @@ -3193,7 +3343,7 @@ public static float GetPayload(HarpMessage message) } /// - /// Returns the timestamped payload data for register messages. + /// Returns the timestamped payload data for register messages. /// /// A object representing the register message. /// A value representing the timestamped message payload. @@ -3203,12 +3353,12 @@ public static Timestamped GetTimestampedPayload(HarpMessage message) } /// - /// Returns a Harp message for the register. + /// Returns a Harp message for the register. /// /// The type of the Harp message. /// The value to be stored in the message payload. /// - /// A object for the register + /// A object for the register /// with the specified message type and payload. /// public static HarpMessage FromPayload(MessageType messageType, float value) @@ -3217,14 +3367,14 @@ public static HarpMessage FromPayload(MessageType messageType, float value) } /// - /// Returns a timestamped Harp message for the + /// Returns a timestamped Harp message for the /// register. /// /// The timestamp of the message payload, in seconds. /// The type of the Harp message. /// The value to be stored in the message payload. /// - /// A object for the register + /// A object for the register /// with the specified message type, timestamp, and payload. /// public static HarpMessage FromPayload(double timestamp, MessageType messageType, float value) @@ -3235,25 +3385,25 @@ public static HarpMessage FromPayload(double timestamp, MessageType messageType, /// /// Provides methods for manipulating timestamped messages from the - /// LedD1PwmDutyCycleReal register. + /// Led1PwmDutyCycleReal register. /// - /// - [Description("Filters and selects timestamped messages from the LedD1PwmDutyCycleReal register.")] - public partial class TimestampedLedD1PwmDutyCycleReal + /// + [Description("Filters and selects timestamped messages from the Led1PwmDutyCycleReal register.")] + public partial class TimestampedLed1PwmDutyCycleReal { /// - /// Represents the address of the register. This field is constant. + /// Represents the address of the register. This field is constant. /// - public const int Address = LedD1PwmDutyCycleReal.Address; + public const int Address = Led1PwmDutyCycleReal.Address; /// - /// Returns timestamped payload data for register messages. + /// Returns timestamped payload data for register messages. /// /// A object representing the register message. /// A value representing the timestamped message payload. public static Timestamped GetPayload(HarpMessage message) { - return LedD1PwmDutyCycleReal.GetTimestampedPayload(message); + return Led1PwmDutyCycleReal.GetTimestampedPayload(message); } } @@ -3698,7 +3848,7 @@ public static Timestamped GetPayload(HarpMessage message) /// /// /// - /// + /// /// /// /// @@ -3731,7 +3881,7 @@ public static Timestamped GetPayload(HarpMessage message) [XmlInclude(typeof(CreateLed0PwmRealPayload))] [XmlInclude(typeof(CreateLed0PwmDutyCycleRealPayload))] [XmlInclude(typeof(CreateLed1PwmRealPayload))] - [XmlInclude(typeof(CreateLedD1PwmDutyCycleRealPayload))] + [XmlInclude(typeof(CreateLed1PwmDutyCycleRealPayload))] [XmlInclude(typeof(CreateAuxDigitalOutputStatePayload))] [XmlInclude(typeof(CreateAuxLedPowerPayload))] [XmlInclude(typeof(CreateDigitalOutputStatePayload))] @@ -3764,7 +3914,7 @@ public static Timestamped GetPayload(HarpMessage message) [XmlInclude(typeof(CreateTimestampedLed0PwmRealPayload))] [XmlInclude(typeof(CreateTimestampedLed0PwmDutyCycleRealPayload))] [XmlInclude(typeof(CreateTimestampedLed1PwmRealPayload))] - [XmlInclude(typeof(CreateTimestampedLedD1PwmDutyCycleRealPayload))] + [XmlInclude(typeof(CreateTimestampedLed1PwmDutyCycleRealPayload))] [XmlInclude(typeof(CreateTimestampedAuxDigitalOutputStatePayload))] [XmlInclude(typeof(CreateTimestampedAuxLedPowerPayload))] [XmlInclude(typeof(CreateTimestampedDigitalOutputStatePayload))] @@ -5362,33 +5512,33 @@ public HarpMessage GetMessage(double timestamp, MessageType messageType) /// Represents an operator that creates a message payload /// that get the real duty cycle (%) of LED1 when in Pwm mode. /// - [DisplayName("LedD1PwmDutyCycleRealPayload")] + [DisplayName("Led1PwmDutyCycleRealPayload")] [Description("Creates a message payload that get the real duty cycle (%) of LED1 when in Pwm mode.")] - public partial class CreateLedD1PwmDutyCycleRealPayload + public partial class CreateLed1PwmDutyCycleRealPayload { /// /// Gets or sets the value that get the real duty cycle (%) of LED1 when in Pwm mode. /// [Description("The value that get the real duty cycle (%) of LED1 when in Pwm mode.")] - public float LedD1PwmDutyCycleReal { get; set; } + public float Led1PwmDutyCycleReal { get; set; } /// - /// Creates a message payload for the LedD1PwmDutyCycleReal register. + /// Creates a message payload for the Led1PwmDutyCycleReal register. /// /// The created message payload value. public float GetPayload() { - return LedD1PwmDutyCycleReal; + return Led1PwmDutyCycleReal; } /// /// Creates a message that get the real duty cycle (%) of LED1 when in Pwm mode. /// /// Specifies the type of the created message. - /// A new message for the LedD1PwmDutyCycleReal register. + /// A new message for the Led1PwmDutyCycleReal register. public HarpMessage GetMessage(MessageType messageType) { - return Harp.LedArray.LedD1PwmDutyCycleReal.FromPayload(messageType, GetPayload()); + return Harp.LedArray.Led1PwmDutyCycleReal.FromPayload(messageType, GetPayload()); } } @@ -5396,19 +5546,19 @@ public HarpMessage GetMessage(MessageType messageType) /// Represents an operator that creates a timestamped message payload /// that get the real duty cycle (%) of LED1 when in Pwm mode. /// - [DisplayName("TimestampedLedD1PwmDutyCycleRealPayload")] + [DisplayName("TimestampedLed1PwmDutyCycleRealPayload")] [Description("Creates a timestamped message payload that get the real duty cycle (%) of LED1 when in Pwm mode.")] - public partial class CreateTimestampedLedD1PwmDutyCycleRealPayload : CreateLedD1PwmDutyCycleRealPayload + public partial class CreateTimestampedLed1PwmDutyCycleRealPayload : CreateLed1PwmDutyCycleRealPayload { /// /// Creates a timestamped message that get the real duty cycle (%) of LED1 when in Pwm mode. /// /// The timestamp of the message payload, in seconds. /// Specifies the type of the created message. - /// A new timestamped message for the LedD1PwmDutyCycleReal register. + /// A new timestamped message for the Led1PwmDutyCycleReal register. public HarpMessage GetMessage(double timestamp, MessageType messageType) { - return Harp.LedArray.LedD1PwmDutyCycleReal.FromPayload(timestamp, messageType, GetPayload()); + return Harp.LedArray.Led1PwmDutyCycleReal.FromPayload(timestamp, messageType, GetPayload()); } } 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 diff --git a/device.yml b/device.yml index cc9006d..f50db56 100644 --- a/device.yml +++ b/device.yml @@ -207,7 +207,7 @@ registers: access: Read type: Float description: Get the real frequency (Hz) of LED1 when in Pwm mode. - LedD1PwmDutyCycleReal: + Led1PwmDutyCycleReal: address: 60 access: Read type: Float