// $Id: pdinrs_channel.c,v 1.2 2005/03/23 23:11:56 pdi Exp $
/******************************************************************************/
// Copyright 1998-2022 Stonie R. Cooper, Licensed under the auspices of GPLv3,
// See top-level copyright disclaimer (COPYRIGHT) and license (LICENSE)
// File:   pdinrs_channel.c
// Author: Stonie R. Cooper
// Documentation:
// Revision Record:
//         Rewritten: 20050114 by Stonie R. Cooper
//                  - created file and added includes and function declara-
//                    tion. Borrowed heavily from pdinrs_buffer.c
/******************************************************************************/

// include file listing - derivated

#include <pdinrs.h>
#include <pdinrs_channel_config.h>
#include <pdinrs_set_output.h>
#include <pdi_logger.h>
#include <pdi_make_path.h>
#include <pdi_signals.h>
#include <sys/time.h>

double elapsed_time(struct timeval current_time, struct timeval old_time);

void channel_stream(channel_type *channel_struct)
{
// Configuration structures
  ChanSettingsType   channel_settings;
  StreamSettingsType stream_settings;
  ProductSettingsType product_settings;
  char                error_message[256];
  char                verbose_path[256];
  signed char         error_code = 0;

// Thread structures
  buffer_type        buffer_struct;
  distribution_type  distribution_struct;
	pid_t              thisThreadPID = 0;
	pid_t              myParentThreadsPID = 0;

// Buffer file header structures
  buffer_header_type buffer_header;
  buffer_header_mutex_type buffer_mutex;

  unsigned char local_quiet        = FALSE;
  unsigned char local_restart      = FALSE;
  unsigned char local_exit         = FALSE;
  unsigned char new_data_flag      = FALSE;

  pthread_t           buffer_thread;
  pthread_attr_t      buffer_sched_attr;
  int buffer_fifo_max, buffer_fifo_min, buffer_fifo_mid;
  struct sched_param  buffer_param;
  pthread_t           distribution_thread;

  pthread_mutex_t     m_next_write_byte  = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     m_first_data_byte  = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     m_maximum_bytes    = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     m_next_read_byte   = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     m_frame_count      = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     m_new_data         = PTHREAD_MUTEX_INITIALIZER;
  pthread_cond_t      c_new_data         = PTHREAD_COND_INITIALIZER;

  pthread_mutex_t     idr_mutex          = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     odr_mutex          = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     cm_mutex           = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     cno_mutex          = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t     demod_mutex        = PTHREAD_MUTEX_INITIALIZER;

  unsigned int   idr = 0;
  unsigned int   local_current_idr = 0;
  unsigned int   local_previous_idr = 0;
  unsigned int   odr = 0;
  unsigned int   product_size = 0;
  unsigned int   local_current_odr = 0;
  unsigned int   local_product_size = 0;
  unsigned int   local_previous_odr = 0;
  char                cm[81];
  char                local_cm[81];
  time_t              rt = 0;
  time_t              local_rt = 0;
  unsigned int   ff = 0;
  unsigned int   local_ff = 0;
  unsigned int   cf = 0;
  unsigned int   local_cf = 0;
  unsigned int   fr = 0;
  unsigned int   local_fr = 0;
  unsigned int   mt = 0;
  unsigned int   local_mt = 0;
  unsigned int   mr = 0;
  unsigned int   local_mr = 0;
  unsigned int   tb = 0;
  unsigned int   local_tb = 0;
  unsigned int   tgb = 0;
  unsigned int   local_tgb = 0;
  unsigned char       cno = 0;
  unsigned char       local_cno = 0;
	
	char                LongNCFWaitWmo[81];
	char                localLongNCFWaitWmo[81];
	unsigned int   LongNCFWait = 0;
	unsigned int   localLongNCFWait = 0;
	signed int     CurNCFWait = 0;
	signed int     localCurNCFWait = 0;
	unsigned int   AveNCFWait = 0;
	unsigned int   localAveNCFWait = 0;
	
	unsigned int   LongTransit = 0;
	unsigned int   localLongTransit = 0;
	signed int     CurTransit = 0;
	signed int     localCurTransit = 0;
	unsigned int   AveTransit = 0;
	unsigned int   localAveTransit = 0;

  double              time_passed = 0.0;
  double              incoming_rate = 0.0;
  double              outgoing_rate = 0.0;
  double              peak_idr = 0.0;
  double              peak_odr = 0.0;
  time_t              idr_max_time = 0;
  time_t              odr_max_time = 0;
  char                proc_path[256];
  char                proc_throughput[512];
  int                 proc_handle = -1;
  int                 stats_handle = -1;
  char                stats_path[256];
  double              local_rawBER = 0.0;
  double              local_EBNZero = 0.0;
  receiver_type       demod;

  struct timeval c_time;
  struct timeval o_time;
  struct timezone timez;

  buffer_mutex.next_write_byte           = &m_next_write_byte;
  buffer_mutex.first_data_byte           = &m_first_data_byte;
  buffer_mutex.maximum_bytes             = &m_maximum_bytes;
  buffer_mutex.next_read_byte            = &m_next_read_byte;
  buffer_mutex.frame_count               = &m_frame_count;
  buffer_header.frame_count              = 0;

// Initialize some of the structs and arrays

  memset((void *)&channel_settings, 0, sizeof(ChanSettingsType));
  memset((void *)&stream_settings, 0, sizeof(StreamSettingsType));
  memset((void *)&product_settings, 0, sizeof(ProductSettingsType));
  memset((void *)error_message, 0, sizeof(error_message));
  memset((void *)cm, 0, sizeof(cm));
  memset((void *)local_cm, 0, sizeof(local_cm));
  memset((void *)LongNCFWaitWmo, 0, sizeof(LongNCFWaitWmo));
  memset((void *)localLongNCFWaitWmo, 0, sizeof(localLongNCFWaitWmo));
  memset((void *)proc_path, 0, sizeof(proc_path));
  memset((void *)stats_path, 0, sizeof(stats_path));
  memset((void *)&c_time, 0, sizeof(struct timeval));
  memset((void *)&o_time, 0, sizeof(struct timeval));
  memset((void *)&timez, 0, sizeof(struct timezone));
  memset((void *)&demod, 0, sizeof(receiver_type));
  gettimeofday(&c_time, &timez);
  gettimeofday(&o_time, &timez);

  sprintf(proc_path, "/dev/shm/pdinrs/.proc/%s", channel_struct->label);
  sprintf(stats_path, "/dev/shm/pdinrs/.proc/%s.stats", channel_struct->label);

// Read configuration file

  pthread_mutex_lock(channel_struct->ui->quiet_mutex);
  local_quiet = channel_struct->ui->quiet;
  pthread_mutex_unlock(channel_struct->ui->quiet_mutex);

  if ((error_code = pdinrs_channel_config(channel_struct->config_file,
                    &channel_settings, &stream_settings, 
                    &product_settings, channel_struct->label)) != PDINRSCONFIG_SUCCESS)
  {
    if (!local_quiet && channel_struct->error->log_file_ptr != NULL)
    {
			switch (error_code)
			{
				case -1:
				{
					sprintf(error_message, "%s channel: Configuring channel: cannot open %s",
              channel_struct->label, channel_struct->config_file);
					break;
				}
				case -2:
				{
					sprintf(error_message, "%s channel: Configuring channel: %s is not a proper config file",
              channel_struct->label, channel_struct->config_file);
					break;
				}
				case -3:
				{
					sprintf(error_message, "%s channel: Configuring channel: Cannot set value to parameter",
							channel_struct->label);
					break;
				}
				case -4:
				{
					sprintf(error_message, "%s channel: Configuring channel: Cannot read parameter name",
							channel_struct->label);
					break;
				}
				case -5:
				{
					sprintf(error_message, 
							"%s channel: Configuring channel: Cannot read config file line from %s",
              channel_struct->label, channel_struct->config_file);
					break;
				}
				default:
				{
					sprintf(error_message, 
							"%s channel: Configuring channel: Error reading %s, error = %d",
              channel_struct->label, channel_struct->config_file, error_code);
				}
			}
      logger(*channel_struct->error, error_message);
			sprintf(error_message, "Stopping processing");
      logger(*channel_struct->error, error_message);
    }
    pthread_mutex_lock(channel_struct->ui->exit_mutex);
    channel_struct->ui->exit = TRUE;
    pthread_mutex_unlock(channel_struct->ui->exit_mutex);
    return;
  }

// Open the log files
	

	thisThreadPID = getpid();
	myParentThreadsPID = getppid();

  pthread_mutex_lock(channel_struct->ui->quiet_mutex);
  if (!channel_struct->ui->quiet)
  {
    memset((void *)verbose_path, 0, sizeof(verbose_path));
    strcpy(verbose_path, channel_settings.errorFile.log_path);
    set_output(verbose_path, NULL, NULL, NULL, NULL, 0, 0, 0, channel_struct->label, NULL, 0, NULL, NULL);
    if ((channel_settings.errorFile.log_file_ptr =
         fopen(verbose_path, "wb+")) == NULL)
    {
      if ((make_path(verbose_path)) == FALSE)
      {
        channel_struct->ui->quiet = TRUE;
        if (channel_struct->error->log_file_ptr != NULL)
        {
          sprintf(error_message, "%s channel: Setting error logging: Cannot open log file = %s",
              channel_struct->label, verbose_path);
          logger(*channel_struct->error, error_message);
        }
      }
      else
      {
        if ((channel_settings.errorFile.log_file_ptr =
             fopen(verbose_path, "wb+")) == NULL)
        {
          channel_struct->ui->quiet = TRUE;
          if (channel_struct->error->log_file_ptr != NULL)
          {
            sprintf(error_message, "%s channel: Setting error logging: Cannot open log file = %s",
              channel_struct->label, verbose_path);
            logger(*channel_struct->error, error_message);
          }
        }
        else
        {
          sprintf(error_message, "%s channel: Starting logging: Successful",
                  channel_struct->label);
          logger(channel_settings.errorFile, error_message);
        }
      }
    }
    else
    {
      sprintf(error_message, "%s channel: Starting logging: Successful",
              channel_struct->label);
      logger(channel_settings.errorFile, error_message);
    }
  }
  if (!channel_struct->ui->quiet)
  {
    memset((void *)verbose_path, 0, sizeof(verbose_path));
    strcpy(verbose_path, channel_settings.logFile.log_path);
    set_output(verbose_path, NULL, NULL, NULL, NULL, 0, 0, 0, channel_struct->label, NULL, 0, NULL, NULL);
    if ((channel_settings.logFile.log_file_ptr =
         fopen(verbose_path, "wb+")) == NULL)
    {
      if ((make_path(verbose_path)) == FALSE)
      {
        channel_struct->ui->quiet = TRUE;
        if (channel_struct->error->log_file_ptr != NULL)
        {
          sprintf(error_message, "%s channel: Setting error logging: Cannot open log file = %s",
              channel_struct->label, verbose_path);
          logger(*channel_struct->error, error_message);
        }
      }
      else
      {
        if ((channel_settings.logFile.log_file_ptr =
             fopen(verbose_path, "wb+")) == NULL)
        {
          channel_struct->ui->quiet = TRUE;
          if (channel_struct->error->log_file_ptr != NULL)
          {
            sprintf(error_message, "%s channel: Setting error logging: Cannot open log file = %s",
              channel_struct->label, verbose_path);
            logger(*channel_struct->error, error_message);
          }
        }
        else
        {
          sprintf(error_message, "%s channel: Starting logging: Successful",
                  channel_struct->label);
          logger(channel_settings.logFile, error_message);
        }
      }
    }
    else
    {
      sprintf(error_message, "%s channel: Starting logging: Successful",
              channel_struct->label);
      logger(channel_settings.logFile, error_message);
    }
  }
  local_quiet = channel_struct->ui->quiet;
  pthread_mutex_unlock(channel_struct->ui->quiet_mutex);

  if (!local_quiet)
  {
    sprintf(error_message, "%s channel: Startup configuration: successful",
            channel_struct->label);
    logger(channel_settings.logFile, error_message);
  }

// Set up the buffer structure and distribution structure

  demod.receiver_mutex               = &demod_mutex;
  buffer_struct.ui                   = channel_struct->ui;
  buffer_struct.restart              = channel_struct->restart;
  strcpy(buffer_struct.label, channel_struct->label);
  buffer_struct.array_number         = channel_struct->array_number;
  buffer_struct.mutex                = &buffer_mutex;
  buffer_struct.header               = &buffer_header;
  buffer_struct.new_data_cond        = &c_new_data;
  buffer_struct.new_data_flag        = &new_data_flag;
  buffer_struct.new_data_mutex       = &m_new_data;
  buffer_struct.error_file           = &channel_settings.errorFile;
  buffer_struct.idr_mutex            = &idr_mutex;
  buffer_struct.idr                  = &idr;
  buffer_struct.demod                = &demod;
  buffer_struct.replay               = channel_struct->replay;

  distribution_struct.ui             = channel_struct->ui;
  distribution_struct.restart        = channel_struct->restart;
  strcpy(distribution_struct.label, channel_struct->label);
  distribution_struct.array_number   = channel_struct->array_number;
  distribution_struct.mutex          = &buffer_mutex;
  distribution_struct.header         = &buffer_header;
  distribution_struct.new_data_cond  = &c_new_data;
  distribution_struct.new_data_flag  = &new_data_flag;
  distribution_struct.new_data_mutex = &m_new_data;
  distribution_struct.error_file     = &channel_settings.errorFile;
  distribution_struct.odr_mutex      = &odr_mutex;
  distribution_struct.cm_mutex       = &cm_mutex;
  distribution_struct.cno_mutex      = &cno_mutex;
  distribution_struct.odr            = &odr;
  distribution_struct.product_size   = &product_size;
  distribution_struct.cm             = cm;
  distribution_struct.cno            = &cno;
  distribution_struct.rt             = &rt;
  distribution_struct.ff             = &ff;
  distribution_struct.cf             = &cf;
  distribution_struct.fr             = &fr;
  distribution_struct.mt             = &mt;
  distribution_struct.mr             = &mr;
  distribution_struct.tb             = &tb;
  distribution_struct.tgb            = &tgb;

  distribution_struct.LongNCFWaitWmo = LongNCFWaitWmo;
  distribution_struct.LongNCFWait    = &LongNCFWait;
  distribution_struct.CurNCFWait     = &CurNCFWait;
  distribution_struct.AveNCFWait     = &AveNCFWait;
  distribution_struct.LongTransit    = &LongTransit;
  distribution_struct.CurTransit     = &CurTransit;
  distribution_struct.AveTransit     = &AveTransit;
  distribution_struct.replay         = channel_struct->replay;

  strcpy(buffer_struct.config_file, stream_settings.streamManagerConfigFile);
  strcpy(distribution_struct.config_file, 
    product_settings.productManagerConfigFile);

  if (!local_quiet)
  {
    sprintf(error_message, "%s channel: Starting channel buffer",
            channel_struct->label);
    logger(channel_settings.logFile, error_message);
  }
//  pthread_attr_t      buffer_sched_attr;
//  int buffer_fifo_max, buffer_fifo_min;
//  struct sched_param  buffer_param;

  pthread_attr_init(&buffer_sched_attr);
  memset((void *)&buffer_param, 0, sizeof(buffer_param));
  pthread_attr_setscope(&buffer_sched_attr, PTHREAD_SCOPE_SYSTEM);
  pthread_attr_setinheritsched(&buffer_sched_attr, PTHREAD_EXPLICIT_SCHED);
  pthread_attr_setschedpolicy(&buffer_sched_attr, SCHED_FIFO);

  buffer_fifo_max = sched_get_priority_max(SCHED_FIFO);
  buffer_fifo_min = sched_get_priority_min(SCHED_FIFO);
  buffer_fifo_mid = (buffer_fifo_max + buffer_fifo_min) / 2;
  buffer_param.sched_priority = buffer_fifo_mid;

  pthread_attr_setschedparam(&buffer_sched_attr, &buffer_param);

// Spawn buffer thread
  if ((error_code = pthread_create(&buffer_thread, NULL, (void *)nrs_buffer, 
                    (void *)&buffer_struct)) != 0)
  {

    fprintf(stderr, "Error code = %d\n", error_code);
    fflush(stderr);

    if (!local_quiet)
    {
      sprintf(error_message, "%s channel: Starting channel buffer: Thread creation unsuccessful: error = %d",
              channel_struct->label, error_code);
      logger(channel_settings.logFile, error_message);
      sprintf(error_message, "%s channel: Stopping processing",
              channel_struct->label);
      logger(channel_settings.errorFile, error_message);
      logger(channel_settings.logFile, error_message);
      fclose(channel_settings.logFile.log_file_ptr);
      channel_settings.logFile.log_file_ptr = NULL;
      fclose(channel_settings.errorFile.log_file_ptr);
      channel_settings.errorFile.log_file_ptr = NULL;
    }
    pthread_mutex_lock(channel_struct->ui->exit_mutex);
    channel_struct->ui->exit = TRUE;
    pthread_mutex_unlock(channel_struct->ui->exit_mutex);
    if (proc_handle != -1)
    {
      close(proc_handle);
      proc_handle = -1;
    }
    if (stats_handle != -1)
    {
      close(stats_handle);
      stats_handle = -1;
    }
    return;
  }

  if (!local_quiet)
  {
    sprintf(error_message, "%s channel: Starting channel buffer: Successful",
            channel_struct->label);
    logger(channel_settings.logFile, error_message);
  }

// Spawn distribution thread
  pthread_mutex_lock(&m_new_data);
  while (new_data_flag == FALSE)
  {
    pthread_cond_wait(&c_new_data, &m_new_data);
  }
  pthread_mutex_unlock(&m_new_data);

  pthread_mutex_lock(channel_struct->ui->exit_mutex);
  local_exit = channel_struct->ui->exit;
  pthread_mutex_unlock(channel_struct->ui->exit_mutex);

  if (local_exit)
  {
    pthread_join(buffer_thread, NULL);
    if (!local_quiet)
    {
      sprintf(error_message, "%s channel: Stopping processing",
              channel_struct->label);
      logger(channel_settings.errorFile, error_message);
      logger(channel_settings.logFile, error_message);
      fclose(channel_settings.logFile.log_file_ptr);
      channel_settings.logFile.log_file_ptr = NULL;
      fclose(channel_settings.errorFile.log_file_ptr);
      channel_settings.errorFile.log_file_ptr = NULL;
    }
    if (proc_handle != -1)
    {
      close(proc_handle);
      proc_handle = -1;
    }
    if (stats_handle != -1)
    {
      close(stats_handle);
      stats_handle = -1;
    }
    return;
  }

  if (!local_quiet)
  {
    sprintf(error_message, "%s channel: Starting channel distribution",
            channel_struct->label);
    logger(channel_settings.logFile, error_message);
  }
  if ((error_code = pthread_create(&distribution_thread, NULL, 
                    (void *)nrs_distribution,
                    (void *)&distribution_struct)) != 0)
  {
    if (!local_quiet)
    {
      sprintf(error_message, "%s channel: Starting channel distribution: Thread creation unsuccessful: error = %d",
              channel_struct->label, error_code);
      logger(channel_settings.logFile, error_message);
      sprintf(error_message, "%s channel: Stopping processing",
              channel_struct->label);
      logger(channel_settings.errorFile, error_message);
      logger(channel_settings.logFile, error_message);
      fclose(channel_settings.logFile.log_file_ptr);
      channel_settings.logFile.log_file_ptr = NULL;
      fclose(channel_settings.errorFile.log_file_ptr);
      channel_settings.errorFile.log_file_ptr = NULL;
    }
    pthread_mutex_lock(channel_struct->ui->exit_mutex);
    channel_struct->ui->exit = TRUE;
    pthread_mutex_unlock(channel_struct->ui->exit_mutex);
    if (proc_handle != -1)
    {
      close(proc_handle);
      proc_handle = -1;
    }
    if (stats_handle != -1)
    {
      close(stats_handle);
      stats_handle = -1;
    }
    return;
  }

  if (!local_quiet)
  {
    sprintf(error_message, "%s channel: Starting channel distribution: Successful",
            channel_struct->label);
    logger(channel_settings.logFile, error_message);
  }

// *****************************************************************************
// // Idle Loop: this is where the infinite loop maintains the buffer input.
// *****************************************************************************
for (;;)
{
// First, let's grab a local copy of the current scope level flags.

    pthread_mutex_lock(channel_struct->restart->restart_mutex);
    local_restart = channel_struct->restart->restart;
    pthread_mutex_unlock(channel_struct->restart->restart_mutex);

    pthread_mutex_lock(channel_struct->ui->exit_mutex);
    local_exit = channel_struct->ui->exit;
    pthread_mutex_unlock(channel_struct->ui->exit_mutex);

// Next, we look to see if we should be exiting.
    if (local_restart || local_exit)
    {
      if (!local_quiet)
      {
        sprintf(error_message, "%s channel: Stopping processing",
              channel_struct->label);
        logger(channel_settings.errorFile, error_message);
        logger(channel_settings.logFile, error_message);
        fclose(channel_settings.logFile.log_file_ptr);
        channel_settings.logFile.log_file_ptr = NULL;
        fclose(channel_settings.errorFile.log_file_ptr);
        channel_settings.errorFile.log_file_ptr = NULL;
      }
      pthread_mutex_lock(&m_new_data);
      if (new_data_flag == FALSE)
      {
        new_data_flag = TRUE;
        pthread_cond_signal(&c_new_data);
      }
      pthread_mutex_unlock(&m_new_data);

      pthread_join(buffer_thread, NULL);
      pthread_join(distribution_thread, NULL);
      if (proc_handle != -1)
      {
        close(proc_handle);
        proc_handle = -1;
      }
      if (stats_handle != -1)
      {
        close(stats_handle);
        stats_handle = -1;
      }
      return;
    }

// We didn't exit, so now let's check the quiet mode.

    pthread_mutex_lock(channel_struct->ui->quiet_mutex);
    local_quiet = channel_struct->ui->quiet;
    pthread_mutex_unlock(channel_struct->ui->quiet_mutex);

// If we have a new request to quiet, we check to see if the log files are
//   open - close them if they are open.

    if (local_quiet && channel_settings.logFile.log_file_ptr != NULL)
    {
      sprintf(error_message, "%s channel: Stopping logging now",
              channel_struct->label);
      logger(channel_settings.logFile, error_message);
      fclose(channel_settings.logFile.log_file_ptr);
      channel_settings.logFile.log_file_ptr = NULL;
    }
    if (local_quiet && channel_settings.errorFile.log_file_ptr != NULL)
    {
      sprintf(error_message, "%s channel: Stopping logging now",
              channel_struct->label);
      logger(channel_settings.errorFile, error_message);
      fclose(channel_settings.errorFile.log_file_ptr);
      channel_settings.errorFile.log_file_ptr = NULL;
    }

// Now we do a check to see if we need to turn the logging back on, when it wasn't
//   on to start with.

    if (!local_quiet && channel_settings.logFile.log_file_ptr == NULL)
    {
      memset((void *)verbose_path, 0, sizeof(verbose_path));
      strcpy(verbose_path, channel_settings.logFile.log_path);
      set_output(verbose_path, NULL, NULL, NULL, NULL, 0, 0, 0, channel_struct->label, NULL, 0, NULL, NULL);
      if ((channel_settings.logFile.log_file_ptr =
           fopen(verbose_path, "wb+")) == NULL)
      {
        if ((make_path(verbose_path)) == FALSE)
        {
          pthread_mutex_lock(channel_struct->ui->quiet_mutex);
          channel_struct->ui->quiet = TRUE;
          pthread_mutex_unlock(channel_struct->ui->quiet_mutex);
        }
        else
        {
          if ((channel_settings.logFile.log_file_ptr =
               fopen(verbose_path, "wb+")) == NULL)
          {
            pthread_mutex_lock(channel_struct->ui->quiet_mutex);
            channel_struct->ui->quiet = TRUE;
            pthread_mutex_unlock(channel_struct->ui->quiet_mutex);
          }
          else
          {
            sprintf(error_message, "%s channel: Starting logging: Successful",
                  channel_struct->label);
            logger(channel_settings.logFile, error_message);
          }
        }
      }
      else
      {
        sprintf(error_message, "%s channel: Starting logging: Successful",
              channel_struct->label);
        logger(channel_settings.logFile, error_message);
      }
    }

    pthread_mutex_lock(channel_struct->ui->quiet_mutex);
    local_quiet = channel_struct->ui->quiet;
    pthread_mutex_unlock(channel_struct->ui->quiet_mutex);

    if (!local_quiet && channel_settings.errorFile.log_file_ptr == NULL)
    {
      memset((void *)verbose_path, 0, sizeof(verbose_path));
      strcpy(verbose_path, channel_settings.errorFile.log_path);
      set_output(verbose_path, NULL, NULL, NULL, NULL, 0, 0, 0, channel_struct->label, NULL, 0, NULL, NULL);
      if ((channel_settings.errorFile.log_file_ptr =
           fopen(verbose_path, "wb+")) == NULL)
      {
        if ((make_path(verbose_path)) == FALSE)
        {
          pthread_mutex_lock(channel_struct->ui->quiet_mutex);
          channel_struct->ui->quiet = TRUE;
          pthread_mutex_unlock(channel_struct->ui->quiet_mutex);
        }
        else
        {
          if ((channel_settings.errorFile.log_file_ptr =
               fopen(verbose_path, "wb+")) == NULL)
          {
            pthread_mutex_lock(channel_struct->ui->quiet_mutex);
            channel_struct->ui->quiet = TRUE;
            pthread_mutex_unlock(channel_struct->ui->quiet_mutex);
          }
          else
          {
            sprintf(error_message, "%s channel: Starting logging: Successful",
                  channel_struct->label);
            logger(channel_settings.errorFile, error_message);
          }
        }
      }
      else
      {
        sprintf(error_message, "%s channel: Starting logging: Successful",
              channel_struct->label);
        logger(channel_settings.errorFile, error_message);
      }
    }

// Setting up the counts for pdinrs_top info

    pthread_mutex_lock(&idr_mutex);
    local_current_idr = idr;
    pthread_mutex_unlock(&idr_mutex);

    pthread_mutex_lock(&odr_mutex);
    local_current_odr = odr;
    local_product_size = product_size;
    pthread_mutex_unlock(&odr_mutex);
    
    pthread_mutex_lock(&demod_mutex);
    local_rawBER = demod.rawBER;
    local_EBNZero = demod.EBNZero;
    pthread_mutex_unlock(&demod_mutex);

    pthread_mutex_lock(&cm_mutex);
    memcpy((void *)local_cm, cm, 80);
    memcpy((void *)localLongNCFWaitWmo, LongNCFWaitWmo, 80);
    local_rt = rt;
    local_ff = ff;
    local_cf = cf;
    local_fr = fr;
    local_mt = mt;
    local_mr = mr;
    local_tb = tb;
    local_tgb = tgb;
		localLongNCFWait = LongNCFWait;
		localCurNCFWait = CurNCFWait;
		localAveNCFWait = AveNCFWait;
		localLongTransit = LongTransit;
		localCurTransit = CurTransit;
		localAveTransit = AveTransit;
    pthread_mutex_unlock(&cm_mutex);
    
    local_cm[27] = '\0';

    pthread_mutex_lock(&cno_mutex);
    local_cno = cno;
    pthread_mutex_unlock(&cno_mutex);

    gettimeofday(&c_time, &timez);
    time_passed = elapsed_time(c_time, o_time);
    memcpy((void *)&o_time, &c_time, sizeof(struct timeval));

    if (time_passed < (double)SLEEP_TIME)
      time_passed = (double)SLEEP_TIME;

    if (local_previous_idr > local_current_idr)
      local_previous_idr = 0;

    if (local_previous_odr > local_current_odr)
      local_previous_odr = 0;

    incoming_rate = ((double)(local_current_idr - local_previous_idr)) / time_passed;
    if (incoming_rate > peak_idr)
    {
      peak_idr = incoming_rate;
      time(&idr_max_time);
    }
    outgoing_rate = ((double)(local_current_odr - local_previous_odr)) / time_passed;
    if (outgoing_rate > peak_odr)
    {
      peak_odr = outgoing_rate;
      time(&odr_max_time);
    }

// And before we are completely done, set previous

    local_previous_idr = local_current_idr;
    local_previous_odr = local_current_odr;

    if (proc_handle < 3)
      proc_handle = open(proc_path, O_WRONLY | O_NONBLOCK);
    if (proc_handle >= 3)
    {
      memset((void *)proc_throughput, 0, sizeof(proc_throughput));
      sprintf(proc_throughput, "%4d %-27s %13.5f %13d %13.5f %13.5f %13d %13.5f %13d %13u %13u %13u %13u %13u %13u %13u %13u %3.1f %6.1e %13u %13u\n",
        local_cno, local_cm, peak_idr, (int)idr_max_time, incoming_rate, 
        peak_odr, (int)odr_max_time, outgoing_rate, local_product_size,
        (int)local_rt, local_ff, local_cf, local_fr, local_mt, local_mr, local_tb, local_tgb,
        local_EBNZero, local_rawBER, localCurTransit, localCurNCFWait);
      if ((write(proc_handle, (void *)proc_throughput, strlen(proc_throughput))) < 0)
      {
        close(proc_handle);
        proc_handle = -1;
      }
    }          
        
    if (stats_handle < 3)
      stats_handle = open(stats_path, O_WRONLY | O_NONBLOCK);
    if (stats_handle >= 3)
    {
      memset((void *)proc_throughput, 0, sizeof(proc_throughput));
      sprintf(proc_throughput, "%13u %13u %13u %13u %13u %13u %13u %13u %13u %13d %13u %13u %13d %13u %24s\n",
              (int)local_rt, local_ff, local_cf, local_fr, local_mt, local_mr, local_tb, local_tgb,
							localLongTransit, localCurTransit, localAveTransit, localLongNCFWait, localCurNCFWait,
							localAveNCFWait, localLongNCFWaitWmo);
      if ((write(stats_handle, (void *)proc_throughput, strlen(proc_throughput))) < 0)
      {
        close(stats_handle);
        stats_handle = -1;
      }
    }

// Add a sleep to keep this loop from hogging the CPU

    sleep(SLEEP_TIME);
  }
}

double elapsed_time(struct timeval current_time, struct timeval old_time)
{
  return (double)((current_time.tv_sec - old_time.tv_sec)
      + (double)(current_time.tv_usec - old_time.tv_usec) / 1000000.0);
}
