// Copyright 2025 RnD Center "ELVEES", JSC

/*! \file
 *  \brief Тестирование одномерной линейной свертки
 */

#include <elcore50-signal-lib/fft.h>
#include <elcore50-signal-lib/reference.h>

#include "common.h"

void print_usage() {
  printf("Usage: test_conv_1d [OPTIONS]\n");
  printf("Options description:\n");
  printf("\t-m   Data location: {DDR, XYRAM}\n");
  printf("\t-h   Print usage\n");
}

int main(int argc, char *argv[]) {
  if ((argc < 2) || (argc > 3)) {
    printf("Error: wrong number of parameters!\n");
    print_usage();
    return 1;
  }

  int8_t is_data_in_xyram;
  char *key = argv[1];
  if (!strcmp(key, "-h")) {
    print_usage();
    return 0;
  } else if (!strcmp(key, "-m")) {
    char *mem_type = argv[2];
    if (strcmp(mem_type, "DDR") && strcmp(mem_type, "XYRAM")) {
      printf("Unrecognized program option: %s\n", mem_type);
      print_usage();
      return 1;
    }
    is_data_in_xyram = strcmp(mem_type, "XYRAM") ? 0 : 1;
  } else {
    printf("Unrecognized program option: %s\n", key);
    print_usage();
    return 1;
  }

  FILE *res_1d;

  if (is_data_in_xyram) {
    printf("start FFT-convolution test 1d XYRAM\n");
    res_1d = fopen("test_conv_1d_XYRAM.csv", "w");
  } else {
    printf("start FFT-convolution test 1d DDR\n");
    res_1d = fopen("test_conv_1d_DDR.csv", "w");
  }

  const int32_t max_size = 131072;
  const int32_t max_conv_size = max_size * 2 - 1;
  const int32_t max_conv_size2 = 1 << (int)ceil(log2f(max_conv_size));

  // Exact solution
  float *ethalon = malloc(max_conv_size2 * 2 * sizeof(float));
  // First array
  float *src0 = memalign(max_conv_size2 * 2 * sizeof(float), max_conv_size2 * 2 * sizeof(float));
  // Second array
  float *src1 = memalign(max_conv_size2 * 2 * sizeof(float), max_conv_size2 * 2 * sizeof(float));
  // Result
  float *dst = memalign(max_conv_size2 * 2 * sizeof(float), max_conv_size2 * 2 * sizeof(float));

  int16_t errors_count = 0;
  const float amplitude0 = 1.0;
  const int16_t freq0 = 5;
  const float amplitude1 = 1.0;
  const int16_t freq1 = 1;

  fprintf(res_1d, "%s,%s,%s,%s,%s\n", "size0", "size1", "conv_size", "ticks", "status");

  int retval = SL_SUCCESS;
  for (int32_t size0 = 256; size0 <= max_size; size0 *= 2) {
    if (retval) break;
    for (int32_t size1 = 256; size1 <= max_size; size1 *= 4) {
      const int32_t conv_size = size0 + size1 - 1;
      const int32_t conv_size2 = 1 << (int)ceil(log2f(conv_size));

      // The first array
      memset(src0, 0.0, conv_size2 * 2 * sizeof(float));
      create_spectrum(src0, size0, freq0, amplitude0);

      // The second array
      memset(src1, 0.0, conv_size2 * 2 * sizeof(float));
      create_spectrum(src1, size1, freq1, amplitude1);

      // Exact solution
      circle_conv_opt(src0, src1, ethalon, conv_size2);

      int32_t ticks_start, ticks_end;
      int32_t instrs_start, instrs_end;
      ticks_counter(&ticks_start, &instrs_start);

      // FFT-convolution
      retval = fft_conv_1d(src0, src1, dst, conv_size2, is_data_in_xyram);
      if (retval) {
        print_error_message(retval);
        errors_count = 1;
        break;
      }

      ticks_counter(&ticks_end, &instrs_end);
      int32_t ticks = ticks_end - ticks_start;

      // Compare results
      float norm = maximum_norm(dst, ethalon, conv_size);
      fprintf(res_1d, "%d,%d,%d,%d,", size0, size1, conv_size2, ticks);
      if (norm < 1e-1) {
        fprintf(res_1d, "%s\n", "passed");
      } else {
        ++errors_count;
        fprintf(res_1d, "%s\n", "failed");
      }
    }
  }

  free(src0);
  free(src1);
  free(dst);
  free(ethalon);

  fclose(res_1d);
  if (errors_count) {
    printf("%d TESTS FAILED\n", errors_count);
  } else {
    printf("PASSED\n");
  }
  return errors_count;
}
