/*
* 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.
*/
#include <string.h>
#include "co_math.h"
#include "rt_plc.h"
#include "rt_plc_io.h"
PiPos
void pipos_exec(plc_sThread* tp, pwr_sClass_pipos* object)
{
float pdiff; /* Position difference from Kal1 */
int idiff; /* Raw value difference from Kal1 */
/* Read Input */
object->PulsIn = *object->PulsInP;
object->CalPos1 = *object->CalPos1P;
object->CalOrder1 = *object->CalOrder1P;
object->CalPos2 = *object->CalPos2P;
object->CalOrder2 = *object->CalOrder2P;
/* Calibration point 1 */
if (object->CalOrder1 && !object->CalOrder1Old) {
object->PosCal1 = object->ActVal = object->CalPos1;
object->PICal1 = object->PulsIn;
/* Clear order if manual */
if (object->CalOrder1P == &object->CalOrder1)
object->CalOrder1 = FALSE;
} else if (object->CalOrder2 && !object->CalOrder2Old) {
/* Calibration point 2 */
pdiff = object->CalPos2 - object->PosCal1;
idiff = object->PulsIn - object->PICal1;
if (!feqf(pdiff, 0.0f) && idiff != 0) {
object->Gain = pdiff / idiff;
object->PosCal2 = object->ActVal = object->CalPos2;
}
/* Clear order if manual */
if (object->CalOrder2P == &object->CalOrder2)
object->CalOrder2 = FALSE;
} else {
/* Calculate position when no calibration */
idiff = object->PulsIn - object->PICal1;
object->ActVal = object->PosCal1 + object->Gain * idiff;
}
/* Save old values */
object->CalOrder1Old = object->CalOrder1;
object->CalOrder2Old = object->CalOrder2;
}
Count
void count_exec(plc_sThread* tp, pwr_sClass_count* object)
{
float old; /* For flank detect */
/* Count up */
old = object->CountUp;
object->CountUp = *object->CountUpP;
if (object->CountUp && !old)
object->Accum++;
/* Count down */
old = object->CountDown;
object->CountDown = *object->CountDownP;
if (object->CountDown && !old)
object->Accum--;
/* Initialize */
old = object->Init;
object->Init = *object->InitP;
if (object->Init && !old)
object->Accum = object->Preset;
/* Clear */
old = object->Clear;
object->Clear = *object->ClearP;
if (object->Clear && !old)
object->Accum = 0;
/* Set Output status */
if (object->Accum > 0) {
object->Pos = TRUE;
object->Neg = FALSE;
object->Zero = FALSE;
} else if (object->Accum == 0) {
object->Pos = FALSE;
object->Neg = FALSE;
object->Zero = TRUE;
} else {
object->Pos = FALSE;
object->Neg = TRUE;
object->Zero = FALSE;
}
object->Equal = object->Accum == object->Preset;
}
BCDDO
void bcddo_exec(plc_sThread* tp, pwr_sClass_bcddo* object)
{
int val; /* One digit */
int i;
int j;
int tal;
int oldtal;
float rest; /* Overflow */
pwr_tBoolean* dopoint; /* Points to output */
rest = object->In = *object->InP; /* Get Input */
dopoint = &object->BCD0; /* Initialize pointer */
if (rest < 0)
rest = 0;
tal = rest / 10000;
tal = rest - tal * 10000;
rest = (rest - tal) / 10000;
for (i = 0; i < 4; i++) { /* Loop 4 digits */
oldtal = tal;
tal = tal / 10;
val = oldtal - 10 * tal; /* Integer 0 - 9 */
for (j = 0; j < 4; j++) {
*dopoint++ = (pwr_tBoolean)(val & 1);
val = val / 2;
}
}
object->Rest = rest;
}
DIBCD
#define DIBCDSIZE 16
void dibcd_exec(plc_sThread* tp, pwr_sClass_dibcd* object)
{
int val; /* One digit */
int i; /* Loop index*/
int j; /* Loop index*/
int res; /* Result */
char* ptr; /* Pointer to pointer */
pwr_tBoolean* p2; /* Pointer to digin */
pwr_tBoolean err; /* Error flag */
/* Initialize */
res = 0;
err = FALSE;
ptr = (char*)&object->BCD0P + (DIBCDSIZE - 1) * pwr_cInputOffset;
/* Double loop for convert */
for (i = 0; i < (DIBCDSIZE / 4); i++) {
val = 0;
for (j = 0; j < 4; j++) {
val += val; /* Mult 2 */
p2 = *(pwr_tBoolean**)ptr; /* Pointer to input */
if (*p2 != object->Inv)
val++; /* Signal till ? */
ptr -= pwr_cInputOffset; /* Pointer to next pointer */
}
if (val > 9)
err = TRUE;
res = 10 * res + val;
}
if (!err)
object->ActVal = res;
object->Error = err;
}
Gray
#define GRAYSIZE 16
void gray_exec(plc_sThread* tp, pwr_sClass_gray* object)
{
int i; /* Loopcounter */
pwr_tBoolean in; /* Digital in after invert */
pwr_tBoolean odd; /* Convert flag */
int sum; /* Convert sum */
char* ptr; /* Pointer to ptr to digin */
pwr_tBoolean* p2; /* Pointer to digin */
/* Init */
odd = 0;
sum = 0;
ptr = (char*)&object->Din0P + (GRAYSIZE - 1) * pwr_cInputOffset;
/* Graycode convert loop */
for (i = 0; i < GRAYSIZE; i++) {
sum += sum; /* Mult 2 */
p2 = *(pwr_tBoolean**)ptr; /* Pointer to next dig in */
in = (*p2 != object->Inv); /* Invert ? */
odd = in ? !odd : odd; /* Odd up to now ? */
sum += odd; /* Inc if odd input */
ptr -= pwr_cInputOffset;
}
/* Result */
object->ActVal = sum;
}
GETDPPTR
void GetDpPtr_init(pwr_sClass_GetDpPtr* o)
{
pwr_tUInt32 p;
pwr_tAttrRef aref = o->DpPtrObject;
/* Reset the indirect bit to fetch the pointer, not the value */
aref.Flags.b.Indirect = 0;
if (ODD(gdh_GetObjectInfoAttrref(&aref, &p, sizeof(p))))
o->Ptr = gdh_TranslateRtdbPointer(p);
}
void GetDpPtr_exec(plc_sThread* tp, pwr_sClass_GetDpPtr* o)
{
if (o->Ptr)
o->Value = *o->Ptr;
}
GETAPPTR
void GetApPtr_init(pwr_sClass_GetApPtr* o)
{
pwr_tUInt32 p;
pwr_tAttrRef aref = o->ApPtrObject;
/* Reset the indirect bit to fetch the pointer, not the value */
aref.Flags.b.Indirect = 0;
if (ODD(gdh_GetObjectInfoAttrref(&aref, &p, sizeof(p))))
o->Ptr = gdh_TranslateRtdbPointer(p);
}
void GetApPtr_exec(plc_sThread* tp, pwr_sClass_GetApPtr* o)
{
if (o->Ptr)
o->Value = *o->Ptr;
}
GETIPPTR
void GetIpPtr_init(pwr_sClass_GetIpPtr* o)
{
pwr_tUInt32 p;
pwr_tAttrRef aref = o->IpPtrObject;
/* Reset the indirect bit to fetch the pointer, not the value */
aref.Flags.b.Indirect = 0;
if (ODD(gdh_GetObjectInfoAttrref(&aref, &p, sizeof(p))))
o->Ptr = gdh_TranslateRtdbPointer(p);
}
void GetIpPtr_exec(plc_sThread* tp, pwr_sClass_GetIpPtr* o)
{
if (o->Ptr)
o->Value = *o->Ptr;
}
STODPPTR
void StoDpPtr_init(pwr_sClass_StoDpPtr* o)
{
pwr_tUInt32 p;
pwr_tAttrRef aref = o->DpPtrObject;
/* Reset the indirect bit to fetch the pointer, not the value */
aref.Flags.b.Indirect = 0;
if (ODD(gdh_GetObjectInfoAttrref(&aref, &p, sizeof(p))))
o->Ptr = gdh_TranslateRtdbPointer(p);
}
void StoDpPtr_exec(plc_sThread* tp, pwr_sClass_StoDpPtr* o)
{
if (o->Ptr)
*o->Ptr = *o->InP;
}
STOAPPTR
void StoApPtr_init(pwr_sClass_StoApPtr* o)
{
pwr_tUInt32 p;
pwr_tAttrRef aref = o->ApPtrObject;
/* Reset the indirect bit to fetch the pointer, not the value */
aref.Flags.b.Indirect = 0;
if (ODD(gdh_GetObjectInfoAttrref(&aref, &p, sizeof(p))))
o->Ptr = gdh_TranslateRtdbPointer(p);
}
void StoApPtr_exec(plc_sThread* tp, pwr_sClass_StoApPtr* o)
{
if (o->Ptr)
*o->Ptr = *o->InP;
}
STOIPPTR
void StoIpPtr_init(pwr_sClass_StoIpPtr* o)
{
pwr_tUInt32 p;
pwr_tAttrRef aref = o->IpPtrObject;
/* Reset the indirect bit to fetch the pointer, not the value */
aref.Flags.b.Indirect = 0;
if (ODD(gdh_GetObjectInfoAttrref(&aref, &p, sizeof(p))))
o->Ptr = gdh_TranslateRtdbPointer(p);
}
void StoIpPtr_exec(plc_sThread* tp, pwr_sClass_StoIpPtr* o)
{
if (o->Ptr)
*o->Ptr = *o->InP;
}
ENUMTOSTR
void EnumToStr_init(pwr_sClass_EnumToStr* o)
{
if (EVEN(gdh_GetEnumValueDef(
o->TypeId, (gdh_sValueDef**)&o->EnumDefP, (int*)&o->EnumDefRows)))
o->EnumDefP = 0;
}
void EnumToStr_exec(plc_sThread* tp, pwr_sClass_EnumToStr* o)
{
int i;
int found = 0;
if (!o->EnumDefP)
return;
for (i = 0; i < o->EnumDefRows; i++) {
if (((gdh_sValueDef*)o->EnumDefP)[i].Value->Value == *o->InP) {
strncpy(o->ActVal, ((gdh_sValueDef*)o->EnumDefP)[i].Value->Text,
sizeof(o->ActVal));
found = 1;
break;
}
}
if (!found)
strcpy(o->ActVal, "");
}
STRTOENUM
void StrToEnum_init(pwr_sClass_StrToEnum* o)
{
if (EVEN(gdh_GetEnumValueDef(
o->TypeId, (gdh_sValueDef**)&o->EnumDefP, (int*)&o->EnumDefRows)))
o->EnumDefP = 0;
}
void StrToEnum_exec(plc_sThread* tp, pwr_sClass_StrToEnum* o)
{
int i;
int found = 0;
if (!o->EnumDefP)
return;
for (i = 0; i < o->EnumDefRows; i++) {
if (strcmp((char*)o->StrP, ((gdh_sValueDef*)o->EnumDefP)[i].Value->Text)
== 0) {
o->ActVal = ((gdh_sValueDef*)o->EnumDefP)[i].Value->Value;
found = 1;
break;
}
}
if (!found)
o->ActVal = 0;
}