<?xml version="1.0" encoding="utf-8"?>---
FUNCTION_BLOCK IoDrvMonarco EXTENDS IoDrvBase
VAR
_IIoDrv: ICmpIoDrv;
_IIoDrvParameter: ICmpIoDrvParameter;
Monarco: MonarcoItf;
_dwInUse: DWORD;
_xBackGroundDiagStarted: BOOL;
_bDeactivated: BOOL;
END_VAR
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
END_VAR
VAR
Result: UDINT;
CLASSID_CCmpIoDrvTemplate: DWORD;
END_VAR
FB_Init_Count := FB_Init_Count + 1;
m_Info.szDriverName := 'IoDrvMonarco';
m_Info.szVendorName := 'Monarcio.IO';
m_Info.szDeviceName := 'Monarco HAT';
m_Info.wModuleType := 501;
_IIoDrv := THIS^;
_IIoDrvParameter := THIS^;
m_IBaseItf := THIS^;
m_hInterface := IoMgrRegisterInstance2(dwClassId:=CLASSID_CCmpIoDrvTemplate, pItf:=m_IBaseItf, pResult:=ADR(Result));
FB_Init := TRUE;
METHOD FB_Exit: BOOL
VAR_INPUT
bInCopyCode: BOOL;
END_VAR
FB_Exit_Count := FB_Exit_Count + 1;
FB_Exit := TRUE;
METHOD FB_Reinit: BOOL
FB_Reinit_Count := FB_Reinit_Count + 1;
FB_Reinit := TRUE;
METHOD QueryInterface: pointer
VAR_INPUT
iid: DWORD;
pResult: pointer;
END_VAR
QueryInterface_Count := QueryInterface_Count + 1;
IF iid = ITFID_ICmpIoDrv THEN
QueryInterface := ADR(_IIoDrv);
AddRef();
IF (pResult <> 0) THEN
pResult^ := Errors.ERR_OK;
END_IF
RETURN;
ELSIF iid = ITFID_ICmpIoDrvParameter THEN
QueryInterface := ADR(_IIoDrvParameter);
AddRef();
IF (pResult <> 0) THEN
pResult^ := Errors.ERR_OK;
END_IF
RETURN;
ELSE
QueryInterface := SUPER^.QueryInterface(iid, pResult);
END_IF
METHOD Initialize: UDINT
VAR_INPUT
wModuleType: UINT;
dwInstance: UDINT;
pConnector: pointer;
END_VAR
Initialize_Count := Initialize_Count + 1;
m_wModuleType := wModuleType;
m_dwInstance := dwInstance;
m_Info.wModuleType := wModuleType;
Monarco.Initialize(wModuleType, dwInstance, pConnector);
Initialize := Errors.ERR_OK;
METHOD IoDrvReadParameter: UDINT
VAR_INPUT
pConnector: pointer;
pParameter: pointer;
pData: pointer;
dwBitSize: DWORD;
dwBitOffset: DWORD;
END_VAR
IF pConnector = 0 OR pParameter = 0 OR pData = 0 THEN
IoDrvReadParameter := Errors.ERR_PARAMETER;
RETURN;
END_IF
// All standard parameters of our device are handled by the IO-manager!
IoDrvReadParameter := Errors.ERR_FAILED;
METHOD IoDrvWriteParameter: UDINT
VAR_INPUT
pConnector: pointer;
pParameter: pointer;
pData: pointer;
dwBitSize: DWORD;
dwBitOffset: DWORD;
END_VAR
VAR
pParam: pointer;
pstDiagString: pointer;
END_VAR
IF pConnector = 0 OR pParameter = 0 OR pData = 0 THEN
IoDrvWriteParameter := Errors.ERR_PARAMETER;
RETURN;
END_IF
IoDrvWriteParameter := Errors.ERR_FAILED;
METHOD IoDrvGetConnector: pointer
VAR_INPUT
pResult: pointer;
END_VAR
IF m_pConnector = 0 THEN
IF pResult <> 0 THEN
pResult^ := Errors.ERR_FAILED;
END_IF
IoDrvGetConnector := 0;
RETURN;
END_IF
IF pResult <> 0 THEN
pResult^ := Errors.ERR_OK;
END_IF
IoDrvGetConnector := m_pConnector;
METHOD IoDrvIdentify: UDINT
VAR_INPUT
pConnector: pointer;
END_VAR
IoDrvIdentify_Count := IoDrvIdentify_Count + 1;
IoDrvIdentify := Errors.ERR_NOTIMPLEMENTED;
METHOD IoDrvWatchdogTrigger: UDINT
VAR_INPUT
pConnector: pointer;
END_VAR
IoDrvWatchdogTrigger_Count := IoDrvWatchdogTrigger_Count + 1;
IoDrvWatchdogTrigger := Errors.ERR_OK;
METHOD IoDrvGetModuleDiagnosis: UDINT
VAR_INPUT
pConnector: pointer;
END_VAR
IF pConnector = 0 THEN
//we are called from the background task
_xBackGroundDiagStarted := TRUE;
END_IF
//Todo: update connectorflags if something changed
IoDrvGetModuleDiagnosis_Count := IoDrvGetModuleDiagnosis_Count + 1;
IoDrvGetModuleDiagnosis := Errors.ERR_NOTIMPLEMENTED;
METHOD IoDrvWriteOutputs: UDINT
VAR_INPUT
pConnectorMapList: pointer;
nCount: DINT;
END_VAR
VAR
i: DINT;
j: DINT;
wSize: WORD;
pbyIecAddress: pointer;
bySrcValue: BYTE;
wSrcIndex: WORD;
bySrcMask: BYTE;
wDestIndex: WORD;
ptr: pointer;
ptrW: pointer;
ptrB: pointer;
END_VAR
IoDrvWriteOutputs_Count := IoDrvWriteOutputs_Count + 1;
IF pConnectorMapList = 0 OR nCount = 0 THEN
IoDrvWriteOutputs := Errors.ERR_PARAMETER;
RETURN;
END_IF
FOR i:=0 TO nCount - 1 DO
IF (pConnectorMapList[i].dwNumOfChannels = 0) THEN
CONTINUE;
END_IF
FOR j:= 0 TO UDINT_TO_UINT(pConnectorMapList[i].dwNumOfChannels) - 1 DO
wSrcIndex := pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset / 8;
pbyIecAddress := pConnectorMapList[i].pChannelMapList[j].pbyIecAddress;
IF (pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId >= 2000 AND pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId<=2002)
OR (pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId >= 9010 AND pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId<=9016)
OR (pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId >= 9030 AND pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId<=9031) THEN
IF pConnectorMapList[i].pChannelMapList[j].wSize = 1 THEN
bySrcValue := pbyIecAddress[wSrcIndex];
IF (pbyIecAddress[wSrcIndex] AND SHL(BYTE#1, pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset MOD 8)) <> 0 THEN
{IF defined (pou:SysCpuSetBit2)}
SysCpuSetBit2(pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific, pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset MOD 8);
{ELSE}
SysCpuSetBit(pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific, pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset MOD 8);
{END_IF}
ELSE
{IF defined (pou:SysCpuResetBit2)}
SysCpuResetBit2(pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific, pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset MOD 8);
{ELSE}
SysCpuResetBit(pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific, pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset MOD 8);
{END_IF}
END_IF
ELSIF pConnectorMapList[i].pChannelMapList[j].wSize = 8 THEN
ptr:= pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific;
ptr^ := pbyIecAddress[wSrcIndex];
END_IF
ELSIF pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId = 2100 THEN
IF pConnectorMapList[i].pChannelMapList[j].wSize = 16 THEN
ptrW:= pbyIecAddress;
Monarco.wAOut1 := ptrW^;
END_IF
ELSIF pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId = 2101 THEN
IF pConnectorMapList[i].pChannelMapList[j].wSize = 16 THEN
ptrW:= pbyIecAddress;
Monarco.wAOut2 := ptrW^;
END_IF
END_IF
END_FOR
END_FOR
IoDrvWriteOutputs := Errors.ERR_OK;
METHOD IoDrvUpdateMapping: UDINT
VAR_INPUT
pTaskMapList: pointer;
nCount: DINT;
END_VAR
IoDrvUpdateMapping_Count := IoDrvUpdateMapping_Count + 1;
IF (pTaskMapList = 0) THEN
IoDrvUpdateMapping := Errors.ERR_PARAMETER;
RETURN;
END_IF
IoDrvUpdateMapping := Errors.ERR_OK;
METHOD IoDrvUpdateConfiguration: UDINT
VAR_INPUT
pConnectorList: pointer;
nCount: DINT;
END_VAR
VAR
pParameter: pointer;
pChild: pointer;
pstConnectorVendorName: pointer;
pstConnectorDeviceName: pointer;
dwTest: pointer;
Result: RTS_IEC_RESULT;
END_VAR
IoDrvUpdateConfiguration_Count := IoDrvUpdateConfiguration_Count + 1;
IoDrvUpdateConfiguration := Errors.ERR_OK;
IF (pConnectorList = 0) THEN
// Reset application
// TODO: Free resources
RETURN;
END_IF
m_pConnector := IoMgrConfigGetConnector(pConnectorList, ADR(nCount), m_wModuleType, m_dwInstance);
IF m_pConnector = 0 THEN
IoDrvUpdateConfiguration := ERRORS.ERR_PARAMETER;
RETURN;
END_IF
//check if device is enabled in the device tree
IF (m_pConnector^.dwFlags AND ConnectorFlags.CF_ENABLE) = 0 THEN
_bDeactivated := TRUE;
IoDrvUpdateConfiguration := Errors.ERR_OK;
RETURN;
END_IF
IF m_pConnector^.hIoDrv = 0 THEN
m_pConnector^.hIoDrv := m_hInterface;
m_pConnector^.pFather^.hIoDrv := m_hInterface;
{IF defined (pou:IoMgrConfigSetDiagnosis)}
IoMgrConfigSetDiagnosis(m_pConnector,
ConnectorFlags.CF_DRIVER_AVAILABLE OR
ConnectorFlags.CF_CONNECTOR_FOUND OR
ConnectorFlags.CF_CONNECTOR_CONFIGURED OR
ConnectorFlags.CF_CONNECTOR_ACTIVE);
{END_IF}
{IF defined (pou:IoMgrConfigSetDiagnosis)}
IoMgrConfigSetDiagnosis(m_pConnector^.pFather,
ConnectorFlags.CF_DRIVER_AVAILABLE OR
ConnectorFlags.CF_CONNECTOR_FOUND OR
ConnectorFlags.CF_CONNECTOR_CONFIGURED OR
ConnectorFlags.CF_CONNECTOR_ACTIVE);
{END_IF}
{IF defined (pou:IoMgrSetDriverProperties)}
IoMgrSetDriverProperties(m_hInterface, DRVPROP_CONSISTENCY OR DRVPROP_BACKGROUND_GETDIAG);
//Note: background diagnosis property flag is optional (supported with 3.5.1.0 runtime)
{END_IF}
//Setup I/O area
pParameter := IoMgrConfigGetParameter(m_pConnector, 2000); (* outputs *)
IF (pParameter <> 0) THEN
pParameter^.dwDriverSpecific := ADR(Monarco.byDOut);
END_IF
//Go through all childs of the device
pChild := IoMgrConfigGetFirstChild(m_pConnector, ADR(nCount), m_pConnector);
WHILE (pChild <> 0) DO
IF (pChild^.dwFlags AND ConnectorFlags.CF_ENABLE) <> 0 THEN
pChild^.hIoDrv := m_hInterface;
{IF defined (pou:IoMgrConfigSetDiagnosis)}
IoMgrConfigSetDiagnosis(pChild,
ConnectorFlags.CF_DRIVER_AVAILABLE OR
ConnectorFlags.CF_CONNECTOR_FOUND OR
ConnectorFlags.CF_CONNECTOR_CONFIGURED OR
ConnectorFlags.CF_CONNECTOR_ACTIVE);
{END_IF}
END_IF
pChild := IoMgrConfigGetNextChild(pChild, ADR(nCount), m_pConnector);
END_WHILE
END_IF
METHOD IoDrvStartBusCycle: UDINT
VAR_INPUT
pConnector: pointer;
END_VAR
IoDrvStartBusCycle_Count := IoDrvStartBusCycle_Count + 1;
//if background diagnosis is not active call IoDrvGetModuleDiagnosis; normally it will be called by the runtime if DRVPROP_BACKGROUND_GETDIAG is set
IF NOT _xBackGroundDiagStarted THEN
IoDrvGetModuleDiagnosis(m_pConnector); //DRVPROP_BACKGROUND_GETDIAG not set or runtime version < V3.5.1.0
END_IF
//optional: call IoDrvWatchdogTrigger or set driver property DRVPROP_WATCHDOG in UpdateConfiguration
IoDrvWatchdogTrigger(pConnector);
IF NOT _bDeactivated THEN
Monarco.AfterReadInputs();
Monarco.BeforeWriteOutputs();
END_IF
IoDrvStartBusCycle := Errors.ERR_OK;
METHOD IoDrvScanModules: UDINT
VAR_INPUT
pConnector: pointer;
ppConnectorList: pointer;
pnCount: pointer;
END_VAR
IoDrvScanModules_Count := IoDrvScanModules_Count + 1;
IoDrvScanModules := Errors.ERR_NOTIMPLEMENTED;
METHOD IoDrvReadInputs: UDINT
VAR_INPUT
pConnectorMapList: pointer;
nCount: DINT;
END_VAR
VAR
i: DINT;
j: DINT;
wSize: WORD;
pbyIecAddress: pointer;
pwIecAddress: pointer;
prIecAddress: pointer;
prPiXtendSrc: pointer;
bySrcValue: BYTE;
bySrcMask: BYTE;
wSrcIndex: WORD;
wDestIndex: WORD;
END_VAR
IoDrvReadInputs_Count := IoDrvReadInputs_Count + 1;
IF pConnectorMapList = 0 OR nCount = 0 THEN
IoDrvReadInputs := Errors.ERR_PARAMETER;
RETURN;
END_IF
FOR i:=0 TO nCount - 1 DO
IF (pConnectorMapList[i].dwNumOfChannels = 0) THEN
CONTINUE;
END_IF
FOR j:= 0 TO UDINT_TO_UINT(pConnectorMapList[i].dwNumOfChannels) - 1 DO
IF pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId =1000 THEN
pbyIecAddress := pConnectorMapList[i].pChannelMapList[j].pbyIecAddress;
wDestIndex := pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset / 8;
IF (pConnectorMapList[i].pChannelMapList[j].wSize = 1) THEN
IF (Monarco.byDIn AND SHL(BYTE#1, pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset MOD 8)) <> 0 THEN
{IF defined (pou:SysCpuSetBit2)}
SysCpuSetBit2(ADR(pbyIecAddress[wDestIndex]), pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset MOD 8);
{ELSE}
SysCpuSetBit(ADR(pbyIecAddress[wDestIndex]), pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset MOD 8);
{END_IF}
ELSE
{IF defined (pou:SysCpuResetBit2)}
SysCpuResetBit2(ADR(pbyIecAddress[wDestIndex]), pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset MOD 8);
{ELSE}
SysCpuResetBit(ADR(pbyIecAddress[wDestIndex]), pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset MOD 8);
{END_IF}
END_IF
ELSIF pConnectorMapList[i].pChannelMapList[j].wSize = 8 THEN
pbyIecAddress[wDestIndex] := Monarco.byDIn;
END_IF
ELSIF pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId = 1110 THEN
pwIecAddress := pConnectorMapList[i].pChannelMapList[j].pbyIecAddress;
pwIecAddress^:= Monarco.wAIn1;
ELSIF pConnectorMapList[i].pChannelMapList[j].pParameter^.dwParameterId = 1111 THEN
pwIecAddress := pConnectorMapList[i].pChannelMapList[j].pbyIecAddress;
pwIecAddress^:= Monarco.wAIn2;
END_IF
END_FOR
END_FOR
IoDrvReadInputs := Errors.ERR_OK;
FUNCTION_BLOCK MonarcoItf EXTENDS SPI
VAR_INPUT
byDOut: BYTE;
wAOut1: WORD;
wAOut2: WORD;
END_VAR
VAR_OUTPUT
byDIn: BYTE;
wAIn1: WORD;
wAIn2: WORD;
END_VAR
VAR
_xInit: BOOL;
stHwConfig: stHWConfig1;
stAOut: stAOut;
stDOut: stDOut;
byLeds: BYTE;
udiPWM1freq: UDINT;
rDutyCycleDOut1: REAL;
rDutyCycleDOut2: REAL;
rDutyCycleDOut3: REAL;
udiPWM2freq: UDINT;
rDutyCycleDOut4: REAL;
xOperational: BOOL;
stDIn: stDIn;
stAIn: stAIn;
stCounter1Config: stCounter1Config;
stCounter2Config: stCounter2Config;
stPWM1: stPWM1;
stPWM2: stPWM2;
stHATinfo: stHATinfo;
eComStatus: eMonarcoComStatus;
_uiNumberOfDevices: INT;
_stControlByte: stControlByte;
_ControlByte8: BYTE;
_uiWatchDog: UINT;
_uiLastWatchDog: UINT;
_stRS485Mode: stRS485Mode;
_stHWConfig1: stHWConfig1;
_stLastCounter1Cfg: stCounter1Config;
_stLastCounter2Cfg: stCounter2Config;
_AfterReadInputs: UINT;
_BeforeWriteOutputs: UINT;
_abyIntTxBuf: ARRAY [..] OF ;
_abyIntRxBuf: ARRAY [..] OF ;
END_VAR
//********************************
// base SPI implementation
//********************************
SUPER^();
//********************************
// get SPI State
//********************************
CASE _iState OF
0:
IF SUPER^.init() THEN
// get only once
THIS^.getHATinfo();
_iState := 1;
END_IF
1: _iState := 10;
END_CASE
//********************************
// is device operational
//********************************
IF _iState = 10 THEN
xOperational := TRUE;
ELSE
xOperational := FALSE;
END_IF
METHOD getHATinfo:
VAR
wValue: WORD;
eCmd: eServiceCommand;
eComStatus: eMonarcoComStatus;
J: INT;
wReqAdr: WORD;
awSrvAnwser: ARRAY [..] OF ;
cpu_l: DWORD;
cpu_h: DWORD;
lwcpu: LWORD;
END_VAR
//********************************
//Read FW, HW revision and CPU-ID
//********************************
FOR J := 1 TO 9 DO
CASE J OF
1: eCmd := eServiceCommand.SDC_FIXED_STATUSWORD; //bogus question (ABCD)
2: eCmd := eServiceCommand.SDC_FIXED_FWVERL;
3: eCmd := eServiceCommand.SDC_FIXED_FWVERH;
4: eCmd := eServiceCommand.SDC_FIXED_HWVERL;
5: eCmd := eServiceCommand.SDC_FIXED_HWVERH;
6: eCmd := eServiceCommand.SDC_FIXED_CPUID1;
7: eCmd := eServiceCommand.SDC_FIXED_CPUID2;
8: eCmd := eServiceCommand.SDC_FIXED_CPUID3;
9: eCmd := eServiceCommand.SDC_FIXED_CPUID4;
END_CASE
wValue := TO_WORD(eServiceCommand.SDC_FIXED_STATUSWORD);
eComStatus := THIS^.ServiceRequest( wValue := wValue, eCommand := eCmd, xWrite := FALSE );
// Get result
eComStatus := THIS^.dataTransfer();
awSrvAnwser[J] := MEM.PackBytesToWord(_abyIntRxBuf[1], _abyIntRxBuf[0]);
END_FOR
// Store anwsers in status
THIS^.stHATinfo.dwFWVersion := MEM.PackWordsToDword(awSrvAnwser[3],awSrvAnwser[2]);
THIS^.stHATinfo.dwHWversion := MEM.PackWordsToDword(awSrvAnwser[5],awSrvAnwser[4]);
cpu_l := MEM.PackWordsToDword(awSrvAnwser[7],awSrvAnwser[6]);
cpu_h := MEM.PackWordsToDword(awSrvAnwser[9],awSrvAnwser[8]);
lwcpu := cpu_h;
lwcpu := SHL(lwcpu,32);
THIS^.stHATinfo.lwCpuID := lwcpu OR cpu_l;
METHOD getCRC: WORD
VAR_INPUT
abyBuf: ARRAY [..] OF ;
END_VAR
VAR
uiSizeTx: UINT;
udiCRCLen: UDINT;
pByteTx: pointer;
CheckSum: WORD;
END_VAR
// startadress of bytes
pByteTx := ADR(abyBuf);
// calculate CRC-16 checksum, beware that for the checksum calculation, we need to skip the checksum itself
uiSizeTx := SIZEOF(abyBuf);
// should always be 24 / 16#18
udiCRCLen := (uiSizeTx -16#02);
CheckSum := MEM.CRC16_Modbus( pByteTx, TO_UINT(udiCRCLen) );
// return checksum
getCRC := CheckSum;
METHOD dataTransfer: eMonarcoComStatus
VAR
tmpRxBuf: ARRAY [..] OF ;
udiBufSize: UDINT;
xDone: BOOL;
CRC: WORD;
END_VAR
//init temporay buffer before filling;
//flush(tmpRxBuf);
// determine size of buffer
udiBufSize := SIZEOF( THIS^._abyIntTxBuf );
(* Sets CRC16 checksum, for Tx byte array [24] and [25]*)
CRC := THIS^.getCRC( THIS^._abyIntTxBuf );
THIS^._abyIntTxBuf[24] := WORD_TO_BYTE(CRC);
THIS^._abyIntTxBuf[25] := WORD_TO_BYTE(SHR(CRC,8));
// Send, Recv
xDone := THIS^.transferExt( pabyTxBuffer := ADR( THIS^._abyIntTxBuf ),
pabyRxBuffer := ADR( tmpRxBuf ), // write result into a temporary buffer for post-analysis. Beware that the received answser is from the last question, not the current question.
udiLen := udiBufSize,
uiDelayus := 5,
udispeedHz := 0);
IF NOT xDone THEN
// Send, Recv failed
DataTransfer := eMonarcoComStatus.ERROR;
ELSE
// OK?
IF THIS^.checkCRC(tmpRxBuf) THEN
//CRC okay, return the recv buffer
THIS^._abyIntRxBuf := tmpRxBuf;
DataTransfer := eMonarcoComStatus.SUCCES;
ELSE
//CRC not okay, return an empty buffer
flush(tmpRxBuf);
THIS^._abyIntRxBuf := tmpRxBuf;
DataTransfer := eMonarcoComStatus.CrcFail;
END_IF
END_IF;
METHOD flush: BOOL
VAR_INPUT
abyRxBuf: ARRAY [..] OF ;
END_VAR
VAR
i: UINT;
END_VAR
//flush the temporary receive buffer before filling;
FOR i :=0 TO (ParamList.MONARCO_STRUCT_SIZE-1) DO
abyRxBuf[i] := 16#00;
END_FOR
flush := TRUE;
METHOD checkCRC: BOOL
VAR_INPUT
abyRxBuf: ARRAY [..] OF ;
END_VAR
VAR
CRC: WORD;
CRCLo: BYTE;
CRCHi: BYTE;
END_VAR
CRC := THIS^.GetCRC(abyRxBuf);
CRCHi := WORD_TO_BYTE(CRC);
CRCLo := WORD_TO_BYTE(SHR(CRC,8));
// check to self calculated CRC against the sent CRC, Equal = OK
IF (CRCHi = abyRxBuf[ParamList.MONARCO_STRUCT_SIZE - 2]) AND (CRCLo = abyRxBuf[ParamList.MONARCO_STRUCT_SIZE - 1]) THEN
checkCRC := TRUE;
ELSE
checkCRC := FALSE;
END_IF;
METHOD setDutyCycleDOut4: eMonarcoComStatus
VAR_INPUT
rDutyCycle: REAL;
END_VAR
VAR
wDC: WORD;
END_VAR
wDC := getDutyCycle( rDutyCycle := rDutyCycle );
// 18.0 2.0 PWM2 Dutycycle ch A
THIS^._abyIntTxBuf[18] := WORD_TO_BYTE(wDC); // bitmask to protect prescaler
THIS^._abyIntTxBuf[19] := WORD_TO_BYTE(SHR(wDC,8));
METHOD setDutyCycleDOut2: eMonarcoComStatus
VAR_INPUT
rDutyCycle: REAL;
END_VAR
VAR
wDC: WORD;
END_VAR
wDC := getDutyCycle( rDutyCycle := rDutyCycle );
// 12.0 2.0 PWM1 Dutycycle ch B
THIS^._abyIntTxBuf[12] := WORD_TO_BYTE(wDC); // bitmask to protect prescaler
THIS^._abyIntTxBuf[13] := WORD_TO_BYTE(SHR(wDC,8));
METHOD setPWM1freq: eMonarcoComStatus
VAR_INPUT
udiHz: UDINT;
END_VAR
VAR
_uidiHz: UDINT;
ePrescale: ePrescaler;
uiRangeLow: UINT;
uiRangeHigh: UINT;
uiTOP: UINT;
fPWM: WORD;
END_VAR
/// clip the input Hz on lower and upper bound, so;
_uidiHz := LIMIT( 1, udiHz, 100000);
/// Determine prescaler and TOP according to table
CASE _uidiHz OF
1..9 : ePrescale := ePrescaler.ScaleFactor512;
uiTOP := TO_UINT( (32000000/ 512/ _uidiHz));// interpolate between 1 and 9Hz
10..99 : ePrescale := ePrescaler.ScaleFactor64;
uiTOP := TO_UINT( (32000000/ 64/ _uidiHz)); // interpolate between 10 and 100Hz
100..999 : ePrescale := ePrescaler.ScaleFactor8;
uiTOP := TO_UINT( (32000000/ 8/ _uidiHz));// interpolate between 100 and 1000Hz
1000..100000 : ePrescale := ePrescaler.ScaleFactor1;
uiTOP := TO_UINT( (32000000/ 1/ _uidiHz));// interpolate between 1000 and 100000Hz
END_CASE
/// Now set prescaler
CASE ePrescale OF
/// 00 0 : prescaler = 1
ePrescaler.ScaleFactor1 : fPWM.0 := FALSE;
fPWM.1 := FALSE;
/// 01 1 : prescaler = 8
ePrescaler.ScaleFactor8 : fPWM.0 := TRUE;
fPWM.1 := FALSE;
/// 10 2 : prescaler = 64
ePrescaler.ScaleFactor64 : fPWM.0 := FALSE;
fPWM.1 := TRUE;
/// 11 3 : prescaler = 512
ePrescaler.ScaleFactor512 : fPWM.0 := TRUE;
fPWM.1 := TRUE;
END_CASE
// 8.0 2.0 PWM1 frequency
THIS^._abyIntTxBuf[8] := WORD_TO_BYTE(fPWM) AND 16#FC; // bitmask to protect prescaler
THIS^._abyIntTxBuf[9] := WORD_TO_BYTE(SHR(fPWM,8));
METHOD setDutyCycleDOut3: eMonarcoComStatus
VAR_INPUT
rDutyCycle: REAL;
END_VAR
VAR
wDC: WORD;
END_VAR
wDC := getDutyCycle( rDutyCycle := rDutyCycle );
// 12.0 2.0 PWM1 Dutycycle ch C
THIS^._abyIntTxBuf[14] := WORD_TO_BYTE(wDC); // bitmask to protect prescaler
THIS^._abyIntTxBuf[15] := WORD_TO_BYTE(SHR(wDC,8));
METHOD setDutyCycleDOut1: eMonarcoComStatus
VAR_INPUT
rDutyCycle: REAL;
END_VAR
VAR
wDC: WORD;
END_VAR
wDC := getDutyCycle( rDutyCycle := rDutyCycle );
// 10.0 2.0 PWM1 Dutycycle ch A
THIS^._abyIntTxBuf[10] := WORD_TO_BYTE(wDC); // bitmask to protect prescaler
THIS^._abyIntTxBuf[11] := WORD_TO_BYTE(SHR(wDC,8));
METHOD setAOutWord: eMonarcoComStatus
VAR_INPUT
wAOut1: WORD;
wAOut2: WORD;
END_VAR
VAR
v1: WORD;
v2: WORD;
END_VAR
// limit the value's
v1 := LIMIT(0, wAOut1, Paramlist.MONARCO_ADC_RANGE_MAX );
v2 := LIMIT(0, wAOut2, Paramlist.MONARCO_ADC_RANGE_MAX );
THIS^._abyIntTxBuf[20] := WORD_TO_BYTE(v1);
THIS^._abyIntTxBuf[21] := WORD_TO_BYTE(SHR(v1,8));
THIS^._abyIntTxBuf[22] := WORD_TO_BYTE(v2);
THIS^._abyIntTxBuf[23] := WORD_TO_BYTE(SHR(v2,8));
METHOD setAOut: eMonarcoComStatus
VAR_INPUT
stAOut: stAOut;
END_VAR
VAR
v1: WORD;
v2: WORD;
END_VAR
// limit the value's
v1 := LIMIT(0, stAOut.wAOut1, Paramlist.MONARCO_ADC_RANGE_MAX );
v2 := LIMIT(0, stAOut.wAOut2, Paramlist.MONARCO_ADC_RANGE_MAX );
THIS^._abyIntTxBuf[20] := WORD_TO_BYTE(v1);
THIS^._abyIntTxBuf[21] := WORD_TO_BYTE(SHR(v1,8));
THIS^._abyIntTxBuf[22] := WORD_TO_BYTE(v2);
THIS^._abyIntTxBuf[23] := WORD_TO_BYTE(SHR(v2,8));
METHOD setPWM2freq: eMonarcoComStatus
VAR_INPUT
udiHz: UDINT;
END_VAR
VAR
_uidiHz: UDINT;
ePrescale: ePrescaler;
uiRangeLow: UINT;
uiRangeHigh: UINT;
uiTOP: UINT;
fPWM: WORD;
END_VAR
/// clip the input Hz on lower and upper bound;
_uidiHz := LIMIT( 1, udiHz, 100000);
//// Determine prescaler and TOP according to table
CASE _uidiHz OF
1..9 : ePrescale := ePrescaler.ScaleFactor512;
uiTOP := TO_UINT( (32000000/ 512/ _uidiHz));// interpolate between 1 and 9Hz
10..99 : ePrescale := ePrescaler.ScaleFactor64;
uiTOP := TO_UINT( (32000000/ 64/ _uidiHz)); // interpolate between 10 and 100Hz
100..999 : ePrescale := ePrescaler.ScaleFactor8;
uiTOP := TO_UINT( (32000000/ 8/ _uidiHz));// interpolate between 100 and 1000Hz
1000..100000 : ePrescale := ePrescaler.ScaleFactor1;
uiTOP := TO_UINT( (32000000/ 1/ _uidiHz));// interpolate between 1000 and 100000Hz
END_CASE
/// Now set prescaler
/// bit 15 .. 2 : TOP / 4
CASE ePrescale OF
/// 00 0 : prescaler = 1
ePrescaler.ScaleFactor1 : fPWM.0 := FALSE;
fPWM.1 := FALSE;
/// 01 1 : prescaler = 8
ePrescaler.ScaleFactor8 : fPWM.0 := TRUE;
fPWM.1 := FALSE;
/// 10 2 : prescaler = 64
ePrescaler.ScaleFactor64 : fPWM.0 := FALSE;
fPWM.1 := TRUE;
/// 11 3 : prescaler = 512
ePrescaler.ScaleFactor512 : fPWM.0 := TRUE;
fPWM.1 := TRUE;
END_CASE
// 8.0 2.0 PWM1 frequency
THIS^._abyIntTxBuf[16] := WORD_TO_BYTE(fPWM);
THIS^._abyIntTxBuf[17] := WORD_TO_BYTE(SHR(fPWM,8));
METHOD getServiceResponse: eMonarcoComStatus
VAR_OUTPUT
Response: stServiceResponse;
END_VAR
VAR
rsp: stServiceResponse;
END_VAR
//send/receive
getServiceResponse := THIS^.dataTransfer();
rsp.wServiceValue := MEM.PackBytesToWord(_abyIntRxBuf[1],_abyIntRxBuf[0]);
rsp.wServiceAddress := MEM.PackBytesToWord(_abyIntRxBuf[3],_abyIntRxBuf[2]);
CASE rsp.wServiceValue OF
/// Set the error bit
Paramlist.MONARCO_SERVICE_STATUS_OK : Response.xError := FALSE;
Paramlist.MONARCO_SERVICE_ERROR_UNKNOWN_REG : Response.xError := TRUE;
Paramlist.MONARCO_SERVICE_ERROR_CRC : Response.xError := TRUE;
END_CASE
/// just give the response back
Response.wServiceValue := MEM.PackBytesToWord(_abyIntRxBuf[1],_abyIntRxBuf[0]);
Response.wServiceAddress := MEM.PackBytesToWord(_abyIntRxBuf[3],_abyIntRxBuf[2]);
METHOD setDOut:
VAR_INPUT
stDOut: stDOut;
END_VAR
THIS^._abyIntTxBuf[7].0 := stDOut.xDOut1;
THIS^._abyIntTxBuf[7].1 := stDOut.xDOut2;
THIS^._abyIntTxBuf[7].2 := stDOut.xDOut3;
THIS^._abyIntTxBuf[7].3 := stDOut.xDOut4;
METHOD setDOutBool:
VAR_INPUT
xDOut0: BOOL;
xDOut1: BOOL;
xDOut2: BOOL;
xDOut3: BOOL;
END_VAR
THIS^._abyIntTxBuf[7].0 := xDOut0;
THIS^._abyIntTxBuf[7].1 := xDOut1;
THIS^._abyIntTxBuf[7].2 := xDOut2;
THIS^._abyIntTxBuf[7].3 := xDOut3;
METHOD setDOutByte:
VAR_INPUT
byDOut: BYTE;
END_VAR
THIS^._abyIntTxBuf[7].0 := byDOut.0;
THIS^._abyIntTxBuf[7].1 := byDOut.1;
THIS^._abyIntTxBuf[7].2 := byDOut.2;
THIS^._abyIntTxBuf[7].3 := byDOut.3;
METHOD getDInByte: eMonarcoComStatus
VAR_OUTPUT
byDIn: BYTE;
END_VAR
byDIn.0 := THIS^._abyIntRxBuf[7].0;
byDIn.1 := THIS^._abyIntRxBuf[7].1;
byDIn.2 := THIS^._abyIntRxBuf[7].2;
byDIn.3 := THIS^._abyIntRxBuf[7].3;
METHOD getDInBool: eMonarcoComStatus
VAR_OUTPUT
xDIn0: BOOL;
xDIn1: BOOL;
xDIn2: BOOL;
xDIn3: BOOL;
END_VAR
xDIn0 := THIS^._abyIntRxBuf[7].0;
xDIn1 := THIS^._abyIntRxBuf[7].1;
xDIn2 := THIS^._abyIntRxBuf[7].2;
xDIn3 := THIS^._abyIntRxBuf[7].3;
METHOD getDIn: eMonarcoComStatus
VAR_OUTPUT
stDIn: stDIn;
END_VAR
stDIn.xDIn1 := THIS^._abyIntRxBuf[7].0;
stDIn.xDIn2 := THIS^._abyIntRxBuf[7].1;
stDIn.xDIn3 := THIS^._abyIntRxBuf[7].2;
stDIn.xDIn4 := THIS^._abyIntRxBuf[7].3;
METHOD getAInWord: eMonarcoComStatus
VAR_OUTPUT
wAIn1: WORD;
wAIn2: WORD;
END_VAR
wAIn1 := MEM.PackBytesToWord(THIS^._abyIntRxBuf[21],THIS^._abyIntRxBuf[20]);
wAIn2 := MEM.PackBytesToWord(THIS^._abyIntRxBuf[23],THIS^._abyIntRxBuf[22]);
METHOD ServiceRequest: eMonarcoComStatus
VAR_INPUT
wValue: WORD;
eCommand: eServiceCommand;
xWrite: BOOL;
END_VAR
VAR
stRequest: stServiceRequest;
END_VAR
stRequest.wServiceValue := wValue;
stRequest.wServiceAddress := Paramlist.SDC_ADDRESS_MASK AND TO_WORD(eCommand);
stRequest.wServiceAddress.12 := xWrite;
// Service Data Request
THIS^._abyIntTxBuf[0] := WORD_TO_BYTE(stRequest.wServiceValue); // ServiceValueHi;
THIS^._abyIntTxBuf[1] := WORD_TO_BYTE(SHR(stRequest.wServiceValue,8)); // ServiceValueLo;
THIS^._abyIntTxBuf[2] := WORD_TO_BYTE(stRequest.wServiceAddress);//ServiceRegisterHi;
THIS^._abyIntTxBuf[3] := WORD_TO_BYTE(SHR(stRequest.wServiceAddress,8));//ServiceRegisterLo;
//send/receive
ServiceRequest := THIS^.dataTransfer();
METHOD getAIn: eMonarcoComStatus
VAR_OUTPUT
stAIn: stAIn;
END_VAR
stAIn.wAIn1 := MEM.PackBytesToWord(THIS^._abyIntRxBuf[21],THIS^._abyIntRxBuf[20]);
stAIn.wAIn2 := MEM.PackBytesToWord(THIS^._abyIntRxBuf[23],THIS^._abyIntRxBuf[22]);
METHOD SetUserLED: eMonarcoComStatus
VAR_INPUT
byLeds: BYTE;
END_VAR
// 10.0 2.0 PWM1 Dutycycle ch A
THIS^._abyIntTxBuf[5] := byLeds; // set userled mask
THIS^._abyIntTxBuf[6] := byLeds; // set userled
METHOD AfterReadInputs: INT
///********************************
/// Continous intputs
///********************************
SUPER^.AfterReadInputs();
IF _iState = 10 THEN
// SPI reads/writes outputs in a single read/write action
THIS^.getDInByte(byDin => byDin);
THIS^.getAInWord(wAIn1 => wAIn1, wAIn2 => wAIn2);
THIS^.setDoutByte(byDout := byDOut);
THIS^.setAOutWord(wAout1 := wAOut1, wAOut2 := wAOut2);
_BeforeWriteOutputs := _BeforeWriteOutputs +1;
eComStatus := THIS^.dataTransfer();
END_IF
METHOD BeforeWriteOutputs: INT
///********************************
/// Continous Outputs
///********************************
SUPER^.BeforeWriteOutputs();
IF _iState = 10 THEN
_BeforeWriteOutputs := _BeforeWriteOutputs +1;
END_IF
METHOD Initialize: UDINT
VAR_INPUT
wModuleType: UINT;
dwInstance: UDINT;
pConnector: pointer;
END_VAR
VAR
pParam1: pointer;
pParam10: pointer;
udiResult: UDINT;
END_VAR
SUPER^.Initialize(wModuleType, dwInstance, pConnector);
pParam1 := ConfigGetParameter(_pConnector, 1);
IF pParam1 <> 0 THEN
THIS^.Watchdog := IoStandard.ConfigGetParameterValueByte(pParam1, ADR(udiResult));
END_IF
pParam10 := ConfigGetParameter(_pConnector, 10);
IF pParam10 <> 0 THEN
THIS^.ControlByte8 := IoStandard.ConfigGetParameterValueByte(pParam10, ADR(udiResult));
END_IF
VAR_GLOBAL
MONARCO_STRUCT_SIZE: UINT;
MONARCO_SERVICE_STATUS_OK: WORD;
MONARCO_SERVICE_ERROR_UNKNOWN_REG: WORD;
MONARCO_SERVICE_ERROR_CRC: WORD;
SDC_ADDRESS_MASK: WORD;
MONARCO_ADC_RANGE_MAX: WORD;
END_VAR