// Copyright 2025 RnD Center "ELVEES", JSC

/*! \file
 *  \brief Тестирование прямого БПФ для типа float16
 */

#include "test.h"

int test_fft_hfloat_1d(const int fft_min_size, const int fft_max_size) {
  int error_count = 0;
  int freq = 5;
  int16_t *dst = memalign(fft_max_size * 2 * sizeof(int16_t), fft_max_size * 2 * sizeof(int16_t));
  int16_t *src = memalign(fft_max_size * 2 * sizeof(int16_t), fft_max_size * 2 * sizeof(int16_t));
  float *fetalon = memalign(fft_max_size * 2 * sizeof(float), fft_max_size * 2 * sizeof(float));

  char *test_info = malloc(sizeof(char) * 1000000);
  int print_bytes;

  FILE *res_1d;
  if (MEM_TYPE == SL_DDR)
    res_1d = fopen("test_HFLOAT_FFT_1D_DDR.csv", "w");
  else
    res_1d = fopen("test_HFLOAT_FFT_1D_XYRAM.csv", "w");

  fprintf(res_1d, "%s,%s,%s,%s\n", "SIZE", "TIC_CNTR", "INSTR_CNTR", "STATUS");

  print_bytes = sprintf(test_info, "hfloat FFT ");
  if (MEM_TYPE == SL_DDR)
    print_bytes += sprintf(test_info + print_bytes, "DDR\n\n");
  else
    print_bytes += sprintf(test_info + print_bytes, "XYRAM\n\n");

  float *v_fl32 = malloc(2 * fft_max_size * sizeof(float));

  int retval = SL_SUCCESS;
  for (int size = fft_min_size; size <= fft_max_size; size <<= 1) {
    if (retval) break;
    print_bytes += sprintf(test_info + print_bytes, "\nsize = %d \n", size);
    fprintf(res_1d, "%d,", size);

    for (freq = 1; freq <= 1; ++freq) {
      fft_t fft_obj;
      fft_obj.src = src;
      fft_obj.dst = dst;
      fft_obj.int_mem = (enum sl_data_memory)MEM_TYPE;
      fft_obj.dir = SL_FFT;
      fft_obj.dim = SL_1D;

      retval = fft_plan_1d(&fft_obj, size, SL_HFLOAT);
      if (retval) {
        print_error_message(retval);
        error_count = 1;
        break;
      }

      const float amplitude = 1. / (float)size;
      create_spectrum(v_fl32, size, freq, amplitude);
      float32_to_float16(v_fl32, src, 2 * size);

      memset(fetalon, 0., 2 * fft_max_size * sizeof(float));
      fetalon[2 * freq + 1] = 1.0;

      retval = fft_execute(&fft_obj);
      if (retval) {
        print_error_message(retval);
        error_count = 1;

        fft_free_sources(&fft_obj);
        break;
      }

      print_bytes += sprintf(test_info + print_bytes, "\nfreq = %d ..... ", freq);
      if (!fft_obj.big_size || !fft_obj.int_mem)
        float16_to_float32(dst, v_fl32, 2 * size);
      else
        float16_to_float32(src, v_fl32, 2 * size);

      print_bytes += sprintf(test_info + print_bytes, "peak = %f + %fi, ", v_fl32[2 * freq + 1], v_fl32[2 * freq]);
      print_bytes += sprintf(test_info + print_bytes, "ticks_fft = %d, instr_fft = %d", fft_obj.ticks, fft_obj.instrs);
      fprintf(res_1d, "%d,%d,", fft_obj.ticks, fft_obj.instrs);

      float norm = maximum_norm(v_fl32, fetalon, size);
      print_bytes += sprintf(test_info + print_bytes, ", norm = %f ", norm);
      if (norm < 1e-1) {
        print_bytes += sprintf(test_info + print_bytes, " : OK\n\n");
        fprintf(res_1d, "%s\n", "passed");
      } else {
        ++error_count;
        print_bytes += sprintf(test_info + print_bytes, ": WRONG\n\n");
        fprintf(res_1d, "%s\n", "failed");
      }

      fft_free_sources(&fft_obj);
    }
  }

  printf("%s", test_info);

  free(v_fl32);
  free(src);
  free(dst);
  free(fetalon);
  free(test_info);
  fclose(res_1d);
  return error_count;
}
