11using System ;
22using System . ComponentModel ;
3+ using Bonsai ;
4+ using Bonsai . Reactive ;
35
46namespace OpenEphys . Onix1
57{
@@ -18,6 +20,10 @@ public class ConfigureBreakoutDigitalIO : ConfigureDigitalIO { }
1820 [ Description ( "Configures the ONIX breakout board's digital inputs and outputs." ) ]
1921 public class ConfigureDigitalIO : SingleDeviceFactory
2022 {
23+
24+ double ? sampleRate = null ;
25+ double deadTime = 0 ;
26+
2127 /// <summary>
2228 /// Initialize a new instance of the <see cref="ConfigureDigitalIO"/> class.
2329 /// </summary>
@@ -38,6 +44,49 @@ public ConfigureDigitalIO()
3844 [ Description ( "Specifies whether the digital IO device is enabled." ) ]
3945 public bool Enable { get ; set ; } = true ;
4046
47+ /// <summary>
48+ /// Gets or sets the dead time, in μsec, between event detections when in asynchronous
49+ /// sampling mode.
50+ /// </summary>
51+ /// <remarks>
52+ /// This property is useful for filtering "glitches" due to rapidly changing port states, for instance
53+ /// from switch bounce. This property has no effect when <see cref="SampleRate"/> is set and periodic
54+ /// sampling mode is active.
55+ /// </remarks>
56+ [ Range ( 0 , 1e6 ) ]
57+ [ Category ( ConfigurationCategory ) ]
58+ [ Description ( "Specifies dead time, in μsec, between digital event detections when in asynchronous " +
59+ "sampling mode" ) ]
60+ public double DeadTime
61+ {
62+ get => deadTime ;
63+ set => deadTime = ( value >= 0 && value <= 1e6 )
64+ ? value
65+ : throw new ArgumentOutOfRangeException ( nameof ( DeadTime ) , value ,
66+ $ "{ nameof ( DeadTime ) } must be between 0 and 1e6 μsec.") ;
67+ }
68+
69+ /// <summary>
70+ /// Gets or sets the optional sample rate, in Hz, of the digital inputs.
71+ /// </summary>
72+ /// <remarks>
73+ /// If specified, digital inputs will be sampled periodically at the specified rate in Hz. If not
74+ /// specified, digital input data will be produced asynchronously upon changes in digital input state
75+ /// as long as the changes do not occur in the <see cref="DeadTime"/> with respect to the last
76+ /// detected digital event.
77+ /// </remarks>
78+ [ Range ( 10 , 1e6 ) ]
79+ [ Category ( ConfigurationCategory ) ]
80+ [ Description ( "Specifies the optional sample rate, in Hz, of digital inputs. If not specified, digital " +
81+ "data will be produced asynchronously upon changes in digital input state." ) ]
82+ public double ? SampleRate {
83+ get => sampleRate ;
84+ set => sampleRate = ( value >= 10 && value <= 1e6 ) | value is null
85+ ? value
86+ : throw new ArgumentOutOfRangeException ( nameof ( SampleRate ) , value ,
87+ $ "{ nameof ( SampleRate ) } must be between 10 Hz and 1 MHz.") ;
88+ }
89+
4190 /// <summary>
4291 /// Configures the digital input and output device in the ONIX breakout board.
4392 /// </summary>
@@ -55,10 +104,25 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
55104 {
56105 var deviceName = DeviceName ;
57106 var deviceAddress = DeviceAddress ;
107+ var dt = deadTime ;
108+ var sr = SampleRate ;
58109 return source . ConfigureDevice ( context =>
59110 {
60111 var device = context . GetDeviceContext ( deviceAddress , DeviceType ) ;
61112 device . WriteRegister ( DigitalIO . ENABLE , Enable ? 1u : 0 ) ;
113+
114+ var baseFreqHz = device . ReadRegister ( DigitalIO . BASE_FREQ_HZ ) ;
115+ device . WriteRegister ( DigitalIO . DEAD_TICKS , ( uint ) ( dt / 1e6 * baseFreqHz ) ) ;
116+
117+ if ( sr is not null )
118+ {
119+ var periodTicks = ( uint ) ( baseFreqHz / sr ) ;
120+ device . WriteRegister ( DigitalIO . SAMPLE_PERIOD , periodTicks ) ;
121+ } else
122+ {
123+ device . WriteRegister ( DigitalIO . SAMPLE_PERIOD , 0 ) ;
124+ }
125+
62126 return DeviceManager . RegisterDevice ( deviceName , device , DeviceType ) ;
63127 } ) ;
64128 }
@@ -69,7 +133,10 @@ static class DigitalIO
69133 public const int ID = 18 ;
70134
71135 // managed registers
72- public const uint ENABLE = 0x0 ; // Enable or disable the data output stream
136+ public const uint ENABLE = 0x0 ;
137+ public const uint BASE_FREQ_HZ = 0x5 ;
138+ public const uint DEAD_TICKS = 0x6 ;
139+ public const uint SAMPLE_PERIOD = 0x7 ;
73140
74141 internal class NameConverter : DeviceNameConverter
75142 {
@@ -126,6 +193,10 @@ public enum DigitalPortState : byte
126193 [ Flags ]
127194 public enum BreakoutButtonState : ushort
128195 {
196+ /// <summary>
197+ /// Specifies that no buttons or switches are active.
198+ /// </summary>
199+ None = 0x0 ,
129200 /// <summary>
130201 /// Specifies that the ☾ key is depressed.
131202 /// </summary>
0 commit comments