Скачиваний:
22
Добавлен:
11.10.2020
Размер:
18.65 Кб
Скачать
/*********************************************************************************/
/*This file contains all the functions, that make the IODrv.                     */
/*These functions are called from 3S-RTPLC as callbacks.                         */
/*********************************************************************************/

#include <ntddk.h>
#include "IOdrvInterface.h"
#include "IODrvFunctions.H"
#include "CardFunctions.h"
#include "RTIOdrv.h"

#define MAXIMUM_STRING_BUFFER 80

extern RtsApiInterface g_rtsapi;

/*globals */
char g_bValidIOdeviceFound = 0;

/***First do the initialization of the devices, and build complete information about them.**/

RTS_LAST_ERROR* s_pLastErr = NULL;
unsigned long IODrvInitIO(unsigned long ulPar)
{
    //TODO: retrieve all available information about my devices: number, interrupt-descriptions, IOranges ...
	
     s_pLastErr = IODrvGetLastError();
    
    return 1;
}

unsigned long IODrvExitIO(void)
{
    //TODO: free evtl. allocated memory in InitIO and all the things need to be done when the PLC exits.
    //Note that IODrvInitIO/ExitIO may be called many times without terminating the driver. 
    //So do the things that need to be done once within the driver-runtime in DriverEntry.

    //Important here: be aware that is fatal to call a function from g_rtsapi after this function has been called.
    //So it is a good idea to delete the pointers in g_rtsapi.
    memset((char*)&g_rtsapi,0,sizeof(g_rtsapi));

	return 1;
}

unsigned long IODrvGetId(void* pData)
{
	int iDev = 1; //this is the default to avoid IOinit-error, if this is 0.
	GetIDdata* pgidd = (GetIDdata*)pData;

//TODO: determine the number of devices this driver manages.

//	*(unsigned long*)pData = iDev; // The number of devices is important to the PLC!!
    pgidd->iNumDevices = iDev;
/*
The informations about interrupts are optional.
    pgidd->iNumInterruptRoutines = iDev; //Normally each device has his own interrupt.
    for(i = 0; i < iMaster; i++)
    {
        pgidd->apfIntRoutine[i] = GlobalIsr;
        pgidd->idIntDesc[i].bConnectNow = 0;
        pgidd->idIntDesc[i].pContext = NULL;
        pgidd->idIntDesc[i].pvIntVec = ptGlobalDrv->aDevInst[i].pvVirtualIrq;
        pgidd->idIntDesc[i].iIntVec = ptGlobalDrv->aDevInst[i].usBoardIrq;
    }
*/
    return 0xffff; //The ID may be usefull to the runtime in future. Return your specific ID.
}

unsigned long IODrvGetDeviceFlags(unsigned long ulDeviceNr)
{
//TODO: return the device-capability flags, specific for each device.
//for example:
//    return DRV_CAP_FLAG_WANTS_CONFIG | DRV_CAP_FLAG_IS_CANDEVICE;
    return 0;
}

void IODrvGetIORange(unsigned long* pulOffset, unsigned long* pulSize)
{
	int i = 0;
	unsigned long ulOffs = 0;
//TODO: insert a list of offset and size of the io-range of each device, for example to handle all your devices as 
//one block of IOs write (if your device-informations are stored in an array):
/*	
    while(a_dev[i].bDeviceAvailable && i < DRV_MAX_DEVICES )
	{
		pulSize[i] = a_Dev[i].ulSize;
		pulOffset[i] = ulOffs;
		ulOffs += a_dev[i].ulSize;
		i++;
	}
*/
}

char IODrvConfigureIONetStart(unsigned long ulDeviceNr)
{
    //TODO: call the appropriate IODev-function IODevConfigureIONetStart, which may be different for each device, who knows.
    return IODevConfigureIONetStart(ulDeviceNr);
    //return 0;
}

char IODrvConfigureIONetDone(unsigned long ulDeviceNr)
{
	//TODO: mark the device as configured (or do nothing, or send config-data now to the device or something like that.)
	return 1;
}

char IODrvConfigureModule(int iModule, void* pModConfData, unsigned long ulDeviceNr)
{
    //TODO: the structures are different for each supported kind of bus (see CAP_FLAGS)
    //so determine with the device-nr, what config-function has to be called.
	//Call the function that configures a PB-Slave.
/*
			return IODevConfigOnePBSlave((char)iModule, //here iModule is stationnumber as contained in PBSlave
										pModConfData, //points to a PBSlave-structure
										(char)ulDeviceNr );//identifies the card
*/
		//Call the function that configures a CAN-node.
/*
			return IODevConfigOneCanNode((char)iModule, //here iModule is NodeAddress
										pModConfData,//points to a CANnode-structure
										(char)ulDeviceNr );//identifies the card
*/
			return 0;
}

char IODrvConfigureDevice(void* pBusDesc, unsigned long ulDeviceNr)
{
    //TODO: the structures are different for each supported kind of bus (see CAP_FLAGS)
    //so determine with the device-nr, what config-function has to be called.
/* Example:
	switch(bustype)
		//Call the function that configures a PB-Master.
			return IODevSetPBCardMasterParams(pBusDesc,(char)ulDeviceNr);
		//Call the function that configures a CAN-Master.
			return IODevSetCANCardMasterParams(pBusDesc,(char)ulDeviceNr);
*/
	return 0;

}

char IODrvStartWriteOutputs(unsigned long ulTaskNr, unsigned long ulCycleTime, int iDevice)
{
    return 1;
}

char IODrvWriteOutput(unsigned long ulOffset, unsigned long ulSize, unsigned char* pucData, unsigned long ulTaskNr, int iDevice)
{
//TODO: call the specific function for that device.
	return IODevWriteOutput(ulOffset, ulSize, pucData, ulTaskNr, iDevice);
}

char IODrvDoneWriteOutputs(unsigned long ulTaskNr, unsigned long ulCycleTime, int iDevice)
{
//TODO: call the specific function for that device.
	return IODevDoneWriteOutputs(ulTaskNr, ulCycleTime, iDevice);
}

char IODrvStartReadInputs(unsigned long ulTaskNr, unsigned long ulCycleTime, int iDevice)
{
    return 1;
}

char IODrvReadInput(unsigned long ulOffset, unsigned long ulSize, unsigned char* pucData, unsigned long ulTaskNr, int iDevice)
{
//TODO: call the specific function for that device.
	return IODevReadInput(ulOffset, ulSize, pucData, ulTaskNr, iDevice);
}

char IODrvDoneReadInputs(unsigned long ulTaskNr, unsigned long ulCycleTime, int iDevice)
{
//TODO: call the specific function for that device.
	return IODevDoneReadInputs(ulTaskNr, ulCycleTime, iDevice);
}

char IODrvPLCStatusChanges(char cNewState)
{
//TODO: if the IODrv wants to prevent the PLC from changing the current state 
//(it is only possible for the driver to prevent the PLC changing from STOP to RUN, not the other way).
//by returning one or not registering this function, the driver is not involved into state-change.
    return 1;
}

void IODrvEnterNMIRoutine(void)
{ //TODO: this routine is called when the NMI-handler is entered. It is very hardware-dependent to quit the NMI,
    //so the hardware will produce the next NMI. Reactivate the NMI here for your HW.

}

void IODrvLeaveNMIRoutine(void)
{   //TODO: if there's something to do, before returning to 'normal' program-execution do it now!
}

int IODrvStartInterrupt(int iParam)
{
//TODO: if the driver wants to start a cyclic interrupt, the PLC-scheduler should use to schedule on.
//return the interrupt-vector of the cyclic interrupt. (Use IDT-indexes, not logical vectors!)
    return -1;
}

int IODrvStopInterrupt(int iParam)
{
    //TODO: stop generating a cyclic interrupt, the PLC will deinstall her handling-routine.
    //The system will crash, if the interrupt is produced any longer.
    //return the interrupt-vector of the cyclic interrupt. (Use IDT-indexes, not logical vectors!)

    return -1;
}

unsigned long IODrvRetainSave(unsigned short sSegment, unsigned char *pbyData, unsigned long ulSize, int iDevice)
{ //TODO: this routine is called whenever a task wants to save retain-data and the driver did tell the PLC (by CAP-flag)
//he will save retain-data.
    return (unsigned long)-1;
}

unsigned long IODrvRetainRestore(unsigned short sSegment, unsigned char *pbyData, unsigned long ulSize, int iDevice)
{ //TODO: this routine is called everytime the PLC loads a bootproject and the driver has set the flag CAN_SAVE_RETAIN
//read the retain-data from whereever you saved it and store it to pbyData, maximum ulSize bytes.
    //return 1; //restoring the retains was successfull.
    return (unsigned long)-1;
}

unsigned long IODrvCyclicCallback(__int64* pliCurTime)
{ //TODO: this routine is called by the scheduler itself, if the pointer to the function is specified 
    // in the functionpointerlist. The returnvalue specifies, in how many ms it is called next time.
    // BE CAREFULL !! This functions is called save from interrupts. Its duration is directly added to the 
    // scheduler's duration. So don't stay longer than max.100us in this function.

   return 500; //Get the next call in 500ms. 
}

static void _cdecl Dummy(void)
{
}
static ExtRef IOdrvExtRefTable[] =
{ //TODO: if you have own lib-function, to be called from IEC-tasks, insert here.(Then 'Dummy' can be removed.)
    //Remember: All functions added here may be called from IEC-tasks (CoDeSys-generated code, so they all MUST be declared as _cdecl !!!
    //(Otherwise unpredictable system crashes may occur, because of stack-faults.)
	{"Dummy", (void (*)())Dummy},

	{"", NULL}
};

void* IODrvGetExtRefTable(void)
{
    return IOdrvExtRefTable;
}

unsigned long IODrvProcessHook(unsigned long ulHook, unsigned long ulAdditionalInfo)
{
	char bCustomHandling = FALSE;

	switch (ulHook)
	{
		case PH_BEFORE_RESET:
		case PH_AFTER_RESET:
		{
			unsigned char byResetMode = (unsigned char)ulAdditionalInfo;
			return 1;
		}
		default:
			break;
	}	
	return 0;
}

unsigned long IODrvPreComputeService(unsigned char* pbyReceive, unsigned long ulRecvLen, unsigned char* pbySend)
{ //returns the number of bytes it writes to pbySend. 
    unsigned char byService;
    byService = pbyReceive[0];

    switch (byService)
    {
		default:
			break;
	}
	return 0;
}

unsigned long IODrvPostComputeService(unsigned char* pbyReceive, unsigned long ulRecvLen, unsigned char* pbySend, unsigned long ulSendLen)
{ //returns the number of bytes it writes to pbySend.
    unsigned char byService;
    byService = pbyReceive[0];

    switch (byService)
    {
		default:
			break;
	}
    return 0;
}

unsigned int IODrvSrvBrowserCmds(char* pszCommand, char* pszAnswer, unsigned int iSubCommand, unsigned int iBlockNr, char* pcActiveBrowserCommand)
{
	/* pszAnswer is the pointer to the buffer, where the answerstring is to be added. Terminate with zero!! */
	/* iSubCommand is the active command to be executed. */
	/* iBlockNr is incremented each time the function is called. The function is called as long as it adds PLC_SUB_FOLLOWINGS */

	/* The function will not be called again for this command if it adds PLC_SUB_LAST. */
	/* The first byte added to the answer MUST be PLC_SUB_LAST / FOLLOWINGS. */
	/* This must look like 
			if (iBlockNr > (something to decide wether the command reached its end) )
			{
				*pcActiveBrowserCommand=BROWSERCMD_NOCMD;	Clear the active browsercommand !!
				*(pszAnswer++)=(unsigned char)PLC_SUB_LAST;	Tell the communication-partner: All data is sent now!!
			}
			else
				*(pszAnswer++)=(unsigned char)PLC_SUB_FOLLOWINGS;	 */

	char* pszAnswerStart;
	char szKeyWord[21];
	unsigned int i, ii=0;
	short bIsCharacter=0;
	for(i=0;(i<strlen(pszCommand) && i<20);i++)
	{
		if (pszCommand[i]!=' ' && pszCommand[i]!='\t')
			bIsCharacter=1;
		if (bIsCharacter!=0 && (pszCommand[i]==' ' || pszCommand[i]=='\t'))
			break; /*first space after a non-space, e.g.first word was read.*/
		if (bIsCharacter!=0)
			szKeyWord[ii++]=pszCommand[i];
	}
	szKeyWord[ii]='\0';
	if(strcmp(szKeyWord,"testit")==0)
		*pcActiveBrowserCommand = BROWSERCMD_USERTEST;

	switch(*pcActiveBrowserCommand)
	{
		case BROWSERCMD_USERTEST:
			if(iBlockNr<10)
				*(pszAnswer++)=(unsigned char)PLC_SUB_FOLLOWINGS;	/*Tell the communication-partner: Not all data is sent !!*/
			else
			{
				*pcActiveBrowserCommand=BROWSERCMD_NOCMD;	/*Clear the active browsercommand !! */
				*(pszAnswer++)=(unsigned char)PLC_SUB_LAST;	/*Tell the communication-partner: All data is sent now!! */
			}
			*(pszAnswer++)=(unsigned char)0x00;
			/*increment block-nr and send new blocknr within answer*/
			iBlockNr++;
			*(pszAnswer++)=(char)(iBlockNr & 0xff);
			*(pszAnswer++)=(char)((iBlockNr>>8) & 0xff);
			pszAnswerStart = pszAnswer;
			*(pszAnswer++) = (char)(iBlockNr + 64);
			pszAnswer += strlen(strcpy(pszAnswer,"  That's the testanwer f. CstBrowserCmd."));
			*(pszAnswer++)='\0';
			break;
		default:
			return 0;
	}
	return strlen(pszAnswerStart);

}

unsigned int IODrvAddBrowserhelp(char* pszAnswer, unsigned short usCurNr)
{
	unsigned short ii;
	const char szHelp[]={"testit - get the testanswer from IODrvSrvBrowserCmds\r\nCustom help Nr.1\r\nCustom help Nr.2\r\nCustom help Nr.3"};

	for(ii=0;szHelp[ii] != '\0'; ii++)
		*(pszAnswer++)=szHelp[ii];
	*(pszAnswer++) = '\0';

	return strlen(szHelp);
}

ProjectInfo* IODrvGetProjectInfo(void)
{
    if(g_rtsapi.pfRtsGetProjectInfo != NULL)
        return (*g_rtsapi.pfRtsGetProjectInfo)();
    return NULL;
}



/*The functions called by BusDiagLib-functioncalls*/
/*
The driver must determine with the name, whether the call is destinated to himself.
If DRIVERNAME is NULL, always accept the call, the requested state may be the master/node first-level-stateinfo,
called from IOupdate of the PLC-task(s).
*/
void IODrvLibGetBusState(BUSDIAGLIB_GETBUSSTATEtyp* pinst)
{
    if(memcmp(pinst->DRIVERNAME,MY_IODRV_NAME,strlen(MY_IODRV_NAME)) != 0)
        return ;
}

void IODrvLibSetBusState(BUSDIAGLIB_SETBUSSTATEtyp* pinst)
{
    if(memcmp(pinst->DRIVERNAME,MY_IODRV_NAME,strlen(MY_IODRV_NAME)) != 0)
        return ;
}

void IODrvLibGetState(BUSDIAGLIB_GETSTATEtyp* pinst)
{
    if(memcmp(pinst->DRIVERNAME,MY_IODRV_NAME,strlen(MY_IODRV_NAME)) != 0)
        return ;
}

void IODrvLibSetState(BUSDIAGLIB_SETSTATEtyp* pinst)
{
    if(memcmp(pinst->DRIVERNAME,MY_IODRV_NAME,strlen(MY_IODRV_NAME)) != 0)
        return ;
}

/*The functions for task-handling-interface. They can also be called directly, but it's easier to encapsulate these calls.*/
int IODrvCreateTask(int iPriority, unsigned long ulCycleTime, int (*pfEntry)(void*), void* pArg, unsigned long ulFlags)
{
    if(g_rtsapi.pfRtsCreateTask != NULL)
        return (*g_rtsapi.pfRtsCreateTask)(iPriority, ulCycleTime, pfEntry, pArg, ulFlags);
    return -1;
}

int IODrvDeleteTask(int iPriority)
{
    if(g_rtsapi.pfRtsDeleteTask != NULL)
        return (*g_rtsapi.pfRtsDeleteTask)(iPriority);
    return -1;
}

int IODrvWaitForObject(int iWaitObjectNr, unsigned long ulMaxTime)
{
    if(g_rtsapi.pfRtsWaitForObject != NULL)
        return (*g_rtsapi.pfRtsWaitForObject)(iWaitObjectNr,ulMaxTime);
    return -1;
}

int IODrvSetObject(int iWaitObjectNr)
{
    if(g_rtsapi.pfRtsSetObject != NULL)
        return (*g_rtsapi.pfRtsSetObject)(iWaitObjectNr);
    return -1;
}

int IODrvSleep(unsigned long ulSleepTime)
{
    if(g_rtsapi.pfRtsSleep != NULL)
        return (*g_rtsapi.pfRtsSleep)(ulSleepTime);
    return -1;
}

int IODrvResume(int iPriority)
{
    if(g_rtsapi.pfRtsResume != NULL)
        return (*g_rtsapi.pfRtsResume)(iPriority);
    return -1;
}

int IODrvSuspend(int iPriority)
{
    if(g_rtsapi.pfRtsSuspend != NULL)
        return (*g_rtsapi.pfRtsSuspend)(iPriority);
    return -1;
}

/*The functions for asynchronuous fileaccess.*/
int IOdrvAsynchFileOpen(void** pHandle,unsigned long ulAttributes,char* pszName)
{
    if(g_rtsapi.pfAsynchFileOpen != NULL)
        return (*g_rtsapi.pfAsynchFileOpen)(pHandle,ulAttributes,pszName);
    return -1;
}

int IOdrvAsynchFileClose(void* Handle)
{
    if(g_rtsapi.pfAsynchFileClose != NULL)
        return (*g_rtsapi.pfAsynchFileClose)(Handle);
    return -1;
}

int IOdrvAsynchFileRead(void* Handle, char* pBuffer, unsigned long ulSize)
{
    if(g_rtsapi.pfAsynchFileRead != NULL)
        return (*g_rtsapi.pfAsynchFileRead)(Handle,pBuffer,ulSize);
    return -1;
}

int IOdrvAsynchFileWrite(void* Handle, char* pBuffer, unsigned long ulSize)
{
    if(g_rtsapi.pfAsynchFileWrite != NULL)
        return (*g_rtsapi.pfAsynchFileWrite)(Handle,pBuffer,ulSize);
    return -1;
}

int IOdrvSynchFileOpen(void** pHandle,unsigned long ulAttributes,char* pszName)
{
    int iRet;
    while((iRet = IOdrvAsynchFileOpen(pHandle,ulAttributes,pszName)) < Done)
    {
        IODrvSleep(100);
    }
    return iRet;
}

int IOdrvSynchFileClose(void* Handle)
{
    int iRet;
    while((iRet = IOdrvAsynchFileClose(Handle)) < Done)
    {
        IODrvSleep(100);
    }
    return iRet;
}

int IOdrvSynchFileRead(void* Handle, char* pBuffer, unsigned long ulSize)
{
    int iRet;
    while((iRet = IOdrvAsynchFileRead(Handle,pBuffer,ulSize)) < Done)
    {
        IODrvSleep(100);
    }
    return iRet;
}

int IOdrvSynchFileWrite(void* Handle, char* pBuffer, unsigned long ulSize)
{
    int iRet;
    while((iRet = IOdrvAsynchFileWrite(Handle,pBuffer,ulSize)) < Done)
    {
        IODrvSleep(100);
    }
    return iRet;
}

char IODrvGetTargetIds(unsigned long *pulIOTrgId, unsigned long *pulIOHookId)
{
	char cResult = TRUE; //Set FALSE, if IODrv doesn't want to determine the ID.
    if(cResult)
    {
	    *pulIOTrgId = 4711;
	    *pulIOHookId = 0;
        return 1; //Yes, take this ID!
    }
    else
        return 0; //No, I don't want to overwrite the target ID.
    
}

RTS_LAST_ERROR* IODrvGetLastError(void)
{
    if(g_rtsapi.pfRtsDataManipulation != NULL)
        return (RTS_LAST_ERROR*)(*g_rtsapi.pfRtsDataManipulation)(DTAMAN_MODE_GETLASTERROR,0);
    return 0;
}

int IODrvGetSystemTimeFromBoot(__int64* pil)
{
    if(g_rtsapi.pfRtsDataManipulation != NULL)
    {
	    (*g_rtsapi.pfRtsDataManipulation)(DTMAN_MODE_GETSYSTEMTIMEFROMBOOT,(unsigned long)pil);
		return 1;
	}
    return 0;
}

char* IODrvGetAddress(unsigned long ulSegment)
{
    if(g_rtsapi.pfRtsDataManipulation != NULL)
        return (char*)(*g_rtsapi.pfRtsDataManipulation)(DTMAN_MODE_GETADDRESS,ulSegment);
    return 0;
}

unsigned long IODrvGetSegSize(unsigned long ulSegment)
{
    if(g_rtsapi.pfRtsDataManipulation != NULL)
        return (*g_rtsapi.pfRtsDataManipulation)(DTMAN_MODE_GETSEGSIZE,ulSegment);
    return 0;
}

long IODrvGetIdentity(void)
{
    if(g_rtsapi.pfRtsDataManipulation != NULL)
        return (long)(*g_rtsapi.pfRtsDataManipulation)(DTMAN_MODE_GETIDENTITY,0);
    return 0;
}
Соседние файлы в папке IODriver ToolKit