// Copyright 2025 RnD Center "ELVEES", JSC

/*! \file
 *  \brief Заголовочный файл со структурами и функциями для управления вычислениями
 */

#ifndef _FFT
#define _FFT

#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "elcore50-signal-lib/DMAInit.h"
#include "elcore50-signal-lib/types_converter.h"

//! Максимальный размер сигнала, помещающегося во внутреннюю память
#define MAX_FFT_BUF_SIZE (512 * 2 * 16 * 4)
//! Размер буфера поворотов для максимального сигнала
#define MAX_FFT_W_BUF_SIZE ((3 * 512 * 4) / 4)
//! Максимальный размер буфера во внутренней памяти
#define MAX_FFT_PLACE_SIZE (16384 * 2 * 4)

#pragma pack(push, 1)

//! Массивы данных, выгружаемых во внутреннюю память с dma
typedef struct sl_tdma_bufs {
  char x_d0[MAX_FFT_BUF_SIZE] __attribute__((aligned(32)));   ///< первый входной блок
  char x_r0[MAX_FFT_BUF_SIZE] __attribute__((aligned(32)));   ///< первый выходной блок
  char x_d1[MAX_FFT_BUF_SIZE] __attribute__((aligned(32)));   ///< второй входной блок
  char x_r1[MAX_FFT_BUF_SIZE] __attribute__((aligned(32)));   ///< второй выходной блок
  char t_d0[MAX_FFT_BUF_SIZE] __attribute__((aligned(32)));   ///< первый блок поворотов
  char t_d1[MAX_FFT_BUF_SIZE] __attribute__((aligned(32)));   ///< второй блок поворотов
  char w_d[MAX_FFT_W_BUF_SIZE] __attribute__((aligned(32)));  ///< блок поворотов столбцов/строк
} sl_tdma_bufs;

//! Входной и выходной массивы во внутренней памяти
typedef struct sl_tinplace_bufs {
  char src[MAX_FFT_PLACE_SIZE] __attribute__((aligned(32)));  ///< входной сигнал
  char dst[MAX_FFT_PLACE_SIZE] __attribute__((aligned(32)));  ///< результат преобразования
} sl_tinplace_bufs;

#pragma pack(pop)

//! Структуры для вычислений во внутренней памяти
union sl_tint_mem_bufs {
  struct sl_tdma_bufs dma_bufs;          ///< для вычислений с dma
  struct sl_tinplace_bufs inplace_bufs;  ///< для вычислений без dma
};

//! Цепочки dma
typedef struct fft_dma_chains {
  VDMAChain ch_in;        ///< цепочка входных блоков
  VDMAChain ch_out;       ///< цепочка выходных блоков
  VDMAChain ch_twiddles;  ///< цепочка блоков поворотов
} fft_dma_chains;

//! Тип данных преобразования
typedef enum sl_data_types {
  SL_FLOAT = 1,       ///< float32
  SL_FRACTIONAL = 2,  ///< fractional16
  SL_HFLOAT = 3       ///< float16
} sl_data_types;

//! Размерность пространства
typedef enum sl_dimensions {
  SL_1D = 1,  ///< одномерное
  SL_2D = 2   ///< двумерное
} sl_dimensions;

//! Тип вычислений
typedef enum sl_data_memory {
  SL_DDR = 0,   ///< во внешней памяти
  SL_XYRAM = 1  ///< во внутренней памяти
} sl_data_memory;

//! Тип преобразования
typedef enum sl_transform_type {
  SL_IFFT = 0,  ///< обратное
  SL_FFT = 1    ///< прямое
} sl_transform_type;

//! Объект преобразования
typedef struct {
  sl_dimensions dim;       ///< размерность пространства
  int size;                ///< размер преобразования
  int height;              ///< количество строк матрицы при переходе к 2D представлению
  int length;              ///< количество столбцов матрицы при переходе к 2D представлению
  void *w_cols;            ///< вектор поворотов столбцов
  void *w_rows;            ///< вектор поворотов строк
  void *t;                 ///< вектор поворотов промежуточного этапа
  void *src;               ///< входной сигнал
  void *dst;               ///< результат преобразования
  sl_transform_type dir;   ///< флаг типа преобразования
  int big_size;            ///< флаг преобразования большого размера: > 16K для типа float32,
                           ///<  > 32K для типов fractional16 и float16
  sl_data_types fft_type;  ///< тип данных преобразования
  int element_size;        ///< размер типа в байтах
  sl_data_memory int_mem;  ///< флаг типа вычислений
  int ticks;               ///< количество тактов
  int instrs;              ///< количество инструкций
} fft_t;

//! Оконные функции
typedef enum sl_fir_window_type {
  HAMMING,           /// Непараметрическое окно Хемминга
  NUTTALL,           /// Непараметрическое окно Натталла
  BLACKMAN,          /// Непараметрическое окно Блэкмана
  BLACKMAN_HARRIS,   /// Непараметрическое окно Блэкмана-Харриса
  BLACKMAN_NUTTALL,  /// Непараметрическое окно Блэкмана-Натталла
  HANN,              /// Непараметрическое окно Ханна
  LANCZOS,           /// Непараметрическое окно Ланцоша
  BARTLETT,          /// Непараметрическое окно Бартлетта
  CHEBWIN            /// Параметрическое окно Дольф-Чебышева
} sl_fir_window_type;

//! Типы фильтров
typedef enum sl_filter_type {
  LOWPASS,   /// Фильтр нижних частот
  HIGHPASS,  /// Фильтр верхних частот
  BANDPASS,  /// Полосовой фильтр
  BANDSTOP   /// Режекторный фильтр
} sl_filter_type;

// Error codes
#define SL_SUCCESS 0
#define SL_MAX_SIZE_RESTRICTION_EXCEEDED -1
#define SL_INVALID_POINTER -2
#define SL_INVALID_SIGNAL_SIZE -3
#define SL_INVALID_DATA_TYPE -4
#define SL_INVALID_FILTER_TYPE -5
#define SL_INVALID_WINDOW -6
#define SL_INVALID_CUTOFF_FREQUENCY -7
#define SL_DMACHAIN_CREATION_FAILURE -8

/// Обработка кодов возврата
void print_error_message(const int error_code  ///< [in] код возврата
);

/// Создание одномерного объекта преобразования
/// @return код статуса
int fft_plan_1d(fft_t *fft_obj,         ///< [in] входные данные типа fft_t
                int size,               ///< [in] количество комплексных элементов
                sl_data_types fft_type  ///< [in] тип данных преобразования
);
/// Создание двумерного объекта преобразования
/// @return код статуса
int fft_plan_2d(fft_t *fft_obj,         ///< [in] входные данные типа fft_t
                const int height,       ///< [in] количество элементов в столбце
                const int length,       ///< [in] количество комплексных элементов в строке
                sl_data_types fft_type  ///< [in] тип данных преобразовани
);
/// Управление вычислениями
/// @return код статуса
int fft_execute(fft_t *fft_obj  ///< [in] входные данные типа fft_t
);
///  Очищение памяти после вычислений
void fft_free_sources(fft_t *fft_obj  ///< [in] входные данные типа fft_t
);
/// Создание dma цепочки
/// @return код статуса
int create_vdma_fft_chain(const fft_t *fft_obj,  ///< [in] входные данные типа fft_t
                          fft_dma_chains *chain  ///< [out] выходные данные типа fft_dma_chains
);
/// Вычисление одномерной быстрой БПФ-свертки
/// @return код статуса
int fft_conv_1d(float *src0,                           ///< [in] первый входной массив
                float *src1,                           ///< [in] второй входной массив
                float *dst,                            ///< [out] выходные данные
                const int32_t size,                    ///< [in] количество комплексных элементов входного массива
                const sl_data_memory is_data_in_xyram  ///< [in] где размещены входные данные
);
/// Вычисление двумерной быстрой БПФ-свертки
/// @return код статуса
int fft_conv_2d(float *src0,                           ///< [in] первый входной массив
                float *src1,                           ///< [in] второй входной массив
                float *dst,                            ///< [out] выходные данные
                const int32_t rows,                    ///< [in] количество элементов в столбце
                const int32_t cols,                    ///< [in] количество комплексных элементов в строке
                const sl_data_memory is_data_in_xyram  ///< [in] где размещены входные данные
);

/// Вычисление функции оконного взвешивания
/// @return код статуса
int get_window(float *w,                           ///< [out] массив с вычисленной функцией
               const int32_t n,                    ///< [in] размер оконной функции (количество комплексных элементов)
               const sl_fir_window_type win_type,  ///< [in] тип окна
               const int8_t is_symmetric,          ///< [in] симметричное или периодическое окно
               float param                         ///< [in] параметр для параметрического окна
);
/// Вычисление коэффициентов КИХ-фильтра нижних частот
/// @return код статуса
int fir_lpf(float *h,                           ///< [out] массив с вычисленными коэффициентами
            const int32_t ord,                  ///< [in] порядок фильтра
            const float wp,                     ///< [in] частота среза
            const sl_fir_window_type win_type,  ///< [in] тип окна
            const int8_t is_symmetric,          ///< [in] симметричное или периодическое окно
            float param                         ///< [in] параметр для параметрического окна
);
/// Вычисление коэффициентов КИХ-фильтра методом оконного взвешивания
/// @return код статуса
int fir_window(
    float *h,           ///< [out] массив с вычисленными коэффициентами
    const int32_t ord,  ///< [in] порядок фильтра (количество комплексных элементов)
    const float w0,     ///< [in] частота среза ФНЧ или левая частота среза для полосового и режекторного фильтров
    const float w1,     ///< [in] частота среза ФВЧ или правая частота среза для полосового и режекторного фильтров
    const sl_filter_type filter_type,   ///< [in] тип фильтра
    const sl_fir_window_type win_type,  ///< [in] тип окна
    const int8_t is_symmetric,          ///< [in] симметричное или периодическое окно
    float param                         ///< [in] параметр для параметрического окна
);
/// Фильтрация сигнала с использованием цифровых фильтров
/// @return код статуса
int lfilter(float *b,           ///< [in] коэффициенты числителя передаточной характеристики фильтра
            float *a,           ///< [in] коэффициенты знаменателя передаточной характеристики фильтра
            const int16_t ord,  ///< [in] порядок фильтра
            float *x,           ///< [in] входной сигнал для фильтрации
            const int16_t n,    ///< [in] количество комплексных элементов во входном сигнале
            float *y,           ///< [out] отфильтрованный сигнал
            const sl_data_memory is_data_in_xyram  ///< [in] где размещены входные данные
);

/// Вычисление БПФ по столбцам/строкам для типа float
extern void fft_float_cols_inter(void *dst,             ///< [out] выходные данные
                                 void *src,             ///< [in] входные данные
                                 int height,            ///< [in] количество строк входной матрицы сигнала
                                 const void *twiddles,  ///< [in] вектор поворотов столбцов/строк
                                 int length,            ///< [in] количество столбцов входной матрицы сигнала
                                 void *temp,            ///< [in] копия выходной матрицы
                                 int stage              ///< [in] номер этапа преобразования
);
/// Вычисление БПФ по столбцам/строкам для типа float с использованием dma
extern void fft_float_cols_inter_dma_tiles(void *dst,       ///< [out] выходные данные
                                           void *src,       ///< [in] входные данные
                                           int height,      ///< [in] количество строк входной матрицы сигнала
                                           void *twiddles,  ///< [in] вектор поворотов столбцов/строк
                                           int length,      ///< [in] количество столбцов входной матрицы сигнала
                                           void *temp,      ///< [in] копия выходной матрицы
                                           int stage        ///< [in] номер этапа преобразования
);
/// Вычисление обратного БПФ по столбцам/строкам для типа fractional16
extern void fft_fract_cols_inv(void *dst,       ///< [out] выходные данные
                               void *src,       ///< [in] входные данные
                               int height,      ///< [in] количество строк входной матрицы сигнала
                               void *twiddles,  ///< [in] вектор поворотов столбцов/строк
                               int length,      ///< [in] количество столбцов входной матрицы сигнала
                               void *temp,      ///< [in] копия выходной матрицы
                               int stage        ///< [in] номер этапа преобразования
);
/// Вычисление прямого БПФ по столбцам/строкам для типа fractional16
extern void fft_fract_cols(void *dst,       ///< [out] выходные данные
                           void *src,       ///< [in] входные данные
                           int height,      ///< [in] количество строк входной матрицы сигнала
                           void *twiddles,  ///< [in] вектор поворотов столбцов/строк
                           int length,      ///< [in] количество столбцов входной матрицы сигнала
                           void *temp,      ///< [in] копия выходной матрицы
                           int stage        ///< [in] номер этапа преобразования
);
/// Вычисление БПФ по столбцам/строкам для типа float16
extern void fft_hfloat_cols(void *dst,       ///< [out] выходные данные
                            void *src,       ///< [in] входные данные
                            int height,      ///< [in] количество строк входной матрицы сигнала
                            void *twiddles,  ///< [in] вектор поворотов столбцов/строк
                            int length,      ///< [in] количество столбцов входной матрицы сигнала
                            void *temp,      ///< [in] копия выходной матрицы
                            int stage        ///< [in] номер этапа преобразования
);

/// Вычисление поворотов столбцов/строк для типа float
extern void fft_twiddles_cols_gen(void *w,  ///< [out] выходные данные
                                  int size  ///< [in] размер входных данных
);
/// Вычисление поворотов для типа float
extern void fft_twiddles_t_gen_inter(void *t,     ///< [out] выходные данные
                                     int size,    ///< [in] размер входных данных
                                     int height,  ///< [in] количество строк входной матрицы
                                     int length   ///< [in] количество столбцов входной матрицы
);

/// Вычисление поворотов столбцов/строк для типа fractional16
extern void fft_fract_twiddles_cols_gen(void *w,  ///< [out] выходные данные
                                        int size  ///< [in] размер входных данных
);
/// Вычисление поворотов для типа fractional16
extern void fft_fract_twiddles_t_gen(void *t,     ///< [out] выходные данные
                                     int size,    ///< [in] размер входных данных
                                     int height,  ///< [in] количество строк входной матрицы
                                     int length   ///< [in] количество столбцов входной матрицы
);

/// Вычисление поворотов столбцов/строк для типа float16
extern void fft_hfloat_twiddles_cols_gen(void *w,  ///< [out] выходные данные
                                         int size  ///< [in] размер входных данных
);
/// Вычисление поворотов для типа float16
extern void fft_hfloat_twiddles_t_gen(void *t,     ///< [out] выходные данные
                                      int size,    ///< [in] размер входных данных
                                      int height,  ///< [in] количество строк входной матрицы
                                      int length   ///< [in] количество столбцов входной матрицы
);

/// Умножение на матрицу поворотов и транспонирование матрицы типа float
extern void fft_mult_and_transpose_inter(void *dst,       ///< [out] выходные данные
                                         void *src,       ///< [in] входные данные
                                         int src_height,  ///< [in] количество строк входной матрицы
                                         int src_length,  ///< [in] количество столбцов входной матрицы
                                         void *T          ///< [in] матрица поворотов
);
/// Умножение на матрицу поворотов и транспонирование матрицы типа float
extern void fft_mult_and_transpose(void *dst,       ///< [out] выходные данные
                                   void *src,       ///< [in] входные данные
                                   int src_height,  ///< [in] количество строк входной матрицы
                                   int src_length,  ///< [in] количество столбцов входной матрицы
                                   void *T          ///< [in] матрица поворотов
);
/// Умножение на матрицу поворотов и транспонирование матрицы типа fractional16
extern void fft_mult_and_transpose_fract(void *dst,       ///< [out] выходные данные
                                         void *src,       ///< [in] входные данные
                                         int src_height,  ///< [in] количество строк входной матрицы
                                         int src_length,  ///< [in] количество столбцов входной матрицы
                                         void *T          ///< [in] матрица поворотов
);
/// Умножение на матрицу поворотов и транспонирование матрицы типа float16
extern void fft_mult_and_transpose_hfloat(void *dst,       ///< [out] выходные данные
                                          void *src,       ///< [in] входные данные
                                          int src_height,  ///< [in] количество строк входной матрицы
                                          int src_length,  ///< [in] количество столбцов входной матрицы
                                          void *T          ///< [in] матрица поворотов
);

/// Транспонирование матрицы типа float
extern void fft_transpose_inter(void *dst,       ///< [out] выходные данные
                                void *src,       ///< [in] входные данные
                                int src_height,  ///< [in] количество строк входной матрицы
                                int src_length   ///< [in] количество столбцов входной матрицы
);
/// Транспонирование матрицы типа fractional16
extern void fft_transpose_fract(void *dst,       ///< [out] выходные данные
                                void *src,       ///< [in] входные данные
                                int src_height,  ///< [in] количество строк входной матрицы
                                int src_length   ///< [in] количество столбцов входной матрицы
);
/// Транспонирование матрицы типа float16
extern void fft_transpose_hfloat(void *dst,       ///< [out] выходные данные
                                 void *src,       ///< [in] входные данные
                                 int src_height,  ///< [in] количество строк входной матрицы
                                 int src_length   ///< [in] количество столбцов входной матрицы
);

#endif
