use core::fmt::Debug;
use core::mem::MaybeUninit;
use core::u16;
use fixed::types::{I1F15, I1F31};
use num_complex::{Complex, Complex32};
use crate::{Error, Result, StatusCode};
#[derive(Debug, Copy, Clone)]
pub enum Direction {
Forward = 0,
Inverse = 1,
}
#[derive(Debug, Copy, Clone)]
pub enum OutputOrder {
Raw = 0,
Standard = 1,
}
impl Default for OutputOrder {
fn default() -> Self {
OutputOrder::Standard
}
}
pub struct FloatRealFft(cmsis_dsp_sys::arm_rfft_fast_instance_f32);
unsafe impl Send for FloatRealFft {}
impl FloatRealFft {
#[inline]
pub fn new(size: u16) -> Result<Self> {
let mut data = MaybeUninit::<cmsis_dsp_sys::arm_rfft_fast_instance_f32>::uninit();
unsafe {
cmsis_dsp_sys::arm_rfft_fast_init_f32(data.as_mut_ptr(), size).check_status()?;
Ok(FloatRealFft(data.assume_init()))
}
}
#[inline]
pub fn run(&self, input: &mut [f32], output: &mut [f32]) {
self.run_inner(input, output, Direction::Forward);
}
#[inline]
pub fn run_inverse(&self, input: &mut [f32], output: &mut [f32]) {
self.run_inner(input, output, Direction::Inverse);
}
fn run_inner(&self, input: &mut [f32], output: &mut [f32], direction: Direction) {
assert_eq!(u32::from(self.0.fftLenRFFT), input.len() as u32);
assert_eq!(u32::from(self.0.fftLenRFFT), output.len() as u32);
unsafe {
cmsis_dsp_sys::arm_rfft_fast_f32(
&self.0 as *const _,
input.as_mut_ptr() as *mut _,
output.as_mut_ptr(),
direction as _,
);
}
}
}
pub struct Q15RealFft(cmsis_dsp_sys::arm_rfft_instance_q15);
unsafe impl Send for Q15RealFft {}
impl Q15RealFft {
#[inline]
pub fn new(size: u32, direction: Direction, output_order: OutputOrder) -> Result<Self> {
let mut data = MaybeUninit::<cmsis_dsp_sys::arm_rfft_instance_q15>::uninit();
unsafe {
cmsis_dsp_sys::arm_rfft_init_q15(
data.as_mut_ptr(),
size,
direction as _,
output_order as _,
)
.check_status()?;
Ok(Q15RealFft(data.assume_init()))
}
}
#[inline]
pub fn run(&self, input: &mut [I1F15], output: &mut [i16]) {
assert_eq!(self.0.fftLenReal, input.len() as u32);
assert_eq!(2u32 * self.0.fftLenReal, output.len() as u32);
unsafe {
cmsis_dsp_sys::arm_rfft_q15(&self.0, input.as_mut_ptr() as *mut _, output.as_mut_ptr());
}
}
}
pub struct Q31RealFft(cmsis_dsp_sys::arm_rfft_instance_q31);
unsafe impl Send for Q31RealFft {}
impl Q31RealFft {
#[inline]
pub fn new(size: u32, direction: Direction, output_order: OutputOrder) -> Result<Self> {
let mut data = MaybeUninit::<cmsis_dsp_sys::arm_rfft_instance_q31>::uninit();
unsafe {
cmsis_dsp_sys::arm_rfft_init_q31(
data.as_mut_ptr(),
size,
direction as _,
output_order as _,
)
.check_status()?;
Ok(Q31RealFft(data.assume_init()))
}
}
#[inline]
pub fn run(&self, input: &mut [I1F31], output: &mut [i32]) {
assert_eq!(self.0.fftLenReal, input.len() as u32);
assert_eq!(2u32 * self.0.fftLenReal, output.len() as u32);
unsafe {
cmsis_dsp_sys::arm_rfft_q31(&self.0, input.as_mut_ptr() as *mut _, output.as_mut_ptr());
}
}
}
pub struct FloatFft {
instance: *const cmsis_dsp_sys::arm_cfft_instance_f32,
}
unsafe impl Send for FloatFft {}
impl FloatFft {
#[inline]
pub fn new(size: u16) -> Result<Self> {
let instance = unsafe {
match size {
16 => &cmsis_dsp_sys::arm_cfft_sR_f32_len16,
32 => &cmsis_dsp_sys::arm_cfft_sR_f32_len32,
64 => &cmsis_dsp_sys::arm_cfft_sR_f32_len64,
128 => &cmsis_dsp_sys::arm_cfft_sR_f32_len128,
256 => &cmsis_dsp_sys::arm_cfft_sR_f32_len256,
512 => &cmsis_dsp_sys::arm_cfft_sR_f32_len512,
1024 => &cmsis_dsp_sys::arm_cfft_sR_f32_len1024,
2048 => &cmsis_dsp_sys::arm_cfft_sR_f32_len2048,
4096 => &cmsis_dsp_sys::arm_cfft_sR_f32_len4096,
_ => return Err(Error::Argument),
}
};
Ok(FloatFft { instance })
}
#[inline]
pub fn run(&self, data: &mut [Complex32], direction: Direction, output_order: OutputOrder) {
unsafe {
assert_eq!(u32::from((*self.instance).fftLen), data.len() as u32);
cmsis_dsp_sys::arm_cfft_f32(
self.instance,
data.as_mut_ptr() as *mut _,
direction as _,
output_order as _,
);
}
}
}
#[inline]
pub fn float_fft_128(data: &mut [Complex32; 128], direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len128,
data.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
pub fn fft<D>(data: &mut D, direction: Direction, output_order: OutputOrder)
where
D: FftBuffer,
{
data.run_fft(direction, output_order)
}
pub trait FftBuffer {
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder);
}
impl FftBuffer for [Complex32; 16] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len16,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 32] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len32,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 64] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len64,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 128] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len128,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 256] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len256,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 512] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len512,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 1024] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len1024,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 2048] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len2048,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
impl FftBuffer for [Complex32; 4096] {
#[inline]
fn run_fft(&mut self, direction: Direction, output_order: OutputOrder) {
unsafe {
cmsis_dsp_sys::arm_cfft_f32(
&cmsis_dsp_sys::arm_cfft_sR_f32_len4096,
self.as_mut_ptr() as *mut f32,
direction as _,
output_order as _,
);
}
}
}
pub struct Q15Fft {
instance: *const cmsis_dsp_sys::arm_cfft_instance_q15,
direction: Direction,
output_order: OutputOrder,
}
unsafe impl Send for Q15Fft {}
impl Q15Fft {
#[inline]
pub fn new(size: u16, direction: Direction, output_order: OutputOrder) -> Result<Self> {
let instance = unsafe {
match size {
16 => &cmsis_dsp_sys::arm_cfft_sR_q15_len16,
32 => &cmsis_dsp_sys::arm_cfft_sR_q15_len32,
64 => &cmsis_dsp_sys::arm_cfft_sR_q15_len64,
128 => &cmsis_dsp_sys::arm_cfft_sR_q15_len128,
256 => &cmsis_dsp_sys::arm_cfft_sR_q15_len256,
512 => &cmsis_dsp_sys::arm_cfft_sR_q15_len512,
1024 => &cmsis_dsp_sys::arm_cfft_sR_q15_len1024,
2048 => &cmsis_dsp_sys::arm_cfft_sR_q15_len2048,
4096 => &cmsis_dsp_sys::arm_cfft_sR_q15_len4096,
_ => return Err(Error::Argument),
}
};
Ok(Q15Fft {
instance,
direction,
output_order,
})
}
#[inline]
pub fn run(&self, data: &mut [Complex<I1F15>]) {
unsafe {
assert_eq!(u32::from((*self.instance).fftLen), data.len() as u32);
cmsis_dsp_sys::arm_cfft_q15(
self.instance,
data.as_mut_ptr() as *mut _,
self.direction as _,
self.output_order as _,
);
}
}
}
pub struct Q31Fft {
instance: *const cmsis_dsp_sys::arm_cfft_instance_q31,
}
unsafe impl Send for Q31Fft {}
impl Q31Fft {
#[inline]
pub fn new(size: u16) -> Result<Self> {
let instance = unsafe {
match size {
16 => &cmsis_dsp_sys::arm_cfft_sR_q31_len16,
32 => &cmsis_dsp_sys::arm_cfft_sR_q31_len32,
64 => &cmsis_dsp_sys::arm_cfft_sR_q31_len64,
128 => &cmsis_dsp_sys::arm_cfft_sR_q31_len128,
256 => &cmsis_dsp_sys::arm_cfft_sR_q31_len256,
512 => &cmsis_dsp_sys::arm_cfft_sR_q31_len512,
1024 => &cmsis_dsp_sys::arm_cfft_sR_q31_len1024,
2048 => &cmsis_dsp_sys::arm_cfft_sR_q31_len2048,
4096 => &cmsis_dsp_sys::arm_cfft_sR_q31_len4096,
_ => return Err(Error::Argument),
}
};
Ok(Q31Fft { instance })
}
#[inline]
pub fn run(
&self,
data: &mut [Complex<I1F31>],
direction: Direction,
output_order: OutputOrder,
) {
unsafe {
assert_eq!(u32::from((*self.instance).fftLen), data.len() as u32);
cmsis_dsp_sys::arm_cfft_q31(
self.instance,
data.as_mut_ptr() as *mut _,
direction as _,
output_order as _,
);
}
}
}