1+ using RDMSharp . PayloadObject ;
2+ using System ;
3+ using System . Collections . Concurrent ;
4+ using System . Collections . Generic ;
5+ using System . Linq ;
6+ using System . Threading . Tasks ;
7+
8+ namespace RDMSharp . RDM . Device . Module ;
9+
10+ public sealed class CurveModule : AbstractModule
11+ {
12+ private const string _moduleName = "Curve" ;
13+ private const string _moduleDisplayName = "Curve" ;
14+ private static readonly ERDM_Parameter [ ] _moduleParameters = new ERDM_Parameter [ ]
15+ {
16+ ERDM_Parameter . CURVE ,
17+ ERDM_Parameter . CURVE_DESCRIPTION
18+ } ;
19+
20+ public override string DisplayName => _moduleDisplayName ;
21+
22+ private byte ? currentId ;
23+ public byte ? CurrentId
24+ {
25+ get
26+ {
27+ return currentId ;
28+ }
29+ set
30+ {
31+ if ( value is null )
32+ return ;
33+
34+ if ( currentId == value )
35+ return ;
36+
37+ bool initial = currentId is null ;
38+ var backup = currentId ;
39+ currentId = value ;
40+
41+ if ( ParentGeneratedDevice is not null )
42+ ParentGeneratedDevice . setParameterValue ( ERDM_Parameter . CURVE , new RDMCurve ( currentId . Value , this . count . Value ) ) ;
43+
44+ if ( initial )
45+ return ;
46+
47+ if ( ParentRemoteDevice is not null )
48+ {
49+ Task . Run ( async ( ) =>
50+ {
51+ if ( await SetCurve ( value . Value ) )
52+ OnPropertyChanged ( nameof ( CurrentId ) ) ;
53+ else
54+ {
55+ currentId = backup ;
56+ OnPropertyChanged ( nameof ( CurrentId ) ) ;
57+ }
58+ } ) ;
59+ }
60+ }
61+ }
62+ private byte ? count ;
63+ public byte ? Count
64+ {
65+ get
66+ {
67+ return count ;
68+ }
69+ private set
70+ {
71+ if ( value == count )
72+ return ;
73+ count = value ;
74+ OnPropertyChanged ( ) ;
75+ }
76+ }
77+
78+ private Dictionary < byte , string > idDescriptionPair = new Dictionary < byte , string > ( ) ;
79+ public IReadOnlyDictionary < byte , string > IdDescriptionPair => idDescriptionPair ;
80+
81+ public readonly IReadOnlyCollection < RDMCurveDescription > _generatedCurves = null ;
82+
83+ private byte _initialCurveId ;
84+
85+ public CurveModule ( byte initialCurveId , params RDMCurveDescription [ ] curves ) : base (
86+ _moduleName ,
87+ _moduleParameters )
88+ {
89+ if ( ! curves . Any ( c => c . CurveId == initialCurveId ) )
90+ throw new ArgumentOutOfRangeException ( $ "No Curve found with ID: { initialCurveId } ") ;
91+
92+ _initialCurveId = initialCurveId ;
93+ _generatedCurves = ( curves ?? Array . Empty < RDMCurveDescription > ( ) ) . ToList ( ) . AsReadOnly ( ) ;
94+ Count = ( byte ) _generatedCurves . Count ;
95+ }
96+ public CurveModule ( AbstractRemoteRDMDevice remoteDevice ) : base (
97+ remoteDevice ,
98+ _moduleName ,
99+ _moduleParameters )
100+ {
101+ if ( ParentRemoteDevice . ParameterValues . TryGetValue ( ERDM_Parameter . CURVE , out object val ) && val is RDMCurve curve )
102+ fillFromRemote ( curve ) ;
103+ }
104+
105+ protected override async void OnParentGeneratedDeviceChanged ( AbstractGeneratedRDMDevice device )
106+ {
107+ if ( _generatedCurves is not null )
108+ {
109+ if ( _generatedCurves . Count >= byte . MaxValue )
110+ throw new ArgumentOutOfRangeException ( $ "There to many { _generatedCurves } ! Maximum is { byte . MaxValue - 1 } ") ;
111+
112+ if ( _generatedCurves . Count != 0 )
113+ {
114+ var curveDesc = new ConcurrentDictionary < object , object > ( ) ;
115+ foreach ( var gCurve in _generatedCurves )
116+ if ( ! curveDesc . TryAdd ( gCurve . CurveId , gCurve ) )
117+ throw new Exception ( $ "{ gCurve . CurveId } already used as { nameof ( gCurve . CurveId ) } ") ;
118+
119+ device . setParameterValue ( ERDM_Parameter . CURVE_DESCRIPTION , curveDesc ) ;
120+ }
121+ }
122+ await SetCurve ( _initialCurveId ) ;
123+ }
124+
125+ protected override void ParameterChanged ( ERDM_Parameter parameter , object newValue , object index )
126+ {
127+ if ( ParentRemoteDevice is null )
128+ return ;
129+
130+ if ( ! _moduleParameters . Contains ( parameter ) )
131+ return ;
132+
133+ switch ( parameter )
134+ {
135+ case ERDM_Parameter . CURVE_DESCRIPTION :
136+ break ;
137+ case ERDM_Parameter . CURVE when newValue is RDMCurve curve :
138+ fillFromRemote ( curve ) ;
139+ break ;
140+ }
141+ }
142+
143+ private void fillFromRemote ( RDMCurve curve )
144+ {
145+ Count = curve . Curves ;
146+ if ( idDescriptionPair . Count == 0 && ParentRemoteDevice is not null )
147+ if ( ParentRemoteDevice . ParameterValues . TryGetValue ( ERDM_Parameter . CURVE_DESCRIPTION , out object val ) && val is ConcurrentDictionary < object , object > dict )
148+ {
149+ foreach ( var pair in dict )
150+ if ( pair . Value is RDMCurveDescription curveDescription )
151+ idDescriptionPair . Add ( ( byte ) curveDescription . Index , curveDescription . Description ) ;
152+ OnPropertyChanged ( nameof ( IdDescriptionPair ) ) ;
153+ }
154+ else
155+ {
156+ for ( byte i = 1 ; i <= Count ; i ++ )
157+ idDescriptionPair . Add ( i , $ "Curve { i } ") ;
158+ OnPropertyChanged ( nameof ( IdDescriptionPair ) ) ;
159+ }
160+
161+ CurrentId = curve . CurrentCurveId ;
162+ }
163+
164+ public override bool IsHandlingParameter ( ERDM_Parameter parameter , ERDM_Command command )
165+ {
166+ if ( parameter == ERDM_Parameter . CURVE )
167+ return command == ERDM_Command . SET_COMMAND ;
168+ return base . IsHandlingParameter ( parameter , command ) ;
169+ }
170+ protected override RDMMessage handleRequest ( RDMMessage message )
171+ {
172+ if ( message . Parameter == ERDM_Parameter . CURVE )
173+ if ( message . Command == ERDM_Command . SET_COMMAND )
174+ {
175+ if ( message . Value is byte b )
176+ {
177+ try
178+ {
179+ if ( this . _generatedCurves . FirstOrDefault ( c => c . CurveId == b ) is RDMCurveDescription curve )
180+ CurrentId = curve . CurveId ;
181+ else
182+ {
183+ return new RDMMessage ( ERDM_NackReason . DATA_OUT_OF_RANGE )
184+ {
185+ DestUID = message . SourceUID ,
186+ SourceUID = message . DestUID ,
187+ Parameter = message . Parameter ,
188+ Command = ERDM_Command . SET_COMMAND_RESPONSE
189+ } ;
190+ }
191+ }
192+ catch ( Exception ex )
193+ {
194+ Logger ? . LogError ( ex ) ;
195+ return new RDMMessage ( ERDM_NackReason . HARDWARE_FAULT )
196+ {
197+ DestUID = message . SourceUID ,
198+ SourceUID = message . DestUID ,
199+ Parameter = message . Parameter ,
200+ Command = ERDM_Command . SET_COMMAND_RESPONSE
201+ } ;
202+ }
203+ return new RDMMessage ( )
204+ {
205+ DestUID = message . SourceUID ,
206+ SourceUID = message . DestUID ,
207+ Parameter = message . Parameter ,
208+ Command = ERDM_Command . SET_COMMAND_RESPONSE ,
209+ } ;
210+ }
211+ return new RDMMessage ( ERDM_NackReason . FORMAT_ERROR )
212+ {
213+ DestUID = message . SourceUID ,
214+ SourceUID = message . DestUID ,
215+ Parameter = message . Parameter ,
216+ Command = ERDM_Command . SET_COMMAND_RESPONSE
217+ } ;
218+ }
219+ return base . handleRequest ( message ) ;
220+ }
221+
222+ public async Task < bool > SetCurve ( byte curveId )
223+ {
224+ if ( ParentGeneratedDevice is not null )
225+ {
226+ if ( this . _generatedCurves . FirstOrDefault ( p => p . CurveId == curveId ) is not RDMCurveDescription curve )
227+ throw new ArgumentOutOfRangeException ( $ "No Curve found with ID: { curveId } ") ;
228+ CurrentId = curve . CurveId ;
229+ }
230+ if ( ParentRemoteDevice is not null )
231+ {
232+ if ( ! this . IdDescriptionPair . Any ( p => p . Key == curveId ) )
233+ throw new ArgumentOutOfRangeException ( $ "No Curve found with ID: { curveId } ") ;
234+ return await ParentRemoteDevice . SetParameter ( ERDM_Parameter . CURVE , curveId ) ;
235+ }
236+ return true ;
237+ }
238+ }
0 commit comments