/* *****************************************************************************
 * File:      fet.c
 * Date:      15 Apr 2026
 * Author:    Andrew Levido
 *
 * Copyright 2026 Imbrius Pty Ltd - All Rights Reserved
 *
 ******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "fet.h"
#include "analog.h"
#include "analyser_helper.h"
#include "cli.h"
#include "screen.h"
#include <stdio.h>
#include "beep.h"

/* Defines -------------------------------------------------------------------*/

/* Typedefs & Enumerations ---------------------------------------------------*/
typedef struct {
  int32_t v_gs_on_mv;
  int32_t i_gs_on_ua;
} ax_mfet_vgs_on_t;

typedef struct {
  int32_t v_po_mv;
  int32_t i_po_ua;
} ax_jfet_vpo_t;

/* Global Variables ----------------------------------------------------------*/

/* Private Functions ---------------------------------------------------------*/
void ax_get_vpo(lead_t gate, lead_t source, lead_t drain, bool pch, ax_jfet_vpo_t * data)
{
  int32_t v_gs_abs_mv = 0;
  int32_t v_gs_id_ua;
  int32_t v_step;

  // Set up
  an_set_load_mv(pch? 6000 : 6000);
  an_set_power(pch ? false : true);
  
  an_set_matrix(NODE_DRIVE, gate);
  an_set_matrix(NODE_POWER, drain);
  an_set_matrix(NODE_LOAD, source);
  
  v_step = AX_JFET_V_STEP_HI;
   #ifdef AX_VERBOSE
  cli_printf("\tVgs(mV)   Id(µA)");
  #endif
  for(v_gs_abs_mv = 0; v_gs_abs_mv <= AX_FET_MAX_V; v_gs_abs_mv += v_step) {
    if(pch) {
      an_set_drive_mv(v_gs_abs_mv);
      HAL_Delay(1);
      v_gs_id_ua = an_get_load_ua();
      #ifdef AX_VERBOSE
      cli_printf("\t%+7i   %+7i ", v_gs_abs_mv, v_gs_id_ua);
      #endif
    }
    else {
       an_set_drive_mv(AX_FET_MAX_V - v_gs_abs_mv);
       HAL_Delay(1);
       v_gs_id_ua = an_get_load_ua();
        #ifdef AX_VERBOSE
       cli_printf("\t%+7i   %+7i ", v_gs_abs_mv - AX_FET_MAX_V, v_gs_id_ua);
       #endif
    }
    v_gs_id_ua = an_get_load_ua();
    if(abs(v_gs_id_ua) < AX_JFET_I_THR_MED) {
       v_step = AX_JFET_V_STEP_MED;
    }
      if(abs(v_gs_id_ua) < AX_JFET_I_THR_LO) {
       v_step = AX_JFET_V_STEP_LO ;
    }
 
    if((v_gs_id_ua < AX_JFET_PINCH_I) && (v_gs_id_ua > -AX_JFET_PINCH_I)) {
      data->v_po_mv = ax_get_lead_mv(gate) - ax_get_lead_mv(source);
      data->i_po_ua = v_gs_id_ua;
      break;
    }
  }
  // Clean up
  an_set_matrix_all_open();
}


void ax_get_vgs_on(lead_t gate, lead_t source, lead_t drain, bool pch, ax_mfet_vgs_on_t * data)
{
  int32_t v_gs_abs_mv = 0;
  int32_t v_gs_id_ua;
  int32_t v_step;
  
  // Set up
  an_set_load_mv(pch? 0 : 12000);
  an_set_power(pch ? true : false);
  
  an_set_matrix(NODE_DRIVE, gate);
  an_set_matrix(NODE_POWER, source);
  an_set_matrix(NODE_LOAD, drain);

  v_step = AX_MFET_V_STEP_HI;
  #ifdef AX_VERBOSE
  cli_printf("\tVgs(mV)   Id(µA)");
  #endif

  for(v_gs_abs_mv = 0; v_gs_abs_mv <= 8000; v_gs_abs_mv += v_step) {
  if(pch) {
    an_set_drive_mv(12000 - v_gs_abs_mv);
    HAL_Delay(1);
    v_gs_id_ua = an_get_load_ua();
    #ifdef AX_VERBOSE
    cli_printf("\t%+7i   %+7i ", 12000 - v_gs_abs_mv, v_gs_id_ua);
    #endif
  }
  else {
      an_set_drive_mv(v_gs_abs_mv);
      HAL_Delay(1);
      v_gs_id_ua = an_get_load_ua();
      #ifdef AX_VERBOSE
      cli_printf("\t%+7i   %+7i ", v_gs_abs_mv, v_gs_id_ua);
      #endif
  }
  v_gs_id_ua = an_get_load_ua();
  if(abs(v_gs_id_ua) > 1000) {
      v_step = AX_MFET_V_STEP_LO;
  }
    if(abs(v_gs_id_ua) > 4000) {
      v_step = 10;
  }

  if((v_gs_id_ua > AX_MFET_ON_I) || (v_gs_id_ua < -AX_MFET_ON_I)) {
    data->v_gs_on_mv = ax_get_lead_mv(gate) - ax_get_lead_mv(source);
    data->i_gs_on_ua = v_gs_id_ua;
    break;
  }
  else {
    data->v_gs_on_mv = 0;
    data->i_gs_on_ua = 0;
  } 
}
// Clean up
an_set_matrix_all_open();
}

/* Public Functions ----------------------------------------------------------*/

void ax_test_jfet(lead_t gate, lead_t sd1, lead_t sd2, bool pch)
{
  ax_jfet_vpo_t jfet;
  screen_desc_t screen;
  char value_1 [10];
  char value_2 [10];

  // Get the pinchoff voltage 
  cli_printf("\t-> J-FET %s-Channel", pch == true ? "P" : "N");
  cli_printf("\t   Gate = %s, Drain/Source = %s, Drain/Source = %s", ax_lead_2_text(gate), ax_lead_2_text(sd1), ax_lead_2_text(sd2));
  ax_get_vpo(gate, sd1, sd2, pch, &jfet);
  cli_printf("\t* Vpo = %+i mV at %+i uA", jfet.v_po_mv, jfet.i_po_ua);

  // Valid pinch-off voltage?
  if(jfet.v_po_mv != 0) {
    screen.screen = pch == true ? &scrn_jfet_pch : &scrn_jfet_nch;
    screen.left_node_id = (scrn_node_id_t)gate;
    screen.top_node_id = (scrn_node_id_t)sd1;
    screen.bottom_node_id = (scrn_node_id_t)sd2;
    ax_print_flt(value_1, jfet.v_po_mv);
    ax_print_flt(value_2, jfet.i_po_ua);
    sprintf(ax_line_1_buffer, "Vpo = %sV @ %smA", value_1, value_2);
    screen.string1_override = ax_line_1_buffer;
  }
  else {
    screen.string1_override = "Vpo not Measured";
  }
  scrn_draw(&screen);
  beep(A6, BEEP_SHORT);
}

void ax_test_mosfet_enhancement(lead_t gate, lead_t source, lead_t drain, bool pch)
{
  ax_mfet_vgs_on_t mfet;
  screen_desc_t screen;
  char value_1 [10];
  char value_2 [10];

  // Get threshold voltage 
  cli_printf("\t -> %s-Channel Enhancement MOSFET", pch == true ? "P" : "N");
  cli_printf("\t    Gate = %s, Source = %s, Drain = %s", ax_lead_2_text(gate), ax_lead_2_text(source), ax_lead_2_text(drain));
  ax_get_vgs_on(gate, source, drain, pch, &mfet);
  cli_printf("\t* Vgs(on) = %+i mV at %+i uA", mfet.v_gs_on_mv, mfet.i_gs_on_ua);

  // Common
  screen.left_node_id = (scrn_node_id_t)gate;

  if(mfet.v_gs_on_mv != 0) {
    ax_print_flt(value_1, mfet.v_gs_on_mv);
    ax_print_flt(value_2, mfet.i_gs_on_ua);
    sprintf(ax_line_1_buffer, "Vgs(on) = %sV", value_1);
    sprintf(ax_line_2_buffer, "at Id = %s mA", value_2);
    screen.string1_override = ax_line_1_buffer;
    screen.string2_override = ax_line_2_buffer;
  }
  else {
    screen.string1_override = "Vgs(on) not Measured";
    screen.string2_override = "";
  }

  if(pch == true) {
    screen.screen = &scrn_mosfet_pch;
    screen.top_node_id = (scrn_node_id_t)source;
    screen.bottom_node_id = (scrn_node_id_t)drain;
  }
  else {
    screen.screen = &scrn_mosfet_nch;
    screen.top_node_id = (scrn_node_id_t)drain;
    screen.bottom_node_id = (scrn_node_id_t)source;
  }
  scrn_draw(&screen);
  beep(A6, BEEP_SHORT);
}

void ax_test_igbt(lead_t gate, lead_t emitter, lead_t collector, bool fwd)
{
  ax_mfet_vgs_on_t mfet;
  screen_desc_t screen;
  char value_1 [10];
  char value_2 [10];

  // Get threshold voltage 
  cli_printf("\t -> IGBT %s Freewheel Diode", fwd == true ? "with" : "without");
  ax_get_vgs_on(gate, emitter, collector, false, &mfet);
  cli_printf("\t* Vge(on) %+i mV at %+i uA", mfet.v_gs_on_mv, mfet.i_gs_on_ua);

  // Common
  screen.left_node_id = (scrn_node_id_t)gate;
  screen.top_node_id = (scrn_node_id_t)collector;
  screen.bottom_node_id = (scrn_node_id_t)emitter;

  if(mfet.v_gs_on_mv != 0) {
    ax_print_flt(value_1, mfet.v_gs_on_mv);
    ax_print_flt(value_2, mfet.i_gs_on_ua);
    sprintf(ax_line_1_buffer, "Vge(on) = %sV", value_1);
    sprintf(ax_line_2_buffer, "at Id = %s mA", value_2);
    screen.string1_override = ax_line_1_buffer;
    screen.string2_override = ax_line_2_buffer;
  }
  else {
    screen.string1_override = "Vge(on) not Measured";
    screen.string2_override = "";
  }
  
  if(fwd == true) {
    screen.screen = &scrn_igbt_diode;
  }
  else {
    screen.screen = &scrn_igbt;
  }
  scrn_draw(&screen);
  beep(A6, BEEP_SHORT);
}

void ax_test_mosfet_depletion(lead_t gate, lead_t source, lead_t drain)

{
  ax_jfet_vpo_t jfet;
  screen_desc_t screen;
  char value_1 [10];
  char value_2 [10];

  // Get the pinchoff voltage 
  cli_printf("\t-> N-Channel Depletion MOSFET");
  ax_get_vpo(gate, source, drain, false, &jfet);
  cli_printf("\t* Vpo = %+i mV at %+i uA", jfet.v_po_mv, jfet.i_po_ua);

  // Valid pinch-off voltage?
  if(jfet.v_po_mv != 0) {
    screen.screen = &scrn_depletion_mosfet_nch;
    screen.left_node_id = (scrn_node_id_t)gate;
    screen.top_node_id = (scrn_node_id_t)drain;
    screen.bottom_node_id = (scrn_node_id_t)source;
    ax_print_flt(value_1, jfet.v_po_mv);
    ax_print_flt(value_2, jfet.i_po_ua);
    sprintf(ax_line_1_buffer, "Vpo = %sV @ %smA", value_1, value_2);
    screen.string1_override = ax_line_1_buffer;
  }
  else {
    screen.string1_override = "Vpo not Measured";
  }
  screen.string2_override = "";
  scrn_draw(&screen);
  beep(A6, BEEP_SHORT);
}


/* End fet */