
/* Return a pointer to a function that translates the indicated type of
 * back plane data (in long int) to real engineering units in float.
 * Also return a string indicating the units of the resulting value.*/

#include        <ctype.h>
#include        <strings.h>
#include        <string.h>
#include        <stdlib.h>
#include        <stdio.h>
#include        <errno.h>
#include        <time.h>

#define NUMTYPE 40

typedef float (*funcptr)( long );

/* Define all the functions we need, there are NUMTYPE of these. */
float plus_12_volts (long dn) { return(dn*0.05863); }
float minus_12_volts (long dn) { return(dn*(-0.06061)); }
float unregulated_plus_5_volts (long dn) { return(dn*0.029235); }
float unregulated_minus_5_volts (long dn) { return(dn*(-0.03903)); }
float ps_plus_5_volts (long dn) { return(dn*0.02929); }
float adc_0_volt_reference (long dn) { return(dn*0.00110); }
float plus_5_volt_reference (long dn) { return((dn/4)*0.00728); }
float x_scan_drive_current (long dn) { return(dn*0.5357); }
float z_scan_drive_current (long dn) { return(dn*0.5336); }
float x_scan_mirror_position (long dn) {
  return(((dn/4)*(dn/4)*1.368240345E-6)+((dn/4)*7.679911943E-2)-4.737040608);
}
float z_scan_mirror_position (long dn) {
  return(((dn/4)*(dn/4)*2.813814272E-6)+((dn/4)*7.288672804E-2)-5.084061651);
}
float ir_channel_output (long dn) { return((dn/4)*0.4884004E-2); }
float ir_detector_temp_high_res_1 (long dn) {
  return(((dn/4)*(dn/4)*0.633725E-5)+((dn/4)*0.083912084)+(4.623448E1));
}
float ir_detector_temp_high_res_2 (long dn) {
  return(((dn/4)*(dn/4)*0.6141E-5)+((dn/4)*0.08397441)+(4.483649E1));
}
float ir_detector_temp_low_res (long dn) {
  return(((dn/4)*(dn/4)*(-0.523408E-4))+((dn/4)*0.37278708)+(2.854299E1));
}
float spe_temp (long dn) {
  return((dn*dn*0.15541E-3)+(dn*0.494456)+(-5.397E1));
}
float me_temp (long dn) { return((dn*0.5)+(-5.0000E1)); }
float ir_shield_temp_1 (long dn) {
  return(((dn/16)*(dn/16)*0.27746E-3)+((dn/16)*1.00457)+(6.766E1));
}
float ir_shield_temp_2 (long dn) {
  return(((dn/16)*(dn/16)*0.27718E-3)+((dn/16)*1.011337)+(6.786E1));
}
float ir_grating_temp (long dn) {
  return(((dn/16)*(dn/16)*0.3045E-3)+((dn/16)*1.001739)+(6.866E1));
}
float ir_slit_shutter_temp (long dn) { return((dn*1.019607843)+(8.000E1)); }
float ir_primary_optics_temp (long dn) {
  return(((dn/16)*(dn/16)*0.27056E-3)+((dn/16)*1.003459)+(6.866E1));
}
float ir_secondary_optics_temp (long dn) {
  return(((dn/16)*(dn/16)*0.26583-3)+((dn/16)*1.01318)+(6.8566E1));
}
float ir_spectrometer_body_temp_1 (long dn) {
  return(((dn/16)*(dn/16)*0.26583E-3)+((dn/16)*1.013188)+(6.856E1));
}
float ir_spectrometer_body_temp_2 (long dn) {
  return(((dn/16)*(dn/16)*0.26945E-3)+((dn/16)*1.012278)+(6.852E1));
}
float shutter_position (long dn) { return(dn*0.019607843); }
float optical_calibration_current (long dn) { return(dn*0.9769); }
float plus_12_volts_switch (long dn) { return((dn/4)*0.01173); }
float ir_scan_power (long dn) { return((dn/4)*0.00733); }
float ir_shutter_power (long dn) { return((dn/4)*0.00730); }
float ir_shutter_drive (long dn) { return((dn/4)); }
float slice_time_seconds (long dn) { return((dn*1.0)); }
float slice_time_ticks (long dn) { return((dn*1.0)); }

/* This is the main subroutine. */
funcptr bp_trans(char *fast_hk_type, char *units)
{

  int i;
  char* typestrings[] = {"PLUS_12_VOLTS", "MINUS_12_VOLTS",
     "UNREGULATED_PLUS_5_VOLTS", "UNREGULATED_MINUS_5_VOLTS",
     "PS_PLUS_5_VOLTS", "ADC_0_VOLT_REFERENCE", "PLUS_5_VOLT_REFERENCE",
     "X_SCAN_DRIVE_CURRENT", "Z_SCAN_DRIVE_CURRENT", "X_SCAN_MIRROR_POSITION",
     "Z_SCAN_MIRROR_POSITION", "IR_CHANNEL_OUTPUT",
     "IR_DETECTOR_TEMP_HIGH_RES_1", "IR_DETECTOR_TEMP_HIGH_RES_2",
     "IR_DETECTOR_TEMP_LOW_RES", "SPE_TEMP", "ME_TEMP", "IR_SHIELD_TEMP_1",
     "IR_SHIELD_TEMP_2", "IR_GRATING_TEMP", "IR_SLIT/SHUTTER_TEMP",
     "IR_PRIMARY_OPTICS_TEMP", "IR_SECONDARY_OPTICS_TEMP",
     "IR_SPECTROMETER_BODY_TEMP_1", "IR_SPECTROMETER_BODY_TEMP_2",
      "SHUTTER_POSITION", "OPTICAL_CALIBRATION_CURRENT", "PLUS_12_VOLTS_SWITCH",
     "IR_SCAN_POWER", "IR_SHUTTER_POWER", "IR_SHUTTER_DRIVE",

     "IR_DETECTOR_TEMPERATURE_HI_RES",
     "IR_FPA_TMP_2_H-R",
     "IR_GRATING_TEMPERATURE",
     "IR_PRIMARY_OPTICS_TEMPERATURE",
     "IR_SECONDARY_OPTICS_TEMPERATURE",
     "IR_SPC_BDY_TMP_1",
     "IR_SPC_BDY_TMP_2",
     "SLICE_TIME_SECONDS",
     "SLICE_TIME_TICKS"
  };

  char* unitarr[] = {"VOLTS", "VOLTS", "VOLTS", "VOLTS", "VOLTS", "VOLTS",
     "VOLTS", "MILLIAMPS", "MILLIAMPS", "STEPS",
     "STEPS", "VOLTS", "KELVINS", "KELVINS",
     "KELVINS", "CELSIUS", "CELSIUS", "KELVINS", "KELVINS",
     "KELVINS", "KELVINS", "KELVINS", "KELVINS",
     "KELVINS", "KELVINS", "VOLTS", "MILLIAMPS",
     "VOLTS", "VOLTS",
     "VOLTS", "NOT_APPLICABLE",

     "KELVIN",
     "KELVIN",
     "KELVIN",
     "KELVIN",
     "KELVIN",
     "KELVIN",
     "KELVIN",
     "SECONDS",
     "TICKS"
  };

  float (*fp[]) (long) = {
     plus_12_volts, minus_12_volts, unregulated_plus_5_volts,
     unregulated_minus_5_volts, ps_plus_5_volts, adc_0_volt_reference,
     plus_5_volt_reference, x_scan_drive_current, z_scan_drive_current,
     x_scan_mirror_position, z_scan_mirror_position, ir_channel_output,
     ir_detector_temp_high_res_1, ir_detector_temp_high_res_2,
     ir_detector_temp_low_res, spe_temp, me_temp, ir_shield_temp_1,
     ir_shield_temp_2, ir_grating_temp, ir_slit_shutter_temp,
     ir_primary_optics_temp, ir_secondary_optics_temp,
     ir_spectrometer_body_temp_1, ir_spectrometer_body_temp_2,
     shutter_position, optical_calibration_current, plus_12_volts_switch,
     ir_scan_power, ir_shutter_power, ir_shutter_drive,

     ir_detector_temp_high_res_1,
     ir_detector_temp_high_res_2,
     ir_grating_temp,
     ir_primary_optics_temp,
     ir_secondary_optics_temp,
     ir_spectrometer_body_temp_1,
     ir_spectrometer_body_temp_2,
     slice_time_seconds,
     slice_time_ticks
  };

  /* This function returns a pointer to a function to do the conversion
   * and it sets the units to the appropriate string.
   */
  for(i=0; i<NUMTYPE; i++) {
    if (strcmp(fast_hk_type,typestrings[i]) == 0) {
      strcpy(units, unitarr[i]);
      return fp[i];
    }
  }

  units = "NULL";
  return NULL;
}
