feagi_structures/genomic/
motor_cortical_unit.rs1use crate::genomic::cortical_area::descriptors::CorticalSubUnitIndex;
2use crate::genomic::cortical_area::descriptors::CorticalUnitIndex;
3use crate::genomic::cortical_area::io_cortical_area_configuration_flag::{
4 FrameChangeHandling, PercentageNeuronPositioning,
5};
6use crate::genomic::cortical_area::{
7 CorticalAreaType, CorticalID, IOCorticalAreaConfigurationFlag,
8};
9use crate::genomic::sensory_cortical_unit::UnitTopology;
10use crate::motor_cortical_units;
11use paste;
12use serde_json::{Map, Value};
13use std::collections::HashMap;
14use std::fmt::{Display, Formatter};
15
16#[macro_export]
18macro_rules! get_allowed_frame_change_handling_impl { () => {
20 None
21 };
22 ($($allowed:ident),+) => {
23 Some(&[$(FrameChangeHandling::$allowed),+] as &'static [FrameChangeHandling])
24 };
25}
26
27macro_rules! define_motor_cortical_units_enum {
28 (
29 MotorCorticalUnit {
30 $(
31 $(#[doc = $doc:expr])?
32 $variant_name:ident => {
33 friendly_name: $friendly_name:expr,
34 accepted_wrapped_io_data_type: $accepted_wrapped_io_data_type:expr,
35 cortical_id_unit_reference: $cortical_id_unit_reference:expr,
36 number_cortical_areas: $number_cortical_areas:expr,
37 cortical_type_parameters: {
38 $($param_name:ident: $param_type:ty),* $(,)?
39 },
40 $(allowed_frame_change_handling: [$($allowed_frame:ident),* $(,)?],)? cortical_area_properties: {
42 $($cortical_sub_unit_index:tt => ($io_cortical_area_configuration_flag_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])),* $(,)?
43 }
44 }
45 ),* $(,)?
46 }
47 ) => {
48 #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, serde::Deserialize, serde::Serialize)]
49 pub enum MotorCorticalUnit {
50 $(
51 $(#[doc = $doc])?
52 $variant_name,
53 )*
54 }
55
56 impl MotorCorticalUnit {
57 $(
58 paste::paste! {
59 #[doc = "Get cortical area types array for " $friendly_name "."]
60 pub const fn [<get_cortical_area_types_array_for_ $variant_name:snake _with_parameters >](
61 $($param_name: $param_type),*) -> [CorticalAreaType; $number_cortical_areas] {
62 $(let _ = &$param_name;)*
64 [
65 $(CorticalAreaType::BrainOutput($io_cortical_area_configuration_flag_expr)),*
66 ]
67 }
68
69 #[doc = "Get cortical IDs array for " $friendly_name "."]
70 pub const fn [<get_cortical_ids_array_for_ $variant_name:snake _with_parameters >](
71 $($param_name: $param_type,)* cortical_unit_index: CorticalUnitIndex) -> [CorticalID; $number_cortical_areas] {
72 $(let _ = &$param_name;)*
74 let cortical_unit_identifier: [u8; 3] = $cortical_id_unit_reference;
75 [
76 $(
77 $io_cortical_area_configuration_flag_expr .as_io_cortical_id(false, cortical_unit_identifier, cortical_unit_index, CorticalSubUnitIndex::from($cortical_sub_unit_index))
78 ),*
79 ]
80 }
81 }
82 )*
83
84 pub const fn get_snake_case_name(&self) -> &'static str {
85 match self {
86 $(
87 MotorCorticalUnit::$variant_name => paste::paste!{ stringify!([<$variant_name:snake>]) },
88 )*
89 }
90 }
91
92 pub const fn get_accepted_wrapped_io_data_type(&self) -> &'static str {
95 match self {
96 $(
97 MotorCorticalUnit::$variant_name => stringify!($variant_name:snake),
98 )*
99 }
100 }
101
102 pub fn from_snake_case_name(name: &str) -> Option<MotorCorticalUnit> {
111 match name {
112 $(
113 paste::paste!{ stringify!([<$variant_name:snake>]) } => Some(MotorCorticalUnit::$variant_name),
114 )*
115 _ => None,
116 }
117 }
118
119 pub const fn list_all() -> &'static [MotorCorticalUnit] {
124 &[
125 $(
126 MotorCorticalUnit::$variant_name,
127 )*
128 ]
129 }
130
131 pub const fn get_friendly_name(&self) -> &'static str {
133 match self {
134 $(
135 MotorCorticalUnit::$variant_name => $friendly_name,
136 )*
137 }
138 }
139
140 pub const fn get_cortical_id_unit_reference(&self) -> [u8; 3] {
142 match self {
143 $(
144 MotorCorticalUnit::$variant_name => $cortical_id_unit_reference,
145 )*
146 }
147 }
148
149 pub const fn get_number_cortical_areas(&self) -> usize {
151 match self {
152 $(
153 MotorCorticalUnit::$variant_name => $number_cortical_areas,
154 )*
155 }
156 }
157
158 pub fn get_unit_default_topology(&self) -> HashMap<CorticalSubUnitIndex, UnitTopology> {
160 match self {
161 $(
162 MotorCorticalUnit::$variant_name => {
163 let mut topology = HashMap::new();
164 $(
165 topology.insert(
166 CorticalSubUnitIndex::from($cortical_sub_unit_index),
167 UnitTopology {
168 relative_position: [$rel_x, $rel_y, $rel_z],
169 channel_dimensions_default: [$dim_default_x, $dim_default_y, $dim_default_z],
170 channel_dimensions_min: [$dim_min_x, $dim_min_y, $dim_min_z],
171 channel_dimensions_max: [$dim_max_x, $dim_max_y, $dim_max_z],
172 }
173 );
174 )*
175 topology
176 }
177 )*
178 }
179 }
180
181 pub fn get_allowed_frame_change_handling(&self) -> Option<&'static [FrameChangeHandling]> {
185 match self {
186 $(
187 MotorCorticalUnit::$variant_name => {
188 $crate::get_allowed_frame_change_handling_impl!($($($allowed_frame),*)?)
189 }
190 )*
191 }
192 }
193
194 pub fn get_cortical_id_vector_from_index_and_serde_io_configuration_flags(&self, cortical_unit_index: CorticalUnitIndex, map: Map<String, Value>) -> Result<Vec<CorticalID>, crate::FeagiDataError> {
195 match self {
196 $(
197 MotorCorticalUnit::$variant_name => {
198 paste::paste! {
199 let array = MotorCorticalUnit::[<get_cortical_ids_array_for_ $variant_name:snake _with_parameters >](
200 $($param_type::try_from_serde_map(&map)?,)*
201 cortical_unit_index);
202 return Ok(array.to_vec());
203 }
204 }
205 )*
206 }
207 }
208
209 }
210
211 impl Display for MotorCorticalUnit {
212 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
213 match self {
214 $(
215 MotorCorticalUnit::$variant_name => write!(f, $friendly_name),
216 )*
217 }
218 }
219 }
220 };
221
222}
223motor_cortical_units!(define_motor_cortical_units_enum);
225
226impl MotorCorticalUnit {
227 pub fn try_from_legacy_subtype(subtype: &str) -> Option<CorticalID> {
230 let subtype_bytes = subtype.as_bytes();
231 if subtype_bytes.len() != 3 {
232 return None;
233 }
234 let subtype_arr = [subtype_bytes[0], subtype_bytes[1], subtype_bytes[2]];
235 for unit in Self::list_all() {
236 if unit.get_cortical_id_unit_reference() == subtype_arr {
237 return Some(unit.get_default_cortical_id_for_group(CorticalUnitIndex::from(0u8)));
238 }
239 }
240 None
241 }
242
243 pub fn get_default_cortical_id_for_group(&self, group_index: CorticalUnitIndex) -> CorticalID {
245 use crate::genomic::cortical_area::io_cortical_area_configuration_flag::{
246 FrameChangeHandling, PercentageNeuronPositioning,
247 };
248 let fh = FrameChangeHandling::Absolute;
249 let pos = PercentageNeuronPositioning::Linear;
250 match self {
251 MotorCorticalUnit::RotaryMotor => {
252 Self::get_cortical_ids_array_for_rotary_motor_with_parameters(fh, pos, group_index)
253 [0]
254 }
255 MotorCorticalUnit::PositionalServo => {
256 Self::get_cortical_ids_array_for_positional_servo_with_parameters(
257 FrameChangeHandling::Absolute,
258 pos,
259 group_index,
260 )[0]
261 }
262 MotorCorticalUnit::Gaze => {
263 Self::get_cortical_ids_array_for_gaze_with_parameters(fh, pos, group_index)[0]
264 }
265 MotorCorticalUnit::MiscData => {
266 Self::get_cortical_ids_array_for_misc_data_with_parameters(fh, group_index)[0]
267 }
268 MotorCorticalUnit::TextEnglishOutput => {
269 Self::get_cortical_ids_array_for_text_english_output_with_parameters(
270 fh,
271 group_index,
272 )[0]
273 }
274 MotorCorticalUnit::CountOutput => {
275 Self::get_cortical_ids_array_for_count_output_with_parameters(fh, pos, group_index)
276 [0]
277 }
278 MotorCorticalUnit::ObjectSegmentation => {
279 Self::get_cortical_ids_array_for_object_segmentation_with_parameters(
280 fh,
281 group_index,
282 )[0]
283 }
284 MotorCorticalUnit::SimpleVisionOutput => {
285 Self::get_cortical_ids_array_for_simple_vision_output_with_parameters(
286 fh,
287 group_index,
288 )[0]
289 }
290 MotorCorticalUnit::DynamicImageProcessing => {
291 Self::get_cortical_ids_array_for_dynamic_image_processing_with_parameters(
292 fh,
293 pos,
294 group_index,
295 )[0]
296 }
297 }
298 }
299}