{ *************************************************************************** }
MODULE mod_tst_ctfe_fend ;
{  Created  27-NOV-1989   MICHIGAN STATE UNIVERSITY, TRIGGER CONTROL SOFTWARE }
{ *************************************************************************** }
INCLUDE
  mod_handle_console,
  mod_handle_tracing,
  mod_handle_result_files,
  mod_io_allocation_handling,
  mod_def_hardware_tables,
  mod_handle_registers,
  mod_common_hard_io,
  mod_tst_common,
  mod_tst_init,
  mod_tst_misc_util ;
{ *************************************************************************** }
EXPORT
  hardware_test_ctfe_fend ;           {PROCESS BLOCK ctfe card front end test }
{ *************************************************************************** }
IMPORT

  scroll,                             {from module MOD_HANDLE_CONSOLE         }
  clearscreen                         {from module MOD_HANDLE_CONSOLE         }
  goxy,                               {from module MOD_HANDLE_CONSOLE         }
  inline_draw_box,                    {from module MOD_HANDLE_CONSOLE         }
  display_console,                    {from module MOD_HANDLE_CONSOLE         }
  esc,{cleol,}                        {from module MOD_HANDLE_CONSOLE         }
  bold, standard,                     {from module MOD_HANDLE_CONSOLE         }

  handle_trc_inf,                     {from module MOD_HANDLE_TRACING         }
  handle_trc_sta,                     {from module MOD_HANDLE_TRACING         }
  handle_trc_sys,                     {from module MOD_HANDLE_TRACING         }
  decimal_string,                     {from module MOD_HANDLE_TRACING         }
  set_trc_exc_mode,                   {from module MOD_HANDLE_TRACING         }

  open_result_file,                   {from module MOD_HANDLE_RESULT_FILES    }
  close_result_file,                  {from module MOD_HANDLE_RESULT_FILES    }
  handle_write_result,                {from module MOD_HANDLE_RESULT_FILES    }

  deallocate_trigger,                 {from module MOD_IO_ALLOCATION_HADLLING }

  ctfe_card_low_half,                 {from module MOD_DEF_HARDWARE_TABLES    }
  ctfe_card_high_half,                {from module MOD_DEF_HARDWARE_TABLES    }
  relative_eta,                       {from module MOD_DEF_HARDWARE_TABLES    }
    rele_0,{rele_1, rele_2,}rele_3,   {from module MOD_DEF_HARDWARE_TABLES    }
  adc_data_type_per_ctfe_channel,     {from module MOD_DEF_HARDWARE_TABLES    }
    EMEtZ0, HDEtZ0,                   {from module MOD_DEF_HARDWARE_TABLES    }
  mtgfwtss,                           {from module MOD_DEF_HARDWARE_TABLES    }
  mtgcttss,                           {from module MOD_DEF_HARDWARE_TABLES    }
  reading_from_pipe,                  {from module MOD_DEF_HARDWARE_TABLES    }
  tss_force_low, tss_force_high,      {from module MOD_DEF_HARDWARE_TABLES    }
  tss_fw_write_ab, tss_fw_read_ab,    {from module MOD_DEF_HARDWARE_TABLES    }
  tss_ct_write_ab, tss_ct_read_ab,    {from module MOD_DEF_HARDWARE_TABLES    }
  ctfe_data,                          {from module MOD_DEF_HARDWARE_TABLES    }
  ctfe_ctrl,                          {from module MOD_DEF_HARDWARE_TABLES    }

  update_register,                    {from module MOD_HANDLE_REGISTER        }
  examine_register,                   {from module MOD_HANDLE_REGISTER        }

  cbus_register,                      {from module MOD_COMMON_HARD_IO         }
  eight_bit_0_7,                      {from module MOD_COMMON_HARD_IO         }

  e_pol,                              {from module MOD_TST_COMMON             }
  e_fe,                               {from module MOD_TST_COMMON             }
  phi,                                {from module MOD_TST_COMMON             }
  result_file,                        {from module MOD_TST_COMMON             }
  result_open,                        {from module MOD_TST_COMMON             }
  testtag,                            {from module MOD_TST_COMMON             }
  iotest,                             {from module MOD_TST_COMMON             }
  single_shot_mtg,                    {from module MOD_TST_COMMON             }
  Check_FW_AndOr,                     {from module MOD_TST_COMMON             }

  init_mtg_for_caltrg,                {from module MOD_TST_INIT               }

  single_cycle_mtgs,                  {from module MOD_TST_MISC_UTIL          }
  mtg_preset_at_end_pattern,          {from module MOD_TST_MISC_UTIL          }
  mtg_stop_clock,                     {from module MOD_TST_MISC_UTIL          }
  mtg_preset_at_begin_pattern,        {from module MOD_TST_MISC_UTIL          }
  mtg_reset_prom_counter,             {from module MOD_TST_MISC_UTIL          }
  mtg_release_clock,                  {from module MOD_TST_MISC_UTIL          }
  update_buffer_pipe,                 {from module MOD_TST_MISC_UTIL          }
  inline_byte_and,                    {from module MOD_TST_MISC_UTIL          }
  inline_byte_or ;                    {from module MOD_TST_MISC_UTIL          }

{ *************************************************************************** }
{ *************************************************************************** }

CONST

  six_time_const   = -1200000 ; { 0.12s = 6 time const = 1/4 % = 1/2 lsb max }
  three_time_const =  -600000 ; { 0.06s = 3 time const = settle within 5 %   }

  noise_test_point = 200 ; {the noise is estimated at this pedestal value}
  noise_samples    =1000 ; {this is the sample size for the noise estimation}
  stat_samples     =  50 ; {this is the data sample size for noisy channel}

  {miscellaneous parameters for report formating}
  l_title      =  5 ;  l_viol_tot   = 12 ;  l_w_err_at   = 17 ;
  l_chan_num   =  7 ;  l_first_viol = 13 ;  l_min_step   = 18 ;
  l_chan_typ   =  8 ;  l_intercept  = 14 ;  l_max_step   = 19 ;
  l_noise_var  = 10 ;  l_slope      = 15 ;  l_b_stuck_H  = 20 ;
  l_sample_size= 11 ;  l_worst_err  = 16 ;  l_b_stuck_L  = 21 ;

  c_start      = 14 ;  co_chan      = 17 ;  co_HDEt      = 8 ;

  {dimension of array below}
  total = 0 ; first_at = 1 ;

TYPE

  bit  = [BIT(1)] 0..1     ;
  byte = [BYTE]   0..255   ;

VAR

  sample_per_point : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF INTEGER ;
  p_ctfe_data      :^ctfe_card_low_half ;
  p_ctfe_ctrl      :^ctfe_card_high_half ;
  histogram        : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0,0..255] OF INTEGER ;
  noise_var        : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF REAL ;
  adc_out          : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0,0..255] OF byte ;
  monoton_viol     : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0,total..first_at] OF byte ;
  zero_adc_ped     : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF REAL ;
  adc_per_ped      : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF REAL ;
  bit_stuck_high   : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF byte ;
  bit_stuck_low    : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF byte ;

  worst_error      : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF REAL ;
  w_err_at         : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF byte ;
  max_step_len     : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF INTEGER ;
  min_step_len     : ARRAY [rele_0..rele_3,EMEtZ0..HDEtZ0] OF INTEGER ;

  result_line      : ARRAY [1..24] OF STRING(80) ; {formatted report}

{ **************************************************************************** }
{ ***************************************************************************** }
PROCEDURE hardware_test_ctfe_fend ;


BEGIN

  ESTABLISH ( exchand_ctfe_fend_test ) ; {nested exception handler }
                                         {closing result file }

  deallocate_trigger ( TAGEXT := testtag ) ;

  open_file_for_results ;

  {start timing signals}
  init_mtg_for_caltrg ;

  {initialize ctfe card control registers}
  init_ctfe_card ;

  handle_trc_inf ( TAG := 'HTT/FET%'+testtag,
               MESSAGE := ' Estimating Noise Variance of each Channel' ) ;
  estimate_noise_variance ;

  handle_trc_inf ( TAG := 'HTT/FET%'+testtag,
               MESSAGE := ' Collecting Statistics ' ) ;
  collect_statistics ;

  {deallocate now so that the message does not disturb the screen report }
  {if the main process were to do it later                               }
{  deallocate_trigger ( TAGEXT := testtag ) ;
}
  handle_trc_inf ( TAG := 'HTT/FET%'+testtag,
               MESSAGE := ' Calculating Parameters ' ) ;
  calculate_parameters ;

  handle_trc_inf ( TAG := 'HTT/FET%'+testtag,
               MESSAGE := ' Building Formated Report' ) ;
  build_formated_report ;

  report_to_screen_and_file ;

END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE open_file_for_results ;

BEGIN

  result_file.origin := 'CTFE_TEST' ;
  result_file.name := 'CTFE_FE_'
                    + CONVERT(STRING(3),e_pol)
                    + '_' + CONVERT(STRING,e_fe)
                    + '_' + CONVERT(STRING,phi)
                    + '.LOG' ;

  open_result_file ( RESULT_FILE := ADDRESS(result_file),
                          STATUS := result_open ) ;

END ;
{ **************************************************************************** }
{ **************************************************************************** }
FUNCTION exchand_ctfe_fend_test OF TYPE EXCEPTION_HANDLER ;

BEGIN
  set_trc_exc_mode ( TRUE ) ;

  handle_trc_sta ( TAG := 'HTT/EXC%'+testtag,
                STATUS := signal_args.name ) ;

  IF ( result_open = 1 ) THEN close_result_file ( ADDRESS(result_file) ) ; 

  handle_trc_sys ( TAG := 'HTT/EXC%'+testtag, MESSAGE := ' Resignaling') ; 

  exchand_ctfe_fend_test := FALSE ;

END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE init_ctfe_card ;

BEGIN

  p_ctfe_data := ADDRESS ( ctfe_data[e_pol,e_fe,phi] ) ;
  p_ctfe_ctrl := ADDRESS ( ctfe_ctrl[e_pol,e_fe,phi] ) ;

  update_register ( TAGEXT := testtag,
                      CARD := p_ctfe_ctrl,
                  REGISTER := ADDRESS(p_ctfe_ctrl^.brdctrl),
                     IOPAR := iotest,
                      DATA := 1 ) ; {select adc data}

  update_register ( TAGEXT := testtag,
                      CARD := p_ctfe_ctrl,
                  REGISTER := ADDRESS(p_ctfe_ctrl^.chanctrl),
                     IOPAR := iotest,
                      DATA := 255 ) ; {all channels updated}

END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE estimate_noise_variance ;

VAR

  rele             : relative_eta ;
  ch_typ           : adc_data_type_per_ctfe_channel ;
  p_adc_reg        :^cbus_register ;
  sample_count     : INTEGER ;
  data             : byte ;
  retry            : INTEGER ;
  average          : INTEGER ;
  noise            : INTEGER ;

BEGIN

  histogram    := ZERO ;

  FOR rele := rele_0 TO rele_3
  DO FOR ch_typ := EMEtZ0 TO HDEtZ0
  DO update_register ( TAGEXT := testtag,
                         CARD := p_ctfe_ctrl,
                     REGISTER := ADDRESS(p_ctfe_ctrl^.pedreg[rele,ch_typ]),
                        IOPAR := iotest,
                         DATA := noise_test_point ) ;

  IF ( result_open = 1 )
  THEN handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                               OUTSTRING := 'The Noise Estimation'
                                             + ' will be done at DAC Byte '
                                             + ' ' + CONVERT(STRING,noise_test_point) ) ;
  WAIT_ANY ( TIME := six_time_const ) ;

  FOR rele := rele_0 TO rele_3
  DO BEGIN
    FOR ch_typ := EMEtZ0 TO HDEtZ0
    DO BEGIN

      p_adc_reg := ADDRESS(p_ctfe_data^.muxout[rele,ch_typ]) ;

      retry := 0 ;
    try_again: {will retry if all of the data is found in 2 consecutive bins}
      histogram[rele,ch_typ] := ZERO ;
      average := 0 ;
      noise := 0 ;

      FOR sample_count := 1 TO noise_samples
      DO BEGIN

        IF ( single_shot_mtg = TRUE ) THEN single_cycle_mtgs ;
        update_buffer_pipe ;

        examine_register ( TAGEXT := testtag,
                             CARD := p_ctfe_data,
                         REGISTER := p_adc_reg,
                         SLICEAGE := 0,
                            IOPAR := iotest,
                             DATA := data ) ;

        average := average + data ;
        noise := noise + data*data ;
        histogram[rele,ch_typ,data] := histogram[rele,ch_typ,data] + 1 ;

      END ;

      noise_var[rele,ch_typ] :=  CONVERT(REAL,noise)/noise_samples
                              - (CONVERT(REAL,average)/noise_samples) ** 2  ;
      average := ROUND(average/noise_samples) ;

      IF ( histogram[rele,ch_typ,average] = noise_samples )
      THEN sample_per_point[rele,ch_typ] := 1
      ELSE
        IF ( ( retry < 2 ) AND ( ( histogram[rele,ch_typ,average] + histogram[rele,ch_typ,average+1] = noise_samples )
                              OR ( histogram[rele,ch_typ,average] + histogram[rele,ch_typ,average-1] = noise_samples ) ) )
        THEN BEGIN
          retry := retry + 1 ;
          update_register ( TAGEXT := testtag,
                              CARD := p_ctfe_ctrl,
                          REGISTER := ADDRESS(p_ctfe_ctrl^.pedreg[rele,ch_typ]),
                             IOPAR := iotest,
                              DATA := noise_test_point + retry ) ; {increment simulation reg by one}
          WAIT_ANY ( TIME := six_time_const ) ;
          IF ( result_open = 1 )
          THEN handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                                       OUTSTRING := 'Retrying Noise Estimation'
                                                  + ' for Channel'
                                                  + ' ' + CONVERT(STRING,rele)
                                                  + ' ' + CONVERT(STRING,ch_typ)
                                                  + ' at DAC Byte '
                                                  + ' ' + CONVERT(STRING,noise_test_point+retry) ) ;
          GOTO try_again ;
        END
      ELSE sample_per_point[rele,ch_typ] := stat_samples ;
{      ELSE sample_per_point[rele,ch_typ] := 1 ;}

    END ; {ch_typ}
  END ; {rele}

  IF ( result_open = 1 )
  THEN BEGIN
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := 'Noise Profile ' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := '       Channel#1 Channel#2 Channel#3 Channel #4 ' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := '         EM   HD   EM   HD   EM   HD   EM   HD    ' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                        ARRAY_4_2_256 := ADDRESS(histogram) ) ;
  END ;


END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE collect_statistics ;

VAR

  rele            : relative_eta ;
  ch_typ          : adc_data_type_per_ctfe_channel ;
  ped_in          : INTEGER ;
  p_adc_reg       :^cbus_register ;
  average         : INTEGER ;
  sample_count    : INTEGER ;
  data            : byte ;
  temp_stuck_high : byte ;
  temp_stuck_low  : byte ;

BEGIN

  monoton_viol := ZERO ;
  adc_out      := ZERO ;

  FOR rele := rele_0 TO rele_3
  DO FOR ch_typ := EMEtZ0 TO HDEtZ0
  DO BEGIN
    update_register ( TAGEXT := testtag,
                        CARD := p_ctfe_ctrl,
                    REGISTER := ADDRESS(p_ctfe_ctrl^.pedreg[rele,ch_typ]),
                       IOPAR := iotest,
                        DATA := 0 ) ; {reset pedestal register}
    bit_stuck_high[rele,ch_typ] := 255 ;
    bit_stuck_low[rele,ch_typ]  := 0   ;
  END ;

  WAIT_ANY ( TIME := six_time_const ) ;

  FOR ped_in := 0 TO 255
  DO BEGIN

    FOR rele := rele_0 TO rele_3
    DO FOR ch_typ := EMEtZ0 TO HDEtZ0
    DO update_register ( TAGEXT := testtag,
                           CARD := p_ctfe_ctrl,
                       REGISTER := ADDRESS(p_ctfe_ctrl^.pedreg[rele,ch_typ]),
                          IOPAR := iotest,
                           DATA := ped_in ) ;

    WAIT_ANY ( TIME := three_time_const ) ;

    FOR rele := rele_0 TO rele_3
    DO BEGIN
      FOR ch_typ := EMEtZ0 TO HDEtZ0
      DO BEGIN

        p_adc_reg := ADDRESS(p_ctfe_data^.muxout[rele,ch_typ]) ;

        average := 0 ;

        temp_stuck_high := bit_stuck_high[rele,ch_typ] ;
        temp_stuck_low := bit_stuck_low[rele,ch_typ] ;

        FOR sample_count := 1 TO sample_per_point[rele,ch_typ]
        DO BEGIN

          IF ( single_shot_mtg = TRUE ) THEN single_cycle_mtgs ;
          update_buffer_pipe ;

          examine_register ( TAGEXT := testtag,
                               CARD := p_ctfe_data,
                           REGISTER := p_adc_reg,
                              IOPAR := iotest,
                               DATA := data ) ;

          average := average + data ;
          temp_stuck_high := inline_byte_and ( data, temp_stuck_high ) ;
          temp_stuck_low := inline_byte_or ( data, temp_stuck_low ) ;

        END ;

        bit_stuck_high[rele,ch_typ] := temp_stuck_high ;
        bit_stuck_low[rele,ch_typ] := temp_stuck_low ;


        adc_out[rele,ch_typ,ped_in] := ROUND(average/sample_per_point[rele,ch_typ]) ;
        histogram[rele,ch_typ,ped_in] := adc_out[rele,ch_typ,ped_in] ;

        IF ( ( ped_in > 0 )
         AND ( adc_out[rele,ch_typ,ped_in-1] > adc_out[rele,ch_typ,ped_in] ) )
        THEN BEGIN
          IF ( monoton_viol[rele,ch_typ,total] = 0 )
          THEN monoton_viol[rele,ch_typ,first_at] := ped_in ;
          monoton_viol[rele,ch_typ,total] := monoton_viol[rele,ch_typ,total] + 1 ;
        END ;

      END ; {ch_typ}
    END ; {rele}
  END ; {ped_in}

  IF ( result_open = 1 )
  THEN BEGIN
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := 'Transfer Function ' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := '       Channel#1 Channel#2 Channel#3 Channel #4 ' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := '         EM   HD   EM   HD   EM   HD   EM   HD    ' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                        ARRAY_4_2_256 := ADDRESS(histogram) ) ;
  END ;

END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE calculate_parameters ;

VAR

  exp_count       : INTEGER ;
  exp_x, exp_y    : INTEGER ;
  exp_xy, exp_xx  : INTEGER ;
  slope           : REAL ;
  offset          : REAL ;
  rele            : relative_eta ;
  ch_typ          : adc_data_type_per_ctfe_channel ;
  ped_in          : INTEGER ;
  local_error     : REAL ;
  cur_step_len    : INTEGER ;

BEGIN

  FOR rele := rele_0 TO rele_3
  DO BEGIN
    FOR ch_typ := EMEtZ0 TO HDEtZ0
    DO BEGIN

      exp_count := 0 ;
      exp_x  := 0 ;
      exp_y  := 0 ;
      exp_xy := 0 ;
      exp_xx := 0 ;

      FOR ped_in := 0 TO 255
      DO IF ( adc_out[rele,ch_typ,ped_in] > 0 )
      THEN BEGIN
        exp_count := exp_count + 1 ;
        exp_x := exp_x + ped_in ;
        exp_y := exp_y + adc_out[rele,ch_typ,ped_in] ;
        exp_xy := exp_xy + ped_in * adc_out[rele,ch_typ,ped_in] ;
        exp_xx := exp_xx + ped_in * ped_in ;
      END ; {ped_in}

      IF ( exp_count <> 0 )
      THEN BEGIN
        slope := ( exp_xy - exp_x * exp_y / exp_count )
               / ( exp_xx - exp_x * exp_x / exp_count ) ;
        offset := ( exp_y - slope * exp_x ) / exp_count ;
      END
      ELSE BEGIN
        slope  := 0 ;
        offset := 0 ;
      END ;

      adc_per_ped[rele,ch_typ] := slope ;
      IF ( adc_per_ped[rele,ch_typ] < 0.001 )
      THEN zero_adc_ped[rele,ch_typ] := 255
      ELSE zero_adc_ped[rele,ch_typ] := -offset/slope ;

    END ; {ch_typ}
  END ; {rele}

  FOR rele := rele_0 TO rele_3
  DO BEGIN
    FOR ch_typ := EMEtZ0 TO HDEtZ0
    DO BEGIN

      worst_error[rele,ch_typ] := 0 ;

      FOR ped_in := 0 TO 255
      DO BEGIN
        IF ( adc_out[rele,ch_typ,ped_in] > 0 )
        THEN BEGIN
          local_error := adc_out[rele,ch_typ,ped_in]
                       - adc_per_ped[rele,ch_typ]
                       * ( ped_in - zero_adc_ped[rele,ch_typ] ) ;
          IF ( ABS(local_error) > ABS(worst_error[rele,ch_typ]) )
          THEN BEGIN
            worst_error[rele,ch_typ] := local_error ;
            w_err_at[rele,ch_typ]    := ped_in ;
          END ; {if}
        END ; {if}
      END ; {do}

      max_step_len[rele,ch_typ] := 0 ;
      min_step_len[rele,ch_typ] := 255 ;
      cur_step_len := 1 ;

      FOR ped_in := 1 TO 255
      DO IF ( adc_out[rele,ch_typ,ped_in] > 1 )
      THEN BEGIN

        IF ( adc_out[rele,ch_typ,ped_in] > adc_out[rele,ch_typ,ped_in-1]+1 )
        THEN min_step_len[rele,ch_typ] := 0 ;

        IF ( adc_out[rele,ch_typ,ped_in] = adc_out[rele,ch_typ,ped_in-1] )
        THEN cur_step_len := cur_step_len + 1
        ELSE BEGIN
          IF ( max_step_len[rele,ch_typ] < cur_step_len )
          THEN max_step_len[rele,ch_typ] := cur_step_len ;
          IF ( min_step_len[rele,ch_typ] > cur_step_len )
          THEN min_step_len[rele,ch_typ] := cur_step_len ;
          cur_step_len := 1 ;
        END ; {if}

      END ; {do if}

    END ; {ch_typ}
  END ; {rele}

END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE build_formated_report ;

VAR

  line_num     : INTEGER ;
  column       : INTEGER ;
  rele             : relative_eta ;
  ch_typ           : adc_data_type_per_ctfe_channel ;

BEGIN

  FOR line_num := 1 TO 24 DO result_line[line_num] := ' ' ;

  result_line[l_title] := 'CTFE ( '
                        + CONVERT(STRING,e_pol) + ', '
                        + CONVERT(STRING,e_fe)  + ', '
                        + CONVERT(STRING,phi)   + ' ) '
                        + ' @ cbus: ' + CONVERT(STRING(2),ctfe_data[e_pol,e_fe,phi].cbus)
                        + ' mba: '    + CONVERT(STRING(4),ctfe_data[e_pol,e_fe,phi].mba)
                        + ' ca: '     + CONVERT(STRING(3),ctfe_data[e_pol,e_fe,phi].ca) ;

  SUBSTR ( result_line[l_chan_num], 2, 8 ) := ' SUMMARY ' ;
  SUBSTR ( result_line[l_chan_num], c_start+0*co_chan         ,16 ) := '   Channel #1  ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+0*co_chan         ,8  ) := ' EM Et ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+0*co_chan+co_HDEt ,8  ) := ' HD Et ' ;
  SUBSTR ( result_line[l_chan_num], c_start+1*co_chan         ,16 ) := '   Channel #2  ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+1*co_chan         ,8  ) := ' EM Et ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+1*co_chan+co_HDEt ,8  ) := ' HD Et ' ;
  SUBSTR ( result_line[l_chan_num], c_start+2*co_chan         ,16 ) := '   Channel #3  ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+2*co_chan         ,8  ) := ' EM Et ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+2*co_chan+co_HDEt ,8  ) := ' HD Et ' ;
  SUBSTR ( result_line[l_chan_num], c_start+3*co_chan         ,16 ) := '   Channel #4  ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+3*co_chan         ,8  ) := ' EM Et ' ;
  SUBSTR ( result_line[l_chan_typ], c_start+3*co_chan+co_HDEt ,8  ) := ' HD Et ' ;
  SUBSTR ( result_line[l_noise_var],   2 ) := '   St.Dev.' ;
  SUBSTR ( result_line[l_sample_size], 2 ) := 'Sample Siz' ;
  SUBSTR ( result_line[l_viol_tot],    2 ) := 'Monot Viol' ;
  SUBSTR ( result_line[l_first_viol],  2 ) := '   First @' ;
  SUBSTR ( result_line[l_intercept],   2 ) := ' Intercept' ;
  SUBSTR ( result_line[l_slope],       2 ) := '     Slope' ;
  SUBSTR ( result_line[l_worst_err],   2 ) := ' Worst Dev' ;
  SUBSTR ( result_line[l_w_err_at],    2 ) := '         @' ;
  SUBSTR ( result_line[l_min_step],    2 ) := '  Min Step' ;
  SUBSTR ( result_line[l_max_step],    2 ) := '  Max step' ;
  SUBSTR ( result_line[l_b_stuck_H],   2 ) := ' B stuck H' ;
  SUBSTR ( result_line[l_b_stuck_L],   2 ) := ' B stuck L' ;

  FOR rele := rele_0 TO rele_3
  DO BEGIN
    FOR ch_typ := EMEtZ0 TO HDEtZ0
    DO BEGIN

      column := c_start+ORD(rele)*co_chan+ORD(ch_typ)*co_HDEt ;

      IF ( noise_var[rele,ch_typ] <> 0 )
      THEN BEGIN
        SUBSTR ( result_line[l_noise_var], column ) := decimal_string ( 6, SQRT( noise_var[rele,ch_typ] ) ) ;
        CASE ch_typ OF
          EMEtZ0 : IF ( noise_var[rele,ch_typ] > 0.75 ** 2 )
                   THEN SUBSTR ( result_line[l_noise_var], column+6 ) := '?' ;
          HDEtZ0 : IF ( noise_var[rele,ch_typ] > 1.0 ** 2 )
                   THEN SUBSTR ( result_line[l_noise_var], column+6 ) := '?' ;
        END ;
      END ;{if}

      SUBSTR ( result_line[l_sample_size], column ) := CONVERT(STRING(6),sample_per_point[rele,ch_typ]) ;

      IF ( monoton_viol[rele,ch_typ,total] <> 0 )
      THEN BEGIN
        SUBSTR ( result_line[l_viol_tot], column ) := CONVERT(STRING(6),monoton_viol[rele,ch_typ,total]) ;
        SUBSTR ( result_line[l_viol_tot], column+6 ) := '?' ;
        SUBSTR ( result_line[l_first_viol], column ) := CONVERT(STRING(6),monoton_viol[rele,ch_typ,first_at]) ;
      END ;{if}

      SUBSTR ( result_line[l_intercept], column ) := CONVERT(STRING(6),ROUND(zero_adc_ped[rele,ch_typ])) ;
      IF ( ( zero_adc_ped[rele,ch_typ] <= 1 ) OR ( zero_adc_ped[rele,ch_typ] > 15 ) )
      THEN SUBSTR ( result_line[l_intercept], column+6 ) := '?' ;

      IF ( adc_per_ped[rele,ch_typ] < 0.001 )
      THEN
        SUBSTR ( result_line[l_slope], column, 6 ) := '     0'
      ELSE BEGIN { build a display string in the format of 1/x.xx }
        SUBSTR ( result_line[l_slope], column+1, 5 ) := decimal_string ( 5, 1 / adc_per_ped[rele,ch_typ] ) ;
        SUBSTR ( result_line[l_slope], column, 2 ) := '1/' ;
      END ;
      IF ( ( ABS(adc_per_ped[rele,ch_typ] - 1/3) * 3 ) > 0.05 )
      THEN SUBSTR ( result_line[l_slope], column+6 ) := '?' ;

      SUBSTR ( result_line[l_worst_err], column   ) := decimal_string ( 6, worst_error[rele,ch_typ] ) ;
      IF ( ABS(worst_error[rele,ch_typ]) > 0.8 )
      THEN SUBSTR ( result_line[l_worst_err], column+6 ) := '?' ;
      SUBSTR ( result_line[l_w_err_at], column ) := CONVERT(STRING(6),w_err_at[rele,ch_typ]) ;

      SUBSTR ( result_line[l_min_step], column ) := CONVERT(STRING(6),min_step_len[rele,ch_typ]) ;
      IF ( min_step_len[rele,ch_typ] < 1 )
      THEN SUBSTR ( result_line[l_min_step], column+6 ) := '?' ;

      SUBSTR ( result_line[l_max_step], column ) := CONVERT(STRING(6),max_step_len[rele,ch_typ]) ;
      IF ( max_step_len[rele,ch_typ] > 4 )
      THEN SUBSTR ( result_line[l_max_step], column+6 ) := '?' ;

      IF ( bit_stuck_high[rele,ch_typ] <> 0 )
      THEN SUBSTR ( result_line[l_b_stuck_H], column ) := BIN(bit_stuck_high[rele,ch_typ],8,8) ;
      IF ( bit_stuck_low[rele,ch_typ]  < 127 )
      THEN SUBSTR ( result_line[l_b_stuck_L], column ) := BIN(bit_stuck_low[rele,ch_typ],8,8) ;

    END ;{ch_typ}
  END ;{rele}

END ;
{ **************************************************************************** }
{ **************************************************************************** }
PROCEDURE report_to_screen_and_file ;

VAR

  line_num     : INTEGER ;

BEGIN

  IF ( result_open = 1 )
  THEN BEGIN

    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := '---------------------------------------------------------' ) ;
    handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                            OUTSTRING := 'Statistics Summary' ) ;

    FOR line_num := l_title TO 24
    DO handle_write_result ( RESULT_FILE := ADDRESS(result_file),
                               OUTSTRING := result_line[line_num] ) ;

    close_result_file ( RESULT_FILE := ADDRESS(result_file) ) ;

  END ;

  clearscreen ;
  display_console ( scroll(4,23) ) ;
  display_console ( bold ) ;
  display_console ( goxy(l_title,1)       + result_line[l_title]    ) ;
  display_console ( goxy(l_chan_num,1)    + result_line[l_chan_num] ) ;
  display_console ( goxy(l_chan_typ,1)    + result_line[l_chan_typ] ) ;
  display_console ( goxy(l_noise_var,1)   + SUBSTR ( result_line[l_noise_var],   1, c_start-3 ) ) ;
  display_console ( goxy(l_sample_size,1) + SUBSTR ( result_line[l_sample_size], 1, c_start-3 ) ) ;
  display_console ( goxy(l_viol_tot,1)    + SUBSTR ( result_line[l_viol_tot],    1, c_start-3 ) ) ;
  display_console ( goxy(l_first_viol,1)  + SUBSTR ( result_line[l_first_viol],  1, c_start-3 ) ) ;
  display_console ( goxy(l_intercept,1)   + SUBSTR ( result_line[l_intercept],   1, c_start-3 ) ) ;
  display_console ( goxy(l_slope,1)       + SUBSTR ( result_line[l_slope],       1, c_start-3 ) ) ;
  display_console ( goxy(l_worst_err,1)   + SUBSTR ( result_line[l_worst_err],   1, c_start-3 ) ) ;
  display_console ( goxy(l_w_err_at,1)    + SUBSTR ( result_line[l_w_err_at],    1, c_start-3 ) ) ;
  display_console ( goxy(l_min_step,1)    + SUBSTR ( result_line[l_min_step],    1, c_start-3 ) ) ;
  display_console ( goxy(l_max_step,1)    + SUBSTR ( result_line[l_max_step],    1, c_start-3 ) ) ;
  display_console ( goxy(l_b_stuck_H,1)   + SUBSTR ( result_line[l_b_stuck_H],   1, c_start-3 ) ) ;
  display_console ( goxy(l_b_stuck_L,1)   + SUBSTR ( result_line[l_b_stuck_L],   1, c_start-3 ) ) ;

  inline_draw_box ( l_title+1, 1, l_chan_typ, c_start-2 ) ;
  display_console ( standard ) ;
  inline_draw_box ( l_title+1, c_start+0*co_chan-1, l_chan_typ+1, c_start+1*co_chan-2 ) ;
  inline_draw_box ( l_title+1, c_start+1*co_chan-1, l_chan_typ+1, c_start+2*co_chan-2 ) ;
  inline_draw_box ( l_title+1, c_start+2*co_chan-1, l_chan_typ+1, c_start+3*co_chan-2 ) ;
  inline_draw_box ( l_title+1, c_start+3*co_chan-1, l_chan_typ+1, c_start+4*co_chan-2 ) ;
  inline_draw_box ( l_chan_typ+1, 1, 22, c_start-2 ) ;

  display_console ( goxy(l_noise_var,c_start-1)   + SUBSTR ( result_line[l_noise_var],   c_start-1 ) ) ;
  display_console ( goxy(l_sample_size,c_start-1) + SUBSTR ( result_line[l_sample_size], c_start-1 ) ) ;
  display_console ( goxy(l_viol_tot,c_start-1)    + SUBSTR ( result_line[l_viol_tot],    c_start-1 ) ) ;
  display_console ( goxy(l_first_viol,c_start-1)  + SUBSTR ( result_line[l_first_viol],  c_start-1 ) ) ;
  display_console ( goxy(l_intercept,c_start-1)   + SUBSTR ( result_line[l_intercept],   c_start-1 ) ) ;
  display_console ( goxy(l_slope,c_start-1)       + SUBSTR ( result_line[l_slope],       c_start-1 ) ) ;
  display_console ( goxy(l_worst_err,c_start-1)   + SUBSTR ( result_line[l_worst_err],   c_start-1 ) ) ;
  display_console ( goxy(l_w_err_at,c_start-1)    + SUBSTR ( result_line[l_w_err_at],    c_start-1 ) ) ;
  display_console ( goxy(l_min_step,c_start-1)    + SUBSTR ( result_line[l_min_step],    c_start-1 ) ) ;
  display_console ( goxy(l_max_step,c_start-1)    + SUBSTR ( result_line[l_max_step],    c_start-1 ) ) ;
  display_console ( goxy(l_b_stuck_H,c_start-1)   + SUBSTR ( result_line[l_b_stuck_H],   c_start-1 ) ) ;
  display_console ( goxy(l_b_stuck_L,c_start-1)   + SUBSTR ( result_line[l_b_stuck_L],   c_start-1 ) ) ;

END ;
{ **************************************************************************** }
{ **************************************************************************** }
{obsolete}
FUNCTION inline_bold_bin ( parse_byte : byte ; highlite : bit ) : VARYING_STRING(48) ;
VAR
  byte_structure : eight_bit_0_7 ;
  temp     : VARYING_STRING(48) ;
  bitnum   : INTEGER ;
BEGIN
  byte_structure::BYTE_DATA := parse_byte::BYTE_DATA ;
  temp := CHR(27) + '[0m' ;

  CASE highlite OF
    0 : FOR bitnum := 7 DOWNTO 0 DO
          CASE byte_structure.bitfield[bitnum] OF
            0 : temp := temp + CHR(27) + '[1m0' ;
            1 : temp := temp + CHR(27) + '[0m1' ;
          END ;
    1 : FOR bitnum := 7 DOWNTO 0 DO
          CASE byte_structure.bitfield[bitnum] OF
            0 : temp := temp + CHR(27) + '[0m0' ;
            1 : temp := temp + CHR(27) + '[1m1' ;
          END ;
    END ;

  inline_bold_bin := temp + CHR(27) + '[0m' ;

END ;
{ *************************************************************************** }
{ **************************************************************************** }
END .
