<?xml version="1.0" encoding="utf-8"?>enumenum---
This function block is the base class for SPI devices controlled via the SPI device /dev/spidev0.0.
It is meant to be extended by other function blocks that overload the body and the following methods/properties and replace it with their specific implementation,
always including a call of the base implementation with super^.<MethodName>() :
- body (general handling, start-up)
- AfterReadInputs (reading input data)
- BeforeWriteOutputs (writing output data)
- Initialize [optional] (used to read parameters from the configuration)
- Operational [optional] (used to signal the status of the device)
The body of this FB is called by the methods AfterReadInputs and BeforeWriteOutputs, where _xAfterReadInputs indicates the caller.
Use _iState to control your statemachine. A value of 10 by default indicates that the drive is operational.
Do not forget to call the base implementation with super^(), where the diagnosis indicators are set according to the Operational property.
FUNCTION_BLOCK GPIO
VAR_INPUT
aeType: ARRAY [..] OF ;
axOutputs: ARRAY [..] OF ;
udiPWMFrequency: UDINT;
uiPWMDutyCycle: UINT;
END_VAR
VAR_OUTPUT
dwInputs: DWORD;
axInputs: ARRAY [..] OF ;
END_VAR
VAR
_pConnector: pointer;
_udiInstance: UDINT;
_uiModuleType: UINT;
_aeOldType: ARRAY [..] OF ;
_axOldOutputs: ARRAY [..] OF ;
_udiOldPWMFrequency: UDINT;
_uiOldPWMDutyCycle: UINT;
_hShmGPIOBASE: SysTypes.RTS_IEC_HANDLE;
_iState: INT;
_iOldState: INT;
_eProcessorType: ProcessorType;
_xAfterReadInputs: BOOL;
END_VAR
VAR
BCM2708_PERI_BASE: DWORD;
BCM2709_PERI_BASE: DWORD;
GPIO_PWMCTL: DWORD;
GPIO_PWMSTA: DWORD;
GPIO_PWMDMAC: DWORD;
GPIO_PWMRNG1: DWORD;
GPIO_PWMDAT1: DWORD;
GPIO_PWMFIF1: DWORD;
GPIO_PWMRNG2: DWORD;
GPIO_PWMDAT2: DWORD;
GPIO_CM_PWMCTL: DWORD;
GPIO_CM_PWMDIV: DWORD;
PAGE_SIZE: DWORD;
BLOCK_SIZE: DWORD;
END_VAR
VAR
PERI_BASE: DWORD;
GPIO_PADS: DWORD;
GPIO_BASE: DWORD;
GPIO_TIMER: DWORD;
GPIO_PWMBASE: DWORD;
GPIO_CLKBASE: DWORD;
END_VAR
IF _iState <> _iOldState THEN
IF Operational THEN
IoMgrConfigResetDiagnosis(_pConnector, ConnectorFlags.CF_CONNECTOR_ERROR);
IoMgrConfigSetDiagnosis(_pConnector, ConnectorFlags.CF_DRIVER_AVAILABLE OR ConnectorFlags.CF_CONNECTOR_FOUND OR ConnectorFlags.CF_CONNECTOR_CONFIGURED OR ConnectorFlags.CF_CONNECTOR_ACTIVE);
ELSE
IoMgrConfigResetDiagnosis(_pConnector, ConnectorFlags.CF_CONNECTOR_ACTIVE);
IoMgrConfigSetDiagnosis(_pConnector, ConnectorFlags.CF_DRIVER_AVAILABLE OR ConnectorFlags.CF_CONNECTOR_FOUND OR ConnectorFlags.CF_CONNECTOR_CONFIGURED OR ConnectorFlags.CF_CONNECTOR_ERROR);
END_IF
_iOldState := _iState;
END_IF
IF _iState = 0 THEN
init();
(*ELSIF _iState >0 AND _iState < 10 THEN
ConfigurePWM();*)
END_IF
//SysShm.SysSharedMemoryRead(_hShmGPIOPWM, 16#4, ADR(udiTestSTatus), 4, ADR(result));
METHOD AfterReadInputs: INT
_xAfterReadInputs := TRUE;
THIS^();
_xAfterReadInputs := FALSE;
IF _iState = 10 THEN
GetInputs();
END_IF
METHOD BeforeWriteOutputs: INT
IF _iState = 10 THEN
SetType();
SetOutputs();
END_IF
THIS^();
METHOD Initialize: UDINT
VAR_INPUT
wModuleType: UINT;
dwInstance: UDINT;
pConnector: pointer;
END_VAR
VAR
pParam: pointer;
udiResult: UDINT;
END_VAR
_uiModuleType := wModuleType;
_udiInstance := dwInstance;
_pConnector := pConnector;
_eProcessorType := DetermineProcessorType();
DetermineConstants();
init();
METHOD ConfigurePWM: BOOL
VAR
udi: UDINT;
Result: UDINT;
iCounter: INT;
END_VAR
CASE _iState OF
1:
udi := 0;
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMCTL, ADR(udi), 4, ADR(result));// Turn off PWM.
IF Result = Errors.ERR_OK THEN
_iState := _iState + 1;
ELSE
_iState := 1000;
END_IF
2:
SysShm.SysSharedMemoryRead(_hShmGPIOCLK, GPIO_CM_PWMCTL, ADR(udi), 4, ADR(result));
IF Result <> Errors.ERR_OK THEN
_iState := 1000;
RETURN;
END_IF
udi.4 := FALSE;
udi := udi OR 16#5A00_0000; // Turn off enable flag.
SysShm.SysSharedMemoryWrite(_hShmGPIOCLK, GPIO_CM_PWMCTL, ADR(udi), 4, ADR(result));
IF Result = Errors.ERR_OK THEN
_iState := _iState + 1;
ELSE
_iState := 1000;
END_IF
3:
SysShm.SysSharedMemoryRead(_hShmGPIOCLK, GPIO_CM_PWMCTL, ADR(udi), 4, ADR(result));
IF Result = Errors.ERR_OK THEN
IF NOT udi.7 THEN
_iState := _iState + 1;
END_IF
ELSE
_iState := 1000;
END_IF
4:
udi := 16#5A000000 OR SHL(DWORD#5, 12); // Configure divider.
SysShm.SysSharedMemoryWrite(_hShmGPIOCLK, GPIO_CM_PWMDIV, ADR(udi), 4, ADR(result));
IF Result = Errors.ERR_OK THEN
_iState := _iState + 1;
ELSE
_iState := 1000;
END_IF
5:
udi := 16#5A00_0206; // Source=PLLD (500 MHz), 1-stage MASH.
SysShm.SysSharedMemoryWrite(_hShmGPIOCLK, GPIO_CM_PWMCTL, ADR(udi), 4, ADR(result));
IF Result = Errors.ERR_OK THEN
_iState := _iState + 1;
ELSE
_iState := 1000;
END_IF
6:
udi := 16#5A00_0216; // Enable clock.
SysShm.SysSharedMemoryWrite(_hShmGPIOCLK, GPIO_CM_PWMCTL, ADR(udi), 4, ADR(result));
IF Result = Errors.ERR_OK THEN
_iState := _iState + 1;
ELSE
_iState := 1000;
END_IF
7:
// Wait for busy flag to turn on.
SysShm.SysSharedMemoryRead(_hShmGPIOCLK, GPIO_CM_PWMCTL, ADR(udi), 4, ADR(result));
IF Result = Errors.ERR_OK THEN
IF udi.7 THEN
_iState := _iState + 1;
END_IF
ELSE
_iState := 1000;
END_IF
8:
udi := 100;
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMRNG1, ADR(udi), 4, ADR(result));
IF Result <> Errors.ERR_OK THEN
_iState := 1000;
RETURN;
END_IF
udi := 20;
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMDAT1, ADR(udi), 4, ADR(result));
IF Result <> Errors.ERR_OK THEN
_iState := 1000;
RETURN;
END_IF
udi := 16#81;
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMCTL, ADR(udi), 4, ADR(result)); // Channel 1 M/S mode, no FIFO, PWM mode, enabled.
IF Result <> Errors.ERR_OK THEN
_iState := 1000;
RETURN;
END_IF
_iState := _iState + 1;
9:
aeType[18] := ALT5;
SetType();
_iState := 10;
END_CASE
METHOD DetermineConstants:
IF _eProcessorType = ProcessorType.BCM2708 THEN
// Raspberry Pi Model B+
PERI_BASE := BCM2708_PERI_BASE;
ELSE
// Raspberry Pi 2 Model B
// Raspberry Pi 3 Model B and all others
PERI_BASE := BCM2709_PERI_BASE;
END_IF
GPIO_PADS := (PERI_BASE + 16#00100000);
GPIO_BASE := (PERI_BASE + 16#00200000);
GPIO_TIMER := (PERI_BASE + 16#0000B000);
GPIO_PWMBASE := (PERI_BASE + 16#0020C000);
GPIO_CLKBASE := (PERI_BASE + 16#00101000);
METHOD DetermineProcessorType: ProcessorType
VAR
Result: RTS_IEC_RESULT;
Handle: RTS_IEC_HANDLE;
fr: FileReader;
str: string;
i: INT;
iLen: INT;
strType: string;
x: BOOL;
END_VAR
Handle := SysFileOpen(szFile:='/proc/cpuinfo' , am:=ACCESS_MODE.AM_READ , pResult:= ADR(Result));
IF Result = CmpErrors.Errors.ERR_OK THEN
fr(hFile:=Handle );
WHILE fr.GetLine(ADR(str), SIZEOF(str)) DO
iLen := Len(Str);
IF iLen > 10 THEN
IF LEFT(str, 10) = 'model name' THEN
i := find(str, ':');
strType := RIGHT(str, iLen-i-1);
strType := LEFT(strType, 5);
EXIT;
END_IF
END_IF
END_WHILE
END_IF
SysFileClose(Handle);
IF strType='ARMv6' THEN
// Raspberry Pi 1 and Model B+
DetermineProcessorType := ProcessorType.BCM2708;
ELSE
// Raspberry Pi 2 Model B
// Raspberry Pi 3 Model B and all others
DetermineProcessorType := ProcessorType.BCM2709;
END_IF
METHOD Fb_exit: BOOL
VAR_INPUT
bInCopyCode: BOOL;
END_VAR
IF _hShmGPIOBASE <> RTS_INVALID_HANDLE THEN
SysShm.SysSharedMemoryClose(_hShmGPIOBASE);
_hShmGPIOBASE := RTS_INVALID_HANDLE;
END_IF
(*
IF _hShmGPIOPWM <> RTS_INVALID_HANDLE THEN
SysShm.SysSharedMemoryClose(_hShmGPIOPWM);
_hShmGPIOPWM := RTS_INVALID_HANDLE;
END_IF
IF _hShmGPIOCLK <> RTS_INVALID_HANDLE THEN
SysShm.SysSharedMemoryClose(_hShmGPIOCLK);
_hShmGPIOCLK := RTS_INVALID_HANDLE;
END_IF*)
METHOD GetInputs:
VAR
Result: UDINT;
i: INT;
END_VAR
SysShm.SysSharedMemoryRead(_hShmGPIOBase, 16#34, ADR(dwInputs), 4, ADR(result));
FOR i:=0 TO 31 DO
axInputs[i] := (dwInputs AND SHL(UDINT#1, i)) > 0;
END_FOR
METHOD GetType:
VAR
Result: UDINT;
ul: UDINT;
i: INT;
j: UDINT;
END_VAR
j := 0;
FOR i:=0 TO 31 DO
IF (i MOD 10) = 0 THEN
SysSharedMemoryRead(_hShmGPIOBase, j*4, ADR(ul), 4, ADR(result));
j := j + 1;
END_IF
aeType[i] := UDINT_TO_USINT(SHR(ul, INT_TO_UDINT(i MOD 10) * 3) AND 2#111);
END_FOR
_aeOldType := aeType;
METHOD SetOutputs:
VAR
Result: UDINT;
ulOn: UDINT;
ulOff: UDINT;
i: INT;
END_VAR
FOR i:=0 TO 31 DO
IF _axOldOutputs[i] <> axOutputs[i] AND aeType[i] = GPIOType.O THEN
IF axOutputs[i] THEN
ulOn := ulOn OR SHL(UDINT#1, i);
ELSE
ulOff := ulOff OR SHL(UDINT#1, i);
END_IF
END_IF
END_FOR
IF ulOn > 0 THEN
SysShm.SysSharedMemoryWrite(_hShmGPIOBase, 16#1C, ADR(ulOn), 4, ADR(result));
END_IF
IF ulOff > 0 THEN
SysShm.SysSharedMemoryWrite(_hShmGPIOBase, 16#28, ADR(ulOff), 4, ADR(result));
END_IF
_axOldOutputs := axOutputs;
//PWM
(*
IF udiPWMFrequency <> _udiOldPWMFrequency THEN
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMRNG1, ADR(udiPWMFrequency), 4, ADR(result));
_udiOldPWMFrequency := udiPWMFrequency;
END_IF
IF uiPWMDutyCycle <> _uiOldPWMDutyCycle THEN
ulOn := uiPWMDutyCycle;
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMDAT1, ADR(ulOn), 4, ADR(result));
_uiOldPWMDutyCycle := uiPWMDutyCycle;
ulOn := 16#81;
SysShm.SysSharedMemoryWrite(_hShmGPIOPWM, GPIO_PWMCTL, ADR(ulOn), 4, ADR(result)); // Channel 1 M/S mode, no FIFO, PWM mode, enabled.
END_IF*)
METHOD SetType:
VAR
Result: UDINT;
ul: UDINT;
ulOrig: UDINT;
i: INT;
j: UDINT;
udiOffset: UDINT;
END_VAR
j := 0;
FOR i:=0 TO 31 DO
IF (i MOD 10) = 0 THEN
SysSharedMemoryRead(_hShmGPIOBase, j*4, ADR(ul), 4, ADR(result));
ulOrig := ul;
END_IF
IF _aeOldType[i] <> aeType[i] THEN
IF aeType[i] = GPIOType.I OR aeType[i] = GPIOType.O THEN
udiOffset := INT_TO_UDINT(i MOD 10) * 3;
CASE aeType[i] OF
GPIOType.I:
ul := ul AND NOT SHL(7, udiOffset);
GPIOType.O:
ul := ul AND NOT SHL(7, udiOffset);
ul := ul OR SHL(1, udiOffset);
_axOldOutputs[i] := axInputs[i];
END_CASE
END_IF
END_IF
IF ((i MOD 10) = 9 OR i=31) THEN
IF ul <> ulOrig THEN
SysSharedMemoryWrite(_hShmGPIOBase, j*4, ADR(ul), 4, ADR(result));
END_IF
j := j + 1;
END_IF
END_FOR
_aeOldType := aeType;
METHOD init: BOOL
VAR
Result1: UDINT;
Result2: UDINT;
Result3: UDINT;
ul: UDINT;
i: INT;
strEmpty: string;
END_VAR
IF _hShmGPIOBASE = RTS_INVALID_HANDLE THEN
ul := BLOCK_SIZE;
IF _hShmGPIOBASE = RTS_INVALID_HANDLE THEN
_hShmGPIOBASE := SysSharedMemoryCreate(pszName:=strEmpty , ulPhysicalAddress:=GPIO_BASE , pulSize:= ADR(ul), pResult:=ADR(Result1) );
END_IF
(* IF _hShmGPIOPWM = RTS_INVALID_HANDLE THEN
_hShmGPIOPWM := SysSharedMemoryCreate(pszName:=strEmpty , ulPhysicalAddress:=GPIO_PWMBASE , pulSize:= ADR(ul), pResult:=ADR(Result2) );
END_IF
IF _hShmGPIOCLK = RTS_INVALID_HANDLE THEN
_hShmGPIOCLK := SysSharedMemoryCreate(pszName:=strEmpty , ulPhysicalAddress:=GPIO_CLKBASE , pulSize:= ADR(ul), pResult:=ADR(Result3) );
END_IF
*)
IF Result1 = 0 AND Result2 = 0 AND Result3 = 0 THEN
init := TRUE;
GetType();
GetInputs();
FOR i:=0 TO 31 DO
IF aeType[i] = GPIOType.O THEN
axOutputs[i] := axInputs[i];
END_IF
END_FOR
_axOldOutputs := axOutputs;
SetOutputs();
_iState := 10;
ELSE
_iState := 1000;
END_IF
END_IF
FUNCTION_BLOCK IoDrvGPIO EXTENDS IoDrvBase
VAR
CLASSID_CCmpIoDrvTemplate: DWORD;
END_VAR
VAR
_IIoDrv: ICmpIoDrv;
_IIoDrvParameter: ICmpIoDrvParameter;
_GPIO: GPIO;
_dwInUse: DWORD;
_xBackGroundDiagStarted: BOOL;
_bDeactivated: BOOL;
END_VAR
METHOD FB_Exit: BOOL
VAR_INPUT
bInCopyCode: BOOL;
END_VAR
FB_Exit_Count := FB_Exit_Count + 1;
FB_Exit := TRUE;
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
END_VAR
VAR
Result: UDINT;
END_VAR
FB_Init_Count := FB_Init_Count + 1;
m_Info.szDriverName := 'IoDrvGPIO';
m_Info.szVendorName := '3S - Smart Software Solutions';
m_Info.szDeviceName := 'Raspberry GPIOs';
m_Info.wModuleType := 8000;
_IIoDrv := THIS^;
_IIoDrvParameter := THIS^;
m_IBaseItf := THIS^;
m_hInterface := IoMgrRegisterInstance2(CLASSID_CCmpIoDrvTemplate, m_IBaseItf, ADR(Result));
FB_Init := TRUE;
METHOD FB_Reinit: BOOL
FB_Reinit_Count := FB_Reinit_Count + 1;
FB_Reinit := TRUE;
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;
_GPIO.Initialize(wModuleType, dwInstance, pConnector);
Initialize := Errors.ERR_OK;
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 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 IoDrvIdentify: UDINT
VAR_INPUT
pConnector: pointer;
END_VAR
IoDrvIdentify_Count := IoDrvIdentify_Count + 1;
IoDrvIdentify := Errors.ERR_NOTIMPLEMENTED;
METHOD IoDrvReadInputs: UDINT
VAR_INPUT
pConnectorMapList: pointer;
nCount: DINT;
END_VAR
VAR
i: DINT;
j: DINT;
wSize: WORD;
pbyIecAddress: pointer;
bySrcValue: BYTE;
bySrcMask: BYTE;
wSrcIndex: WORD;
wDestIndex: WORD;
pdw: pointer;
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
pbyIecAddress := pConnectorMapList[i].pChannelMapList[j].pbyIecAddress;
wDestIndex := pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset / 8;
IF (pConnectorMapList[i].pChannelMapList[j].wSize = 1) THEN
IF _GPIO.axInputs[pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset] THEN
(*IF (PiFace.byIn 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 = 32 THEN
pdw := pbyIecAddress + wDestIndex;
pdw^ := _GPIO.dwInputs;
END_IF
END_FOR
END_FOR
IoDrvReadInputs := 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 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
_GPIO.AfterReadInputs();
_GPIO.BeforeWriteOutputs();
END_IF
IoDrvStartBusCycle := Errors.ERR_OK;
METHOD IoDrvUpdateConfiguration: UDINT
VAR_INPUT
pConnectorList: pointer;
nCount: DINT;
END_VAR
VAR
pParameter: pointer;
pChild: pointer;
pstConnectorVendorName: pointer;
pstConnectorDeviceName: pointer;
Result: RTS_IEC_RESULT;
i: INT;
bySetting: BYTE;
END_VAR
IoDrvUpdateConfiguration_Count := IoDrvUpdateConfiguration_Count + 1;
IoDrvUpdateConfiguration := Errors.ERR_OK;
IF (pConnectorList = 0) THEN
// Reset application
// TODO: Free ressources
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}
_dwInUse := 0;
FOR i:=0 TO 31 DO
pParameter := IoMgrConfigGetParameter(m_pConnector, INT_TO_DWORD(i));
IF (pParameter <> 0) THEN
bySetting := IoMgrConfigGetParameterValueByte(pParameter, ADR(Result));
IF bySetting >= 0 AND bySetting <= 7 THEN
_GPIO.aeType[i] := bySetting;
_dwInUse := _dwInUse OR SHL(DWORD#1, i);
END_IF
END_IF
END_FOR
//Setup I/O area
pParameter := IoMgrConfigGetParameter(m_pConnector, 1000); (* inputs *)
IF (pParameter <> 0) THEN
pParameter^.dwDriverSpecific := 0; (* Device offset 0 *)
END_IF
pParameter := IoMgrConfigGetParameter(m_pConnector, 2000); (* outputs *)
IF (pParameter <> 0) THEN
pParameter^.dwDriverSpecific := 0; (* Device offset 0 *)
END_IF
pParameter := IoMgrConfigGetParameter(m_pConnector, 2100); (* outputs *)
IF (pParameter <> 0) THEN
pParameter^.dwDriverSpecific := 10; (* Device offset 0 *)
END_IF
pParameter := IoMgrConfigGetParameter(m_pConnector, 2101); (* outputs *)
IF (pParameter <> 0) THEN
pParameter^.dwDriverSpecific := 14; (* Device offset 0 *)
END_IF
(* no child devices used
//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 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 IoDrvWatchdogTrigger: UDINT
VAR_INPUT
pConnector: pointer;
END_VAR
IoDrvWatchdogTrigger_Count := IoDrvWatchdogTrigger_Count + 1;
IoDrvWatchdogTrigger := Errors.ERR_OK;
METHOD IoDrvWriteOutputs: UDINT
VAR_INPUT
pConnectorMapList: pointer;
nCount: DINT;
END_VAR
VAR
i: DINT;
j: DINT;
k: UINT;
wSize: WORD;
pbyIecAddress: pointer;
bySrcValue: BYTE;
wSrcIndex: WORD;
bySrcMask: BYTE;
wDestIndex: WORD;
pdw: pointer;
pw: 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;
CASE pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific OF
0: // digitals
IF pConnectorMapList[i].pChannelMapList[j].wSize = 1 THEN
bySrcValue := pbyIecAddress[wSrcIndex];
k := pConnectorMapList[i].pChannelMapList[j].wParameterBitOffset;
IF (_dwInUse AND SHL(DWORD#1, k)) > 0 THEN
_GPIO.axOutputs[k] := BYTE_TO_BOOL(pbyIecAddress[wSrcIndex] AND SHL(BYTE#1, pConnectorMapList[i].pChannelMapList[j].wIecAddressBitOffset MOD 8));
END_IF
ELSIF pConnectorMapList[i].pChannelMapList[j].wSize = 32 THEN
pdw := pbyIecAddress;
FOR k:=0 TO 32 DO
IF (_dwInUse AND SHL(DWORD#1, k)) > 0 THEN
_GPIO.axOutputs[k] := DWORD_TO_BOOL(pdw^ AND SHL(1, k));
END_IF
END_FOR
END_IF
10:
pdw := pbyIecAddress;
_GPIO.udiPWMFrequency := DWORD#100_000_000 / pdw^;
14:
pw := pbyIecAddress;
_GPIO.uiPWMDutyCycle := UDINT_TO_UINT(UINT_TO_UDINT(pw^) * _GPIO.udiPWMFrequency / UDINT#65536);
END_CASE
END_FOR
END_FOR
IoDrvWriteOutputs := Errors.ERR_OK;
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 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;