1use crate::configuration::jsonable::JSONInputOutputDefinition;
2use crate::data_pipeline::per_channel_stream_caches::MotorCorticalUnitCache;
3use crate::data_pipeline::{PipelineStageProperties, PipelineStagePropertyIndex};
4use crate::data_types::descriptors::*;
5use crate::data_types::*;
6use crate::neuron_voxel_coding::xyzp::decoders::*;
7use crate::neuron_voxel_coding::xyzp::NeuronVoxelXYZPDecoder;
8use crate::wrapped_io_data::{WrappedIOData, WrappedIOType};
9use feagi_serialization::FeagiByteContainer;
10use feagi_structures::genomic::cortical_area::descriptors::{
11 CorticalChannelCount, CorticalChannelIndex, CorticalUnitIndex, NeuronDepth,
12};
13use feagi_structures::genomic::cortical_area::io_cortical_area_configuration_flag::{
14 FrameChangeHandling, PercentageNeuronPositioning,
15};
16use feagi_structures::genomic::cortical_area::CorticalID;
17use feagi_structures::genomic::MotorCorticalUnit;
18use feagi_structures::neuron_voxels::xyzp::CorticalMappedXYZPNeuronVoxels;
19use feagi_structures::{motor_cortical_units, FeagiDataError, FeagiSignalIndex};
20use serde_json::json;
21use std::collections::HashMap;
22use std::fmt::{Display, Formatter};
23use std::time::Instant;
24
25macro_rules! motor_unit_functions {
26 (
27 MotorCorticalUnit {
28 $(
29 $(#[doc = $doc:expr])?
30 $cortical_type_key_name:ident => {
31 friendly_name: $friendly_name:expr,
32 accepted_wrapped_io_data_type: $accepted_wrapped_io_data_type:ident,
33 cortical_id_unit_reference: $cortical_id_unit_reference:expr,
34 number_cortical_areas: $number_cortical_areas:expr,
35 cortical_type_parameters: {
36 $($param_name:ident: $param_type:ty),* $(,)?
37 },
38 $(allowed_frame_change_handling: [$($allowed_frame:ident),* $(,)?],)?
39 cortical_area_properties: {
40 $($area_index:tt => ($cortical_area_type_expr:expr, relative_position: [$rel_x:expr, $rel_y:expr, $rel_z:expr], channel_dimensions_default: [$dim_default_x:expr, $dim_default_y:expr, $dim_default_z:expr], channel_dimensions_min: [$dim_min_x:expr, $dim_min_y:expr, $dim_min_z:expr], channel_dimensions_max: [$dim_max_x:expr, $dim_max_y:expr, $dim_max_z:expr])),* $(,)?
41 }
42 }
43 ),* $(,)?
44 }
45 ) =>
46 {
47 $(
48 motor_unit_functions!(@generate_functions
49 $cortical_type_key_name,
50 $accepted_wrapped_io_data_type
51 );
52 )*
53 };
54
55 (@generate_similar_functions
58 $cortical_type_key_name:ident,
59 $wrapped_data_type:ident
60 ) => {
61 ::paste::paste! {
62 pub fn [<$cortical_type_key_name:snake _read_preprocessed_cache_value>](
63 &self,
64 unit: CorticalUnitIndex,
65 channel: CorticalChannelIndex,
66 ) -> Result< $wrapped_data_type, FeagiDataError> {
67
68 const MOTOR_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
69 let wrapped = self.try_read_preprocessed_cached_value(MOTOR_TYPE, unit, channel)?;
70 let val: $wrapped_data_type = wrapped.try_into()?;
71 Ok(val)
72 }
73
74 pub fn [<$cortical_type_key_name:snake _read_postprocessed_cache_value>](
75 &self,
76 unit: CorticalUnitIndex,
77 channel: CorticalChannelIndex,
78 ) -> Result< $wrapped_data_type, FeagiDataError> {
79
80 const MOTOR_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
81 let wrapped = self.try_read_postprocessed_cached_value(MOTOR_TYPE, unit, channel)?;
82 let val: $wrapped_data_type = wrapped.try_into()?;
83 Ok(val)
84 }
85
86 pub fn [<$cortical_type_key_name:snake _try_register_motor_callback>]<F>(
87 &mut self,
88 unit: CorticalUnitIndex,
89 channel_index: CorticalChannelIndex,
90 callback: F
91 ) -> Result<FeagiSignalIndex, FeagiDataError>
92 where F: Fn(&WrappedIOData) + Send + Sync + 'static,
93 {
94 const MOTOR_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
95 let signal_index = self.try_register_motor_callback(MOTOR_TYPE, unit, channel_index, callback)?;
96 Ok(signal_index)
97 }
98
99 pub fn [<$cortical_type_key_name:snake _get_single_stage_properties>](
100 &mut self,
101 unit: CorticalUnitIndex,
102 channel_index: CorticalChannelIndex,
103 stage_index: PipelineStagePropertyIndex
104 ) -> Result<PipelineStageProperties, FeagiDataError>
105 {
106 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
107 let stage = self.try_get_single_stage_properties(MOTOR_UNIT_TYPE, unit, channel_index, stage_index)?;
108 Ok(stage)
109 }
110
111 pub fn [<$cortical_type_key_name:snake _get_all_stage_properties>](
112 &mut self,
113 unit: CorticalUnitIndex,
114 channel_index: CorticalChannelIndex
115 ) -> Result<Vec<PipelineStageProperties>, FeagiDataError>
116 {
117 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
118 let stages = self.try_get_all_stage_properties(MOTOR_UNIT_TYPE, unit, channel_index)?;
119 Ok(stages)
120 }
121
122 pub fn [<$cortical_type_key_name:snake _update_single_stage_properties>](
123 &mut self,
124 unit: CorticalUnitIndex,
125 channel_index: CorticalChannelIndex,
126 pipeline_stage_property_index: PipelineStagePropertyIndex,
127 updating_property: PipelineStageProperties
128 ) -> Result<(), FeagiDataError>
129 {
130 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
131 self.try_update_single_stage_properties(MOTOR_UNIT_TYPE, unit, channel_index, pipeline_stage_property_index, updating_property)?;
132 Ok(())
133 }
134
135 pub fn [<$cortical_type_key_name:snake _update_all_stage_properties>](
136 &mut self,
137 unit: CorticalUnitIndex,
138 channel_index: CorticalChannelIndex,
139 updated_pipeline_stage_properties: Vec<PipelineStageProperties>
140 ) -> Result<(), FeagiDataError>
141 {
142 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
143 self.try_update_all_stage_properties(MOTOR_UNIT_TYPE, unit, channel_index, updated_pipeline_stage_properties)?;
144 Ok(())
145 }
146
147 pub fn [<$cortical_type_key_name:snake _replace_single_stage>](
148 &mut self,
149 unit: CorticalUnitIndex,
150 channel_index: CorticalChannelIndex,
151 pipeline_stage_property_index: PipelineStagePropertyIndex,
152 replacing_property: PipelineStageProperties
153 ) -> Result<(), FeagiDataError>
154 {
155 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
156 self.try_replace_single_stage(MOTOR_UNIT_TYPE, unit, channel_index, pipeline_stage_property_index, replacing_property)?;
157 Ok(())
158 }
159
160 pub fn [<$cortical_type_key_name:snake _replace_all_stages>](
161 &mut self,
162 unit: CorticalUnitIndex,
163 channel_index: CorticalChannelIndex,
164 new_pipeline_stage_properties: Vec<PipelineStageProperties>
165 ) -> Result<(), FeagiDataError>
166 {
167 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
168 self.try_replace_all_stages(MOTOR_UNIT_TYPE, unit, channel_index, new_pipeline_stage_properties)?;
169 Ok(())
170 }
171
172 pub fn [<$cortical_type_key_name:snake _removing_all_stages>](
173 &mut self,
174 unit: CorticalUnitIndex,
175 channel_index: CorticalChannelIndex
176 ) -> Result<(), FeagiDataError>
177 {
178 const MOTOR_UNIT_TYPE: MotorCorticalUnit = MotorCorticalUnit::$cortical_type_key_name;
179 self.try_removing_all_stages(MOTOR_UNIT_TYPE, unit, channel_index)?;
180 Ok(())
181 }
182 }
183 };
184 (@generate_functions
188 $motor_unit:ident,
189 GazeProperties
190 ) => {
191 ::paste::paste! {
192 pub fn [<$motor_unit:snake _register>](
193 &mut self,
194 unit: CorticalUnitIndex,
195 number_channels: CorticalChannelCount,
196 frame_change_handling: FrameChangeHandling,
197 eccentricity_z_neuron_resolution: NeuronDepth,
198 modulation_z_neuron_resolution: NeuronDepth,
199 percentage_neuron_positioning: PercentageNeuronPositioning
200 ) -> Result<(), FeagiDataError>
201 {
202 let eccentricity_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
203 let modularity_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[1];
204
205 let io_props: serde_json::Map<String, serde_json::Value> = json!({
206 "frame_change_handling": frame_change_handling,
207 "percentage_neuron_positioning": percentage_neuron_positioning
208 }).as_object().unwrap().clone();
209
210 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = GazePropertiesNeuronVoxelXYZPDecoder::new_box(
211 eccentricity_cortical_id,
212 modularity_cortical_id,
213 eccentricity_z_neuron_resolution,
214 modulation_z_neuron_resolution,
215 number_channels,
216 percentage_neuron_positioning,
217 )?;
218
219 let initial_val: WrappedIOData = WrappedIOData::GazeProperties(GazeProperties::create_default_centered());
220 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
221 Ok(())
222 }
223 }
224
225 motor_unit_functions!(@generate_similar_functions $motor_unit, GazeProperties);
226 };
227
228 (@generate_functions
230 $motor_unit:ident,
231 Percentage
232 ) => {
233 ::paste::paste! {
234 pub fn [<$motor_unit:snake _register>](
235 &mut self,
236 unit: CorticalUnitIndex,
237 number_channels: CorticalChannelCount,
238 frame_change_handling: FrameChangeHandling,
239 z_neuron_resolution: NeuronDepth,
240 percentage_neuron_positioning: PercentageNeuronPositioning
241 ) -> Result<(), FeagiDataError>
242 {
243 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
244 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = PercentageNeuronVoxelXYZPDecoder::new_box(
245 cortical_id,
246 z_neuron_resolution,
247 number_channels,
248 percentage_neuron_positioning,
249 false,
250 PercentageChannelDimensionality::D1
251 )?;
252
253 let io_props: serde_json::Map<String, serde_json::Value> = json!({
254 "frame_change_handling": frame_change_handling,
255 "percentage_neuron_positioning": percentage_neuron_positioning
256 }).as_object().unwrap().clone();
257
258 let initial_val: WrappedIOData = WrappedIOData::Percentage(Percentage::new_zero());
259 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
260 Ok(())
261 }
262 }
263
264 motor_unit_functions!(@generate_similar_functions $motor_unit, Percentage);
265 };
266
267 (@generate_functions
269 $motor_unit:ident,
270 Percentage_3D
271 ) => {
272 ::paste::paste! {
273 pub fn [<$motor_unit:snake _register>](
274 &mut self,
275 unit: CorticalUnitIndex,
276 number_channels: CorticalChannelCount,
277 frame_change_handling: FrameChangeHandling,
278 z_neuron_resolution: NeuronDepth,
279 percentage_neuron_positioning: PercentageNeuronPositioning
280 ) -> Result<(), FeagiDataError>
281 {
282 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
283
284 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = PercentageNeuronVoxelXYZPDecoder::new_box(
285 cortical_id,
286 z_neuron_resolution,
287 number_channels,
288 percentage_neuron_positioning,
289 false,
290 PercentageChannelDimensionality::D3
291 )?;
292
293 let io_props: serde_json::Map<String, serde_json::Value> = json!({
294 "frame_change_handling": frame_change_handling,
295 "percentage_neuron_positioning": percentage_neuron_positioning
296 }).as_object().unwrap().clone();
297
298 let initial_val: WrappedIOData = WrappedIOData::Percentage_3D(Percentage3D::new_zero());
299 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
300 Ok(())
301 }
302 }
303
304 motor_unit_functions!(@generate_similar_functions $motor_unit, Percentage3D);
305 };
306
307 (@generate_functions
309 $motor_unit:ident,
310 SignedPercentage
311 ) => {
312 ::paste::paste! {
313 pub fn [<$motor_unit:snake _register>](
314 &mut self,
315 unit: CorticalUnitIndex,
316 number_channels: CorticalChannelCount,
317 frame_change_handling: FrameChangeHandling,
318 z_neuron_resolution: NeuronDepth,
319 percentage_neuron_positioning: PercentageNeuronPositioning
320 ) -> Result<(), FeagiDataError>
321 {
322 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
323 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = PercentageNeuronVoxelXYZPDecoder::new_box(
324 cortical_id,
325 z_neuron_resolution,
326 number_channels,
327 percentage_neuron_positioning,
328 true,
329 PercentageChannelDimensionality::D1
330 )?;
331
332 let io_props: serde_json::Map<String, serde_json::Value> = json!({
333 "frame_change_handling": frame_change_handling,
334 "percentage_neuron_positioning": percentage_neuron_positioning
335 }).as_object().unwrap().clone();
336
337 let initial_val: WrappedIOData = WrappedIOData::SignedPercentage(SignedPercentage::new_from_m1_1_unchecked(0.0));
338 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
339 Ok(())
340 }
341 }
342
343 motor_unit_functions!(@generate_similar_functions $motor_unit, SignedPercentage);
344 };
345
346 (@generate_functions
348 $motor_unit:ident,
349 MiscData
350 ) => {
351 ::paste::paste! {
352 pub fn [<$motor_unit:snake _register>](
353 &mut self,
354 unit: CorticalUnitIndex,
355 number_channels: CorticalChannelCount,
356 frame_change_handling: FrameChangeHandling,
357 misc_data_dimensions: MiscDataDimensions
358 ) -> Result<(), FeagiDataError>
359 {
360 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, unit)[0];
361 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = MiscDataNeuronVoxelXYZPDecoder::new_box(cortical_id, misc_data_dimensions, number_channels)?;
362
363 let io_props: serde_json::Map<String, serde_json::Value> = json!({
364 "frame_change_handling": frame_change_handling
365 }).as_object().unwrap().clone();
366
367 let initial_val: WrappedIOData = WrappedIOType::MiscData(Some(misc_data_dimensions)).create_blank_data_of_type()?;
368 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
369 Ok(())
370 }
371 }
372
373 motor_unit_functions!(@generate_similar_functions $motor_unit, MiscData);
374 };
375
376 (@generate_functions
378 $motor_unit:ident,
379 ImageFrame
380 ) => {
381 ::paste::paste! {
382 pub fn [<$motor_unit:snake _register>](
383 &mut self,
384 unit: CorticalUnitIndex,
385 number_channels: CorticalChannelCount,
386 frame_change_handling: FrameChangeHandling,
387 image_properties: ImageFrameProperties,
388 ) -> Result<(), FeagiDataError>
389 {
390 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, unit)[0];
391 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = CartesianPlaneNeuronVoxelXYZPDecoder::new_box(cortical_id, &image_properties, number_channels)?;
392
393 let io_props: serde_json::Map<String, serde_json::Value> = json!({
394 "frame_change_handling": frame_change_handling
395 }).as_object().unwrap().clone();
396
397 let initial_val: WrappedIOData = WrappedIOType::ImageFrame(Some(image_properties)).create_blank_data_of_type()?;
398 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
399 Ok(())
400 }
401 }
402
403 motor_unit_functions!(@generate_similar_functions $motor_unit, ImageFrame);
404 };
405
406 (@generate_functions
408 $motor_unit:ident,
409 ImageFilteringSettings
410 ) => {
411 ::paste::paste! {
412 pub fn [<$motor_unit:snake _register>](
413 &mut self,
414 unit: CorticalUnitIndex,
415 number_channels: CorticalChannelCount,
416 frame_change_handling: FrameChangeHandling,
417 z_neuron_resolution: NeuronDepth,
418 percentage_neuron_positioning: PercentageNeuronPositioning
419 ) -> Result<(), FeagiDataError>
420 {
421 let brightness_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
422 let contrast_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[1];
423 let diff_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[2];
424
425 let io_props: serde_json::Map<String, serde_json::Value> = json!({
426 "frame_change_handling": frame_change_handling,
427 "percentage_neuron_positioning": percentage_neuron_positioning
428 }).as_object().unwrap().clone();
429
430 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = ImageFilteringSettingsNeuronVoxelXYZPDecoder::new_box(
431 brightness_cortical_id,
432 contrast_cortical_id,
433 diff_cortical_id,
434 z_neuron_resolution,
435 z_neuron_resolution,
436 z_neuron_resolution,
437 number_channels,
438 percentage_neuron_positioning)?;
439
440
441
442 let initial_val: WrappedIOData = WrappedIOData::ImageFilteringSettings(ImageFilteringSettings::default());
443
444 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
445 Ok(())
446 }
447 }
448
449 motor_unit_functions!(@generate_similar_functions $motor_unit, ImageFilteringSettings);
450 };
451}
452
453pub struct MotorDeviceCache {
454 motor_cortical_unit_caches:
455 HashMap<(MotorCorticalUnit, CorticalUnitIndex), MotorCorticalUnitCache>,
456 neuron_data: CorticalMappedXYZPNeuronVoxels,
457 byte_data: FeagiByteContainer,
458 previous_burst: Instant,
459 #[allow(dead_code)]
460 is_active: bool,
461}
462
463impl std::fmt::Debug for MotorDeviceCache {
464 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465 f.debug_struct("MotorDeviceCache")
466 .field(
467 "stream_caches_count",
468 &self.motor_cortical_unit_caches.len(),
469 )
470 .field("neuron_data", &self.neuron_data)
471 .field("byte_data", &self.byte_data)
472 .field("previous_burst", &self.previous_burst)
473 .finish()
474 }
475}
476
477impl MotorDeviceCache {
478 pub fn new() -> Self {
479 MotorDeviceCache {
480 motor_cortical_unit_caches: HashMap::new(),
481 neuron_data: CorticalMappedXYZPNeuronVoxels::new(),
482 byte_data: FeagiByteContainer::new_empty(),
483 previous_burst: Instant::now(),
484 is_active: false,
485 }
486 }
487
488 pub fn ingest_neuron_data_and_run_callbacks(
498 &mut self,
499 neuron_data: CorticalMappedXYZPNeuronVoxels,
500 time_of_decode: Instant,
501 ) -> Result<(), FeagiDataError> {
502 self.neuron_data = neuron_data;
503 self.try_decode_neural_data_into_cache(time_of_decode)
504 }
505
506 pub fn reset(&mut self) {
508 self.motor_cortical_unit_caches.clear();
509 self.neuron_data = CorticalMappedXYZPNeuronVoxels::new();
510 self.byte_data = FeagiByteContainer::new_empty();
511 self.previous_burst = Instant::now();
512 }
513
514 pub fn verify_existence(
515 &self,
516 motor_cortical_unit: MotorCorticalUnit,
517 unit_index: CorticalUnitIndex,
518 cortical_channel_index: CorticalChannelIndex,
519 ) -> Result<(), FeagiDataError> {
520 let motor_stream_caches =
521 self.try_get_motor_channel_stream_caches(motor_cortical_unit, unit_index)?;
522 motor_stream_caches.verify_channel_exists(cortical_channel_index)
523 }
524
525 motor_cortical_units!(motor_unit_functions);
526
527 pub fn get_feagi_byte_container(&self) -> &FeagiByteContainer {
530 &self.byte_data
531 }
532
533 pub fn get_feagi_byte_container_mut(&mut self) -> &mut FeagiByteContainer {
534 &mut self.byte_data
535 }
536
537 pub fn get_neurons(&self) -> &CorticalMappedXYZPNeuronVoxels {
538 &self.neuron_data
539 }
540
541 pub fn try_decode_bytes_to_neural_data(&mut self) -> Result<bool, FeagiDataError> {
543 self.byte_data
544 .try_update_struct_from_first_found_struct_of_type(&mut self.neuron_data)
545 }
546
547 pub fn try_decode_neural_data_into_cache(
548 &mut self,
549 time_of_decode: Instant,
550 ) -> Result<(), FeagiDataError> {
551 for motor_channel_stream_cache in self.motor_cortical_unit_caches.values_mut() {
552 motor_channel_stream_cache.try_read_neuron_data_to_cache_and_do_callbacks(
553 &self.neuron_data,
554 time_of_decode,
555 )?;
556 }
557 Ok(())
558 }
559
560 pub fn import_from_output_definition(
569 &mut self,
570 replacing_definition: &JSONInputOutputDefinition,
571 ) -> Result<(), FeagiDataError> {
572 self.reset();
573 let output_units_and_decoder_properties =
574 replacing_definition.get_output_units_and_decoder_properties();
575 for (motor_unit, unit_and_decoder_definitions) in output_units_and_decoder_properties {
576 for unit_and_decoder_definition in unit_and_decoder_definitions {
577 let unit_definition = &unit_and_decoder_definition.0;
578 let encoder_definition = &unit_and_decoder_definition.1;
579
580 if self
581 .motor_cortical_unit_caches
582 .contains_key(&(*motor_unit, unit_definition.cortical_unit_index))
583 {
584 return Err(FeagiDataError::DeserializationError(format!(
585 "Already registered motor {} of unit index {}!",
586 *motor_unit, unit_definition.cortical_unit_index
587 )));
588 }
589
590 let new_unit = MotorCorticalUnitCache::new_from_json(
591 motor_unit,
592 unit_definition,
593 encoder_definition,
594 )?;
595 self.motor_cortical_unit_caches
596 .insert((*motor_unit, unit_definition.cortical_unit_index), new_unit);
597 }
598 }
599 Ok(())
600 }
601
602 pub fn export_to_output_definition(
603 &self,
604 filling_definition: &mut JSONInputOutputDefinition,
605 ) -> Result<(), FeagiDataError> {
606 for ((motor_cortical_unit, cortical_unit_index), motor_channel_stream_caches) in
607 self.motor_cortical_unit_caches.iter()
608 {
609 let unit_and_encoder =
610 motor_channel_stream_caches.export_as_jsons(*cortical_unit_index);
611 filling_definition.insert_motor(
612 *motor_cortical_unit,
613 unit_and_encoder.0,
614 unit_and_encoder.1,
615 );
616 }
617 Ok(())
618 }
619
620 fn register(
627 &mut self,
628 motor_type: MotorCorticalUnit,
629 unit_index: CorticalUnitIndex,
630 neuron_decoder: Box<dyn NeuronVoxelXYZPDecoder>,
631 io_configuration_flags: serde_json::Map<String, serde_json::Value>,
632 number_channels: CorticalChannelCount,
633 initial_cached_value: WrappedIOData,
634 ) -> Result<(), FeagiDataError> {
635 if self
638 .motor_cortical_unit_caches
639 .contains_key(&(motor_type, unit_index))
640 {
641 return Err(FeagiDataError::BadParameters(format!(
642 "Already registered motor {} of unit index {}!",
643 motor_type, unit_index
644 )));
645 }
646
647 self.motor_cortical_unit_caches.insert(
648 (motor_type, unit_index),
649 MotorCorticalUnitCache::new(
650 neuron_decoder,
651 io_configuration_flags,
652 number_channels,
653 initial_cached_value,
654 )?,
655 );
656
657 Ok(())
658 }
659
660 fn try_read_preprocessed_cached_value(
663 &self,
664 motor_type: MotorCorticalUnit,
665 unit_index: CorticalUnitIndex,
666 channel_index: CorticalChannelIndex,
667 ) -> Result<&WrappedIOData, FeagiDataError> {
668 let motor_stream_caches =
669 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
670 motor_stream_caches.get_preprocessed_motor_value(channel_index)
671 }
672
673 fn try_read_postprocessed_cached_value(
674 &self,
675 motor_type: MotorCorticalUnit,
676 unit_index: CorticalUnitIndex,
677 channel_index: CorticalChannelIndex,
678 ) -> Result<&WrappedIOData, FeagiDataError> {
679 let motor_stream_caches =
680 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
681 motor_stream_caches.get_postprocessed_motor_value(channel_index)
682 }
683
684 fn try_register_motor_callback<F>(
685 &mut self,
686 motor_type: MotorCorticalUnit,
687 unit_index: CorticalUnitIndex,
688 channel_index: CorticalChannelIndex,
689 callback: F,
690 ) -> Result<FeagiSignalIndex, FeagiDataError>
691 where
692 F: Fn(&WrappedIOData) + Send + Sync + 'static,
693 {
694 let motor_stream_caches =
695 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
696 let index =
697 motor_stream_caches.try_connect_to_data_processed_signal(channel_index, callback)?;
698 Ok(index)
699 }
700
701 fn try_get_single_stage_properties(
706 &self,
707 motor_type: MotorCorticalUnit,
708 unit_index: CorticalUnitIndex,
709 channel_index: CorticalChannelIndex,
710 stage_index: PipelineStagePropertyIndex,
711 ) -> Result<PipelineStageProperties, FeagiDataError> {
712 let motor_stream_caches =
713 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
714 motor_stream_caches.try_get_single_stage_properties(channel_index, stage_index)
715 }
716
717 fn try_get_all_stage_properties(
718 &self,
719 motor_type: MotorCorticalUnit,
720 unit_index: CorticalUnitIndex,
721 channel_index: CorticalChannelIndex,
722 ) -> Result<Vec<PipelineStageProperties>, FeagiDataError> {
723 let motor_stream_caches =
724 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
725 motor_stream_caches.get_all_stage_properties(channel_index)
726 }
727
728 fn try_update_single_stage_properties(
729 &mut self,
730 motor_type: MotorCorticalUnit,
731 unit_index: CorticalUnitIndex,
732 channel_index: CorticalChannelIndex,
733 pipeline_stage_property_index: PipelineStagePropertyIndex,
734 replacing_property: PipelineStageProperties,
735 ) -> Result<(), FeagiDataError> {
736 let motor_stream_caches =
737 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
738 motor_stream_caches.try_update_single_stage_properties(
739 channel_index,
740 pipeline_stage_property_index,
741 replacing_property,
742 )
743 }
744
745 fn try_update_all_stage_properties(
746 &mut self,
747 motor_type: MotorCorticalUnit,
748 unit_index: CorticalUnitIndex,
749 channel_index: CorticalChannelIndex,
750 new_pipeline_stage_properties: Vec<PipelineStageProperties>,
751 ) -> Result<(), FeagiDataError> {
752 let motor_stream_caches =
753 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
754 motor_stream_caches
755 .try_update_all_stage_properties(channel_index, new_pipeline_stage_properties)
756 }
757
758 fn try_replace_single_stage(
759 &mut self,
760 motor_type: MotorCorticalUnit,
761 unit_index: CorticalUnitIndex,
762 channel_index: CorticalChannelIndex,
763 replacing_at_index: PipelineStagePropertyIndex,
764 new_pipeline_stage_properties: PipelineStageProperties,
765 ) -> Result<(), FeagiDataError> {
766 let motor_stream_caches =
767 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
768 motor_stream_caches.try_replace_single_stage(
769 channel_index,
770 replacing_at_index,
771 new_pipeline_stage_properties,
772 )
773 }
774
775 fn try_replace_all_stages(
776 &mut self,
777 motor_type: MotorCorticalUnit,
778 unit_index: CorticalUnitIndex,
779 channel_index: CorticalChannelIndex,
780 new_pipeline_stage_properties: Vec<PipelineStageProperties>,
781 ) -> Result<(), FeagiDataError> {
782 let motor_stream_caches =
783 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
784 motor_stream_caches.try_replace_all_stages(channel_index, new_pipeline_stage_properties)
785 }
786
787 fn try_removing_all_stages(
788 &mut self,
789 sensor_type: MotorCorticalUnit,
790 unit_index: CorticalUnitIndex,
791 channel_index: CorticalChannelIndex,
792 ) -> Result<(), FeagiDataError> {
793 let motor_stream_cache =
794 self.try_get_motor_channel_stream_caches_mut(sensor_type, unit_index)?;
795 motor_stream_cache.try_removing_all_stages(channel_index)?;
796 Ok(())
797 }
798
799 fn try_get_motor_channel_stream_caches(
806 &self,
807 motor_type: MotorCorticalUnit,
808 unit_index: CorticalUnitIndex,
809 ) -> Result<&MotorCorticalUnitCache, FeagiDataError> {
810 let check = self
811 .motor_cortical_unit_caches
812 .get(&(motor_type, unit_index));
813 if check.is_none() {
814 return Err(FeagiDataError::BadParameters(format!(
815 "Unable to find {} of cortical unit index {} in registered motor's list!",
816 motor_type, unit_index
817 )));
818 }
819 let check = check.unwrap();
820 Ok(check)
821 }
822
823 fn try_get_motor_channel_stream_caches_mut(
824 &mut self,
825 motor_type: MotorCorticalUnit,
826 unit_index: CorticalUnitIndex,
827 ) -> Result<&mut MotorCorticalUnitCache, FeagiDataError> {
828 let check = self
829 .motor_cortical_unit_caches
830 .get_mut(&(motor_type, unit_index));
831 if check.is_none() {
832 return Err(FeagiDataError::BadParameters(format!(
833 "Unable to find {} of cortical unit index {} in registered motor's list!",
834 motor_type, unit_index
835 )));
836 }
837 let check = check.unwrap();
838 Ok(check)
839 }
840
841 }
845
846impl Default for MotorDeviceCache {
847 fn default() -> Self {
848 Self::new()
849 }
850}
851
852impl Display for MotorDeviceCache {
853 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
854 Ok(writeln!(f, "Motor Device Cache:")?)
855 }
856}