device-driver-codegen 2.0.0

Internal compiler crate for the device-driver toolkit
Documentation
{{self::description_to_docstring(field_set.description)}}
{{ self::maybe_doc_alias(field_set.name, Case::Pascal) }}
#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(transparent)]
pub struct {{field_set.name.to_case(Case::Pascal)}} {
    #[doc(hidden)]
    /// The internal bits
    bits: [u8; {{field_set.size_bytes}}]
}

unsafe impl ::device_driver::Fieldset for {{field_set.name.to_case(Case::Pascal)}} {
    const METADATA: ::device_driver::FieldsetMetadata =
        ::device_driver::FieldsetMetadata::new()
            .with_byte_order(::device_driver::ByteOrder::{{field_set.byte_order}});
    const ZERO: Self = Self { bits: [0; {{field_set.size_bytes}}] };
}

impl {{field_set.name.to_case(Case::Pascal)}} {
    {% for field in field_set.fields %}
        {% if matches!(field.access, Access::RW | Access::RO) %}
            /// `{{field.address_text()}}` - Read the `{{field.name.to_case(Case::Snake)}}` field.
            ///
            {{ self::description_to_docstring(field.description) }}
            {{ self::maybe_doc_alias(field.name, Case::Snake) }}
            #[must_use]
            pub fn {{field.name.to_case(Case::Snake)}}(
                &self,
                {% match field.repeat %}
                    {% when Repeat::None %}
                    {% when Repeat::Count { .. } %} index: usize
                    {% when Repeat::Enum { enum_name, .. } %} index: {{enum_name.to_case(Case::Pascal)}}
                {% endmatch %}
            ) -> 
                {% match field.conversion_method %}
                    {% when FieldConversionMethod::None %} {{field.base_type}}
                    {% when FieldConversionMethod::Into(t) | FieldConversionMethod::UnsafeInto(t) %} {{t.to_case(Case::Pascal)}}
                    {% when FieldConversionMethod::TryInto(t) %} Result<{{t.to_case(Case::Pascal)}}, <{{t.to_case(Case::Pascal)}} as TryFrom<{{field.base_type}}>>::Error>
                    {% when FieldConversionMethod::Bool %} bool
                {% endmatch %}
            {
                {% match field.repeat %}
                    {% when Repeat::None %}
                    let start = {{field.address.start}};
                    let end = {{field.address.end}};
                    {% when Repeat::Count { count, stride } %}
                    assert!(index < {{count}});
                    let start = {{field.address.start}} + index * {{stride}};
                    let end = start + {{field.address.len()}};
                    {% when Repeat::Enum { enum_name, stride, .. } %}
                    let start = {{field.address.start}} + {{self::get_enum_base_type(driver, &enum_name)}}::from(index) as usize * {{stride}};
                    let end = start + {{field.address.len()}};
                {% endmatch %}

                let raw = unsafe {
                    ::device_driver::ops::load::<
                        {{field.base_type}},
                        ::device_driver::ops::{{field_set.byte_order}},
                    >(&self.bits, start, end)
                };

                {% match field.conversion_method %}
                    {% when FieldConversionMethod::None %} raw
                    {% when FieldConversionMethod::Into(t) %} raw.into()
                    {% when FieldConversionMethod::UnsafeInto(t) %} unsafe { raw.try_into().unwrap_unchecked() }
                    {% when FieldConversionMethod::TryInto(t) %} raw.try_into()
                    {% when FieldConversionMethod::Bool %} raw > 0
                {% endmatch %}
            }
        {% endif %}
    {% endfor %}

    {% for field in field_set.fields %}
        {% if matches!(field.access, Access::RW | Access::WO) %}
            /// `{{field.address_text()}}` - Set the `{{field.name.to_case(Case::Snake)}}` field.
            ///
            {{ self::description_to_docstring(field.description) }}
            {{ self::maybe_doc_alias(field.name, Case::Snake) }}
            pub fn set_{{field.name.to_case(Case::Snake)}}(
                &mut self,
                {% match field.repeat %}
                    {% when Repeat::None %}
                    {% when Repeat::Count { .. } %} index: usize,
                    {% when Repeat::Enum { enum_name, .. } %} index: {{enum_name.to_case(Case::Pascal)}},
                {% endmatch %}
                value: {% match field.conversion_method %}
                    {% when FieldConversionMethod::None %} {{field.base_type}}
                    {% when FieldConversionMethod::Into(t) %} {{t.to_case(Case::Pascal)}}
                    {% when FieldConversionMethod::UnsafeInto(t) %} {{t.to_case(Case::Pascal)}}
                    {% when FieldConversionMethod::TryInto(t) %} {{t.to_case(Case::Pascal)}}
                    {% when FieldConversionMethod::Bool %} bool
                {% endmatch %}
            ) {
                {% match field.repeat %}
                    {% when Repeat::None %}
                    let start = {{field.address.start}};
                    let end = {{field.address.end}};
                    {% when Repeat::Count { count, stride } %}
                    assert!(index < {{count}});
                    let start = {{field.address.start}} + index * {{stride}};
                    let end = start + {{field.address.len()}};
                    {% when Repeat::Enum { enum_name, stride, .. } %}
                    let start = {{field.address.start}} + {{self::get_enum_base_type(driver, &enum_name)}}::from(index) as usize * {{stride}};
                    let end = start + {{field.address.len()}};
                {% endmatch %}

                let raw = 
                {% match field.conversion_method %}
                    {% when FieldConversionMethod::None %} value;
                    {% when FieldConversionMethod::Bool %} value as _;
                    {% else %} value.into();
                {% endmatch %}

                unsafe {
                    ::device_driver::ops::store::<
                        {{field.base_type}},
                        ::device_driver::ops::{{field_set.byte_order}},
                    >(raw, start, end, &mut self.bits)
                };
            }
        {% endif %}
    {% endfor %}
}

impl Default for {{field_set.name.to_case(Case::Pascal)}} {
    fn default() -> Self {
        <Self as ::device_driver::Fieldset>::ZERO
    }
}

impl From<[u8; {{field_set.size_bytes}}]> for {{field_set.name.to_case(Case::Pascal)}} {
    fn from(bits: [u8; {{field_set.size_bytes}}]) -> Self {
        Self { bits }
    }
}

impl From<{{field_set.name.to_case(Case::Pascal)}}> for [u8; {{field_set.size_bytes}}] {
    fn from(val: {{field_set.name.to_case(Case::Pascal)}}) -> Self {
        val.bits
    }
}

impl core::fmt::Debug for {{field_set.name.to_case(Case::Pascal)}} {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
        let mut d = f.debug_struct("{{field_set.name.to_case(Case::Pascal)}}");
        {% for field in field_set.fields %}
            {% if field.access.is_readable() %}
                {% match field.repeat %}
                    {% when Repeat::None %}
                        d.field("{{field.name.to_case(Case::Snake)}}", &self.{{field.name.to_case(Case::Snake)}}());
                    {% when Repeat::Count { count, .. } %}
                        {% for index in 0..*count %}
                            d.field("{{field.name.to_case(Case::Snake)}}[{{index}}]", &self.{{field.name.to_case(Case::Snake)}}({{index}}));
                        {% endfor %}
                    {% when Repeat::Enum { enum_name, enum_variants, .. } %}
                        {% for variant in enum_variants %}
                            d.field("{{field.name.to_case(Case::Snake)}}[{{variant.to_case(Case::Pascal)}}]", &self.{{field.name.to_case(Case::Snake)}}({{enum_name.to_case(Case::Pascal)}}::{{variant.to_case(Case::Pascal)}}));
                        {% endfor %}
                {% endmatch %}
            {% endif %}
        {% endfor %}
        d.finish()
    }
}

{% if let Some(defmt_feature) = defmt_feature() %}
#[cfg(feature = "{{defmt_feature}}")]
impl defmt::Format for {{field_set.name.to_case(Case::Pascal)}} {
    fn format(&self, f: defmt::Formatter) {
        defmt::write!(f, "{{field_set.name.to_case(Case::Pascal)}} {% raw %}{{{% endraw %} ");

        {% for field in field_set.fields %}
            {% if field.access.is_readable() %}
                {% match field.repeat %}
                    {% when Repeat::None %}
                        defmt::write!(f, "{{self::get_defmt_fmt_string(field)}}", &self.{{field.name.to_case(Case::Snake)}}());
                    {% when Repeat::Count { count, .. } %}
                        {% for index in 0..*count %}
                            defmt::write!(f, "{{self::get_defmt_fmt_string(field)}}[{{index}}]", &self.{{field.name.to_case(Case::Snake)}}({{index}}));
                        {% endfor %}
                    {% when Repeat::Enum { enum_name, enum_variants, .. } %}
                        {% for variant in enum_variants %}
                            defmt::write!(f, "{{self::get_defmt_fmt_string(field)}}[{{variant.to_case(Case::Pascal)}}]", &self.{{field.name.to_case(Case::Snake)}}({{enum_name.to_case(Case::Pascal)}}::{{variant.to_case(Case::Pascal)}}));
                        {% endfor %}
                {% endmatch %}
            {% endif %}
        {% endfor %}

        defmt::write!(f, "{% raw %}}}{% endraw %}");
    }
}
{% endif %}

impl core::ops::BitAnd for {{field_set.name.to_case(Case::Pascal)}} {
    type Output = Self;
    fn bitand(mut self, rhs: Self) -> Self::Output {
        self &= rhs;
        self
    }
}
impl core::ops::BitAndAssign for {{field_set.name.to_case(Case::Pascal)}} {
    fn bitand_assign(&mut self, rhs: Self) {
        for (l, r) in self.bits.iter_mut().zip(&rhs.bits) {
            *l &= *r;
        }
    }
}
impl core::ops::BitOr for {{field_set.name.to_case(Case::Pascal)}} {
    type Output = Self;
    fn bitor(mut self, rhs: Self) -> Self::Output {
        self |= rhs;
        self
    }
}
impl core::ops::BitOrAssign for {{field_set.name.to_case(Case::Pascal)}} {
    fn bitor_assign(&mut self, rhs: Self) {
        for (l, r) in self.bits.iter_mut().zip(&rhs.bits) {
            *l |= *r;
        }
    }
}
impl core::ops::BitXor for {{field_set.name.to_case(Case::Pascal)}} {
    type Output = Self;
    fn bitxor(mut self, rhs: Self) -> Self::Output {
        self ^= rhs;
        self
    }
}
impl core::ops::BitXorAssign for {{field_set.name.to_case(Case::Pascal)}} {
    fn bitxor_assign(&mut self, rhs: Self) {
        for (l, r) in self.bits.iter_mut().zip(&rhs.bits) {
            *l ^= *r;
        }
    }
}
impl core::ops::Not for {{field_set.name.to_case(Case::Pascal)}} {
    type Output = Self;
    fn not(mut self) -> Self::Output {
        for val in self.bits.iter_mut() {
            *val = !*val;
        }
        self
    }
}