/*
 * ProviewR   Open Source Process Control.
 * Copyright (C) 2005-2025 SSAB EMEA AB.
 *
 * This file is part of ProviewR.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ProviewR. If not, see <http://www.gnu.org/licenses/>
 *
 * Linking ProviewR statically or dynamically with other modules is
 * making a combined work based on ProviewR. Thus, the terms and
 * conditions of the GNU General Public License cover the whole
 * combination.
 *
 * In addition, as a special exception, the copyright holders of
 * ProviewR give you permission to, from the build function in the
 * ProviewR Configurator, combine ProviewR with modules generated by the
 * ProviewR PLC Editor to a PLC program, regardless of the license
 * terms of these modules. You may copy and distribute the resulting
 * combined work under the terms of your choice, provided that every
 * copy of the combined work is accompanied by a complete copy of
 * the source code of ProviewR (the version used to produce the
 * combined work), being distributed under the terms of the GNU
 * General Public License plus this exception.
 */
/* rt_c_plcthread.c
   Functions for the class PlcThread. */
#include <string.h>
#include <pthread.h>
#include "co_time.h"
#include "rt_gdh_msg.h"
#include "rt_c_plcthread.h"
#define cNanoSec 1.0e-9

PlcThread


pwr_sClass_PlcThread* pwrb_PlcThread_Init(pwr_tStatus* sts, plc_sThread* tp)
{
  pwr_sClass_PlcThread* o;
  *sts
      = gdh_DLRefObjectInfoAttrref(&tp->aref, (void*)&tp->PlcThread, &tp->dlid);
  if (EVEN(*sts))
    return NULL;
  o = tp->PlcThread;
  tp->f_scan_time = o->ScanTime;
  tp->prio = o->Prio;
  o->Dlid = tp->dlid;
  return o;
}
void pwrb_PlcThread_Exec(plc_sThread* tp)
{
  pwr_tDeltaTime last;
  int meanCount;
  pwr_sClass_PlcThread* o = tp->PlcThread;
  if (o == NULL)
    return;
  o->ActualScanTime = tp->ActualScanTime;
  meanCount = o->ScanTimeMeanCount;
  if ((meanCount != 0) && (o->Count % meanCount == 0)) {
    if (o->Count != 0) {
      double diff;
      time_Dsub(&last, (pwr_tDeltaTime*)&tp->before_scan_abs,
          (pwr_tDeltaTime*)&o->ScanTimeStart);
      diff = last.tv_sec + last.tv_nsec * cNanoSec;
      o->ScanTimeMean = diff / meanCount;
    }
    o->ScanTimeStart.tv_sec = tp->before_scan_abs.tv_sec;
    o->ScanTimeStart.tv_nsec = tp->before_scan_abs.tv_nsec;
  }
  o->Count++;
  if (o->Count != 1) {
    double scanTime;
    time_Dsub(&last, (pwr_tDeltaTime*)&tp->before_scan_abs,
        (pwr_tDeltaTime*)&tp->one_before_scan_abs);
    scanTime = last.tv_nsec * cNanoSec + last.tv_sec;
    if (scanTime < o->ScanTimeMin)
      o->ScanTimeMin = scanTime;
    if (scanTime > o->ScanTimeMax)
      o->ScanTimeMax = scanTime;
  }
  time_Dsub(&last, (pwr_tDeltaTime*)&tp->after_scan_abs,
      (pwr_tDeltaTime*)&tp->before_scan_abs);
  o->Last = last.tv_nsec * cNanoSec + last.tv_sec;
  if (o->Last < o->Min)
    o->Min = o->Last;
  if (o->Last > o->Max)
    o->Max = o->Last;
  o->Sum += o->Last;
  o->Mean = o->Sum / o->Count;
  o->Coverage = 0.99 * o->Coverage + 0.01 * (o->Last / o->ScanTime) * 100.0;
  if (o->Last < o->Limit_1_8)
    o->Count_1_8++;
  else if (o->Last < o->Limit_1_4)
    o->Count_1_4++;
  else if (o->Last < o->Limit_1_2)
    o->Count_1_2++;
  else if (o->Last < o->Limit_1_1)
    o->Count_1_1++;
  else if (o->Last < o->Limit_2_1)
    o->Count_2_1++;
  else if (o->Last < o->Limit_4_1)
    o->Count_4_1++;
  else if (o->Last < o->Limit_8_1)
    o->Count_8_1++;
  else
    o->CountHigh++;
  o->SlipCount = tp->sliped;
}
void pwrb_PlcThread_Zero(plc_sThread* tp)
{
  pwr_sClass_PlcThread* o;
  o = tp->PlcThread;
  o->Limit_1_8 = o->ScanTime / 8.0;
  o->Limit_1_4 = o->ScanTime / 4.0;
  o->Limit_1_2 = o->ScanTime / 2.0;
  o->Limit_1_1 = o->ScanTime;
  o->Limit_2_1 = o->ScanTime * 2.0;
  o->Limit_4_1 = o->ScanTime * 4.0;
  o->Limit_8_1 = o->ScanTime * 8.0;
  o->ScanTimeMin = 1.0e30;
  o->ScanTimeMean = 0.0;
  o->ScanTimeMax = 0.0;
  /* Update ScanTimeMean after 100 loops or after 10 seconds */
  o->ScanTimeMeanCount = MIN(100., MAX(10. / o->ScanTime, 1)) + .5;
  o->ScanTimeStart.tv_sec = 0;
  o->ScanTimeStart.tv_nsec = 0;
  o->Count = 0;
  o->Sum = 0.0;
  o->Min = 1.0e30;
  o->Mean = 0.0;
  o->Coverage = 0.0;
  o->Max = 0.0;
  o->Count_1_8 = 0;
  o->Count_1_4 = 0;
  o->Count_1_2 = 0;
  o->Count_1_1 = 0;
  o->Count_2_1 = 0;
  o->Count_4_1 = 0;
  o->Count_8_1 = 0;
  o->CountHigh = 0;
  o->SlipCount = 0;
}