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_ids = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit);
244
245 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = match (cortical_ids.get(0), cortical_ids.get(1)) {
247 (Some(&id0), Some(&id1)) => {
248 PositionalServoNeuronVoxelXYZPDecoder::new_box(
250 id0,
251 id1,
252 z_neuron_resolution,
253 number_channels,
254 percentage_neuron_positioning,
255 )?
256 }
257 (Some(&id0), None) => {
258 PercentageNeuronVoxelXYZPDecoder::new_box(
260 id0,
261 z_neuron_resolution,
262 number_channels,
263 percentage_neuron_positioning,
264 false,
265 PercentageChannelDimensionality::D1
266 )?
267 }
268 _ => {
269 return Err(FeagiDataError::InternalError(
270 "Expected at least one cortical ID for Percentage motor unit".to_string()
271 ));
272 }
273 };
274
275 let io_props: serde_json::Map<String, serde_json::Value> = json!({
276 "frame_change_handling": frame_change_handling,
277 "percentage_neuron_positioning": percentage_neuron_positioning
278 }).as_object().unwrap().clone();
279
280 let initial_val: WrappedIOData = WrappedIOData::Percentage(Percentage::new_zero());
281 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
282 Ok(())
283 }
284 }
285
286 motor_unit_functions!(@generate_similar_functions $motor_unit, Percentage);
287 };
288
289 (@generate_functions
291 $motor_unit:ident,
292 Percentage_3D
293 ) => {
294 ::paste::paste! {
295 pub fn [<$motor_unit:snake _register>](
296 &mut self,
297 unit: CorticalUnitIndex,
298 number_channels: CorticalChannelCount,
299 frame_change_handling: FrameChangeHandling,
300 z_neuron_resolution: NeuronDepth,
301 percentage_neuron_positioning: PercentageNeuronPositioning
302 ) -> Result<(), FeagiDataError>
303 {
304 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
305
306 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = PercentageNeuronVoxelXYZPDecoder::new_box(
307 cortical_id,
308 z_neuron_resolution,
309 number_channels,
310 percentage_neuron_positioning,
311 false,
312 PercentageChannelDimensionality::D3
313 )?;
314
315 let io_props: serde_json::Map<String, serde_json::Value> = json!({
316 "frame_change_handling": frame_change_handling,
317 "percentage_neuron_positioning": percentage_neuron_positioning
318 }).as_object().unwrap().clone();
319
320 let initial_val: WrappedIOData = WrappedIOData::Percentage_3D(Percentage3D::new_zero());
321 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
322 Ok(())
323 }
324 }
325
326 motor_unit_functions!(@generate_similar_functions $motor_unit, Percentage3D);
327 };
328
329 (@generate_functions
331 $motor_unit:ident,
332 SignedPercentage
333 ) => {
334 ::paste::paste! {
335 pub fn [<$motor_unit:snake _register>](
336 &mut self,
337 unit: CorticalUnitIndex,
338 number_channels: CorticalChannelCount,
339 frame_change_handling: FrameChangeHandling,
340 z_neuron_resolution: NeuronDepth,
341 percentage_neuron_positioning: PercentageNeuronPositioning
342 ) -> Result<(), FeagiDataError>
343 {
344 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
345 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = PercentageNeuronVoxelXYZPDecoder::new_box(
346 cortical_id,
347 z_neuron_resolution,
348 number_channels,
349 percentage_neuron_positioning,
350 true,
351 PercentageChannelDimensionality::D1
352 )?;
353
354 let io_props: serde_json::Map<String, serde_json::Value> = json!({
355 "frame_change_handling": frame_change_handling,
356 "percentage_neuron_positioning": percentage_neuron_positioning
357 }).as_object().unwrap().clone();
358
359 let initial_val: WrappedIOData = WrappedIOData::SignedPercentage(SignedPercentage::new_from_m1_1_unchecked(0.0));
360 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
361 Ok(())
362 }
363 }
364
365 motor_unit_functions!(@generate_similar_functions $motor_unit, SignedPercentage);
366 };
367
368 (@generate_functions
370 $motor_unit:ident,
371 MiscData
372 ) => {
373 ::paste::paste! {
374 pub fn [<$motor_unit:snake _register>](
375 &mut self,
376 unit: CorticalUnitIndex,
377 number_channels: CorticalChannelCount,
378 frame_change_handling: FrameChangeHandling,
379 misc_data_dimensions: MiscDataDimensions
380 ) -> Result<(), FeagiDataError>
381 {
382 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, unit)[0];
383 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = MiscDataNeuronVoxelXYZPDecoder::new_box(cortical_id, misc_data_dimensions, number_channels)?;
384
385 let io_props: serde_json::Map<String, serde_json::Value> = json!({
386 "frame_change_handling": frame_change_handling
387 }).as_object().unwrap().clone();
388
389 let initial_val: WrappedIOData = WrappedIOType::MiscData(Some(misc_data_dimensions)).create_blank_data_of_type()?;
390 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
391 Ok(())
392 }
393 }
394
395 motor_unit_functions!(@generate_similar_functions $motor_unit, MiscData);
396 };
397
398 (@generate_functions
400 $motor_unit:ident,
401 ImageFrame
402 ) => {
403 ::paste::paste! {
404 pub fn [<$motor_unit:snake _register>](
405 &mut self,
406 unit: CorticalUnitIndex,
407 number_channels: CorticalChannelCount,
408 frame_change_handling: FrameChangeHandling,
409 image_properties: ImageFrameProperties,
410 ) -> Result<(), FeagiDataError>
411 {
412 let cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, unit)[0];
413 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = CartesianPlaneNeuronVoxelXYZPDecoder::new_box(cortical_id, &image_properties, number_channels)?;
414
415 let io_props: serde_json::Map<String, serde_json::Value> = json!({
416 "frame_change_handling": frame_change_handling
417 }).as_object().unwrap().clone();
418
419 let initial_val: WrappedIOData = WrappedIOType::ImageFrame(Some(image_properties)).create_blank_data_of_type()?;
420 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
421 Ok(())
422 }
423 }
424
425 motor_unit_functions!(@generate_similar_functions $motor_unit, ImageFrame);
426 };
427
428 (@generate_functions
430 $motor_unit:ident,
431 ImageFilteringSettings
432 ) => {
433 ::paste::paste! {
434 pub fn [<$motor_unit:snake _register>](
435 &mut self,
436 unit: CorticalUnitIndex,
437 number_channels: CorticalChannelCount,
438 frame_change_handling: FrameChangeHandling,
439 z_neuron_resolution: NeuronDepth,
440 percentage_neuron_positioning: PercentageNeuronPositioning
441 ) -> Result<(), FeagiDataError>
442 {
443 let brightness_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[0];
444 let contrast_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[1];
445 let diff_cortical_id: CorticalID = MotorCorticalUnit::[<get_cortical_ids_array_for_ $motor_unit:snake _with_parameters>](frame_change_handling, percentage_neuron_positioning, unit)[2];
446
447 let io_props: serde_json::Map<String, serde_json::Value> = json!({
448 "frame_change_handling": frame_change_handling,
449 "percentage_neuron_positioning": percentage_neuron_positioning
450 }).as_object().unwrap().clone();
451
452 let decoder: Box<dyn NeuronVoxelXYZPDecoder + Sync + Send> = ImageFilteringSettingsNeuronVoxelXYZPDecoder::new_box(
453 brightness_cortical_id,
454 contrast_cortical_id,
455 diff_cortical_id,
456 z_neuron_resolution,
457 z_neuron_resolution,
458 z_neuron_resolution,
459 number_channels,
460 percentage_neuron_positioning)?;
461
462
463
464 let initial_val: WrappedIOData = WrappedIOData::ImageFilteringSettings(ImageFilteringSettings::default());
465
466 self.register(MotorCorticalUnit::$motor_unit, unit, decoder, io_props, number_channels, initial_val)?;
467 Ok(())
468 }
469 }
470
471 motor_unit_functions!(@generate_similar_functions $motor_unit, ImageFilteringSettings);
472 };
473}
474
475pub struct MotorDeviceCache {
476 motor_cortical_unit_caches:
477 HashMap<(MotorCorticalUnit, CorticalUnitIndex), MotorCorticalUnitCache>,
478 neuron_data: CorticalMappedXYZPNeuronVoxels,
479 byte_data: FeagiByteContainer,
480 previous_burst: Instant,
481 #[allow(dead_code)]
482 is_active: bool,
483}
484
485impl std::fmt::Debug for MotorDeviceCache {
486 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
487 f.debug_struct("MotorDeviceCache")
488 .field(
489 "stream_caches_count",
490 &self.motor_cortical_unit_caches.len(),
491 )
492 .field("neuron_data", &self.neuron_data)
493 .field("byte_data", &self.byte_data)
494 .field("previous_burst", &self.previous_burst)
495 .finish()
496 }
497}
498
499impl MotorDeviceCache {
500 pub fn new() -> Self {
501 MotorDeviceCache {
502 motor_cortical_unit_caches: HashMap::new(),
503 neuron_data: CorticalMappedXYZPNeuronVoxels::new(),
504 byte_data: FeagiByteContainer::new_empty(),
505 previous_burst: Instant::now(),
506 is_active: false,
507 }
508 }
509
510 pub fn ingest_neuron_data_and_run_callbacks(
520 &mut self,
521 neuron_data: CorticalMappedXYZPNeuronVoxels,
522 time_of_decode: Instant,
523 ) -> Result<(), FeagiDataError> {
524 self.neuron_data = neuron_data;
525 self.try_decode_neural_data_into_cache(time_of_decode)
526 }
527
528 pub fn reset(&mut self) {
530 self.motor_cortical_unit_caches.clear();
531 self.neuron_data = CorticalMappedXYZPNeuronVoxels::new();
532 self.byte_data = FeagiByteContainer::new_empty();
533 self.previous_burst = Instant::now();
534 }
535
536 pub fn verify_existence(
537 &self,
538 motor_cortical_unit: MotorCorticalUnit,
539 unit_index: CorticalUnitIndex,
540 cortical_channel_index: CorticalChannelIndex,
541 ) -> Result<(), FeagiDataError> {
542 let motor_stream_caches =
543 self.try_get_motor_channel_stream_caches(motor_cortical_unit, unit_index)?;
544 motor_stream_caches.verify_channel_exists(cortical_channel_index)
545 }
546
547 motor_cortical_units!(motor_unit_functions);
548
549 pub fn get_feagi_byte_container(&self) -> &FeagiByteContainer {
552 &self.byte_data
553 }
554
555 pub fn get_feagi_byte_container_mut(&mut self) -> &mut FeagiByteContainer {
556 &mut self.byte_data
557 }
558
559 pub fn get_neurons(&self) -> &CorticalMappedXYZPNeuronVoxels {
560 &self.neuron_data
561 }
562
563 pub fn try_decode_bytes_to_neural_data(&mut self) -> Result<bool, FeagiDataError> {
565 self.byte_data
566 .try_update_struct_from_first_found_struct_of_type(&mut self.neuron_data)
567 }
568
569 pub fn try_decode_neural_data_into_cache(
570 &mut self,
571 time_of_decode: Instant,
572 ) -> Result<(), FeagiDataError> {
573 for motor_channel_stream_cache in self.motor_cortical_unit_caches.values_mut() {
574 motor_channel_stream_cache.try_read_neuron_data_to_cache_and_do_callbacks(
575 &self.neuron_data,
576 time_of_decode,
577 )?;
578 }
579 Ok(())
580 }
581
582 pub fn import_from_output_definition(
587 &mut self,
588 replacing_definition: &JSONInputOutputDefinition,
589 ) -> Result<(), FeagiDataError> {
590 self.reset();
591 let output_units_and_decoder_properties =
592 replacing_definition.get_output_units_and_decoder_properties();
593 for (motor_unit, unit_and_decoder_definitions) in output_units_and_decoder_properties {
594 for unit_and_decoder_definition in unit_and_decoder_definitions {
595 let unit_definition = &unit_and_decoder_definition.0;
596 let encoder_definition = &unit_and_decoder_definition.1;
597
598 if self
599 .motor_cortical_unit_caches
600 .contains_key(&(*motor_unit, unit_definition.cortical_unit_index))
601 {
602 return Err(FeagiDataError::DeserializationError(format!(
603 "Already registered motor {} of unit index {}!",
604 *motor_unit, unit_definition.cortical_unit_index
605 )));
606 }
607
608 let new_unit = MotorCorticalUnitCache::new_from_json(
609 motor_unit,
610 unit_definition,
611 encoder_definition,
612 )?;
613 self.motor_cortical_unit_caches
614 .insert((*motor_unit, unit_definition.cortical_unit_index), new_unit);
615 }
616 }
617 Ok(())
618 }
619
620 pub fn export_to_output_definition(
621 &self,
622 filling_definition: &mut JSONInputOutputDefinition,
623 ) -> Result<(), FeagiDataError> {
624 for ((motor_cortical_unit, cortical_unit_index), motor_channel_stream_caches) in
625 self.motor_cortical_unit_caches.iter()
626 {
627 let unit_and_encoder =
628 motor_channel_stream_caches.export_as_jsons(*cortical_unit_index);
629 filling_definition.insert_motor(
630 *motor_cortical_unit,
631 unit_and_encoder.0,
632 unit_and_encoder.1,
633 );
634 }
635 Ok(())
636 }
637
638 fn register(
645 &mut self,
646 motor_type: MotorCorticalUnit,
647 unit_index: CorticalUnitIndex,
648 neuron_decoder: Box<dyn NeuronVoxelXYZPDecoder>,
649 io_configuration_flags: serde_json::Map<String, serde_json::Value>,
650 number_channels: CorticalChannelCount,
651 initial_cached_value: WrappedIOData,
652 ) -> Result<(), FeagiDataError> {
653 if self
656 .motor_cortical_unit_caches
657 .contains_key(&(motor_type, unit_index))
658 {
659 return Err(FeagiDataError::BadParameters(format!(
660 "Already registered motor {} of unit index {}!",
661 motor_type, unit_index
662 )));
663 }
664
665 self.motor_cortical_unit_caches.insert(
666 (motor_type, unit_index),
667 MotorCorticalUnitCache::new(
668 neuron_decoder,
669 io_configuration_flags,
670 number_channels,
671 initial_cached_value,
672 )?,
673 );
674
675 Ok(())
676 }
677
678 fn try_read_preprocessed_cached_value(
681 &self,
682 motor_type: MotorCorticalUnit,
683 unit_index: CorticalUnitIndex,
684 channel_index: CorticalChannelIndex,
685 ) -> Result<&WrappedIOData, FeagiDataError> {
686 let motor_stream_caches =
687 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
688 motor_stream_caches.get_preprocessed_motor_value(channel_index)
689 }
690
691 fn try_read_postprocessed_cached_value(
692 &self,
693 motor_type: MotorCorticalUnit,
694 unit_index: CorticalUnitIndex,
695 channel_index: CorticalChannelIndex,
696 ) -> Result<&WrappedIOData, FeagiDataError> {
697 let motor_stream_caches =
698 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
699 motor_stream_caches.get_postprocessed_motor_value(channel_index)
700 }
701
702 fn try_register_motor_callback<F>(
703 &mut self,
704 motor_type: MotorCorticalUnit,
705 unit_index: CorticalUnitIndex,
706 channel_index: CorticalChannelIndex,
707 callback: F,
708 ) -> Result<FeagiSignalIndex, FeagiDataError>
709 where
710 F: Fn(&WrappedIOData) + Send + Sync + 'static,
711 {
712 let motor_stream_caches =
713 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
714 let index =
715 motor_stream_caches.try_connect_to_data_processed_signal(channel_index, callback)?;
716 Ok(index)
717 }
718
719 fn try_get_single_stage_properties(
724 &self,
725 motor_type: MotorCorticalUnit,
726 unit_index: CorticalUnitIndex,
727 channel_index: CorticalChannelIndex,
728 stage_index: PipelineStagePropertyIndex,
729 ) -> Result<PipelineStageProperties, FeagiDataError> {
730 let motor_stream_caches =
731 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
732 motor_stream_caches.try_get_single_stage_properties(channel_index, stage_index)
733 }
734
735 fn try_get_all_stage_properties(
736 &self,
737 motor_type: MotorCorticalUnit,
738 unit_index: CorticalUnitIndex,
739 channel_index: CorticalChannelIndex,
740 ) -> Result<Vec<PipelineStageProperties>, FeagiDataError> {
741 let motor_stream_caches =
742 self.try_get_motor_channel_stream_caches(motor_type, unit_index)?;
743 motor_stream_caches.get_all_stage_properties(channel_index)
744 }
745
746 fn try_update_single_stage_properties(
747 &mut self,
748 motor_type: MotorCorticalUnit,
749 unit_index: CorticalUnitIndex,
750 channel_index: CorticalChannelIndex,
751 pipeline_stage_property_index: PipelineStagePropertyIndex,
752 replacing_property: PipelineStageProperties,
753 ) -> Result<(), FeagiDataError> {
754 let motor_stream_caches =
755 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
756 motor_stream_caches.try_update_single_stage_properties(
757 channel_index,
758 pipeline_stage_property_index,
759 replacing_property,
760 )
761 }
762
763 fn try_update_all_stage_properties(
764 &mut self,
765 motor_type: MotorCorticalUnit,
766 unit_index: CorticalUnitIndex,
767 channel_index: CorticalChannelIndex,
768 new_pipeline_stage_properties: Vec<PipelineStageProperties>,
769 ) -> Result<(), FeagiDataError> {
770 let motor_stream_caches =
771 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
772 motor_stream_caches
773 .try_update_all_stage_properties(channel_index, new_pipeline_stage_properties)
774 }
775
776 fn try_replace_single_stage(
777 &mut self,
778 motor_type: MotorCorticalUnit,
779 unit_index: CorticalUnitIndex,
780 channel_index: CorticalChannelIndex,
781 replacing_at_index: PipelineStagePropertyIndex,
782 new_pipeline_stage_properties: PipelineStageProperties,
783 ) -> Result<(), FeagiDataError> {
784 let motor_stream_caches =
785 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
786 motor_stream_caches.try_replace_single_stage(
787 channel_index,
788 replacing_at_index,
789 new_pipeline_stage_properties,
790 )
791 }
792
793 fn try_replace_all_stages(
794 &mut self,
795 motor_type: MotorCorticalUnit,
796 unit_index: CorticalUnitIndex,
797 channel_index: CorticalChannelIndex,
798 new_pipeline_stage_properties: Vec<PipelineStageProperties>,
799 ) -> Result<(), FeagiDataError> {
800 let motor_stream_caches =
801 self.try_get_motor_channel_stream_caches_mut(motor_type, unit_index)?;
802 motor_stream_caches.try_replace_all_stages(channel_index, new_pipeline_stage_properties)
803 }
804
805 fn try_removing_all_stages(
806 &mut self,
807 sensor_type: MotorCorticalUnit,
808 unit_index: CorticalUnitIndex,
809 channel_index: CorticalChannelIndex,
810 ) -> Result<(), FeagiDataError> {
811 let motor_stream_cache =
812 self.try_get_motor_channel_stream_caches_mut(sensor_type, unit_index)?;
813 motor_stream_cache.try_removing_all_stages(channel_index)?;
814 Ok(())
815 }
816
817 fn try_get_motor_channel_stream_caches(
824 &self,
825 motor_type: MotorCorticalUnit,
826 unit_index: CorticalUnitIndex,
827 ) -> Result<&MotorCorticalUnitCache, FeagiDataError> {
828 let check = self
829 .motor_cortical_unit_caches
830 .get(&(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 fn try_get_motor_channel_stream_caches_mut(
842 &mut self,
843 motor_type: MotorCorticalUnit,
844 unit_index: CorticalUnitIndex,
845 ) -> Result<&mut MotorCorticalUnitCache, FeagiDataError> {
846 let check = self
847 .motor_cortical_unit_caches
848 .get_mut(&(motor_type, unit_index));
849 if check.is_none() {
850 return Err(FeagiDataError::BadParameters(format!(
851 "Unable to find {} of cortical unit index {} in registered motor's list!",
852 motor_type, unit_index
853 )));
854 }
855 let check = check.unwrap();
856 Ok(check)
857 }
858
859 }
863
864impl Default for MotorDeviceCache {
865 fn default() -> Self {
866 Self::new()
867 }
868}
869
870impl Display for MotorDeviceCache {
871 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
872 Ok(writeln!(f, "Motor Device Cache:")?)
873 }
874}