syncInterrupt.c -- Configure board to interrupt host every N samples.
/* syncInterrupt.c */
/* Copyright(c) 1991-2006 by Motion Engineering, Inc. All rights reserved.
*
* This software contains proprietary and confidential information of
* Motion Engineering Inc., and its suppliers. Except as may be set forth
* in the license agreement under which this software is supplied, use,
* disclosure, or reproduction is prohibited without the prior express
* written consent of Motion Engineering, Inc.
*/
/*
: Configure board to interrupt host every N samples.
This program configures the board to interrupt the host every N (SYNC_PERIOD) samples.
It also will spawn a task that will wake up every time the interrupt occurs and check
to see if the interrupt sent was the sync interrupt.
If HOST_PROCESS_FLAG is defined, the program will set the HostProcessFlag in the firmware
at the beginning of the task. When the task is complete, it will clear the HostProcessFlag.
If the HostProcessFlag is still set when the firmware starts SynqNet transmission, a status
bit in the Control Status word is set. This code also will look to see if that bit gets set.
The bit indicates that the host's process did not complete before SynqNet transmission. This
should be used if the host is trying to (for example) process feedback and calculate a new DAC
command. HOST_PROCESS_FLAG should only be defined if the SYNC_PERIOD is 1 (interrupt every
sample).
Warning! This is a sample program to assist in the integration of an
MEI motion controller with your application. It may not contain all
of the logic and safety features that your application requires.
The msgCHECK(...) macros used in the following sample code are intended
to convey our strong belief that ALL error return codes should be checked.
Actual application code should use specific error handling techniques (other
than msgCHECKs) best suited to your internal error recovery methods.
*/
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"
#define SYNC_PERIOD (1) /* sync interrupt every sample */
#define HOST_PROCESS_FLAG (1)
long syncDone = 0;
long syncStop = 0;
/* Perform basic command line parsing. (-control -server -port -trace) */
void basicParsing(int argc,
char *argv[],
MPIControlType *controlType,
MPIControlAddress *controlAddress)
{
long argIndex;
/* Parse command line for Control type and address */
argIndex = argControl(argc, argv, controlType, controlAddress);
/* Check for unknown/invalid command line arguments */
if (argIndex < argc) {
fprintf(stderr,"usage: %s %s\n", argv[0], ArgUSAGE);
exit(MPIMessageARG_INVALID);
}
}
/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control)
{
long returnValue;
/* Delete control handle */
returnValue =
mpiControlDelete(*control);
msgCHECK(returnValue);
*control = MPIHandleVOID;
}
static long syncInterruptFunction(MPIControl *control)
{
long returnValue;
MPIXmpData *firmware;
MPIControlConfig mpiConfig;
MPIControlConfig mpiConfig;
MPI_BOOL interrupted;
long sampleCounter, oldSampleCounter, syncFlag;
returnValue = mpiControlMemory(*control,
&firmware,
NULL);
/* Enable interrupts */
if (returnValue == MPIMessageOK) {
MPIPlatform platform = mpiControlPlatform(*control);
returnValue = mpiPlatformValidate(platform);
if (returnValue == MPIMessageOK) {
returnValue = mpiPlatformInterruptEnable(platform,
TRUE);
}
}
/* Configure sync interrupt */
if (returnValue == MPIMessageOK) {
returnValue = mpiControlConfigGet(*control,
&mpiConfig,
&mpiConfig);
if (returnValue == MPIMessageOK) {
mpiConfig.syncInterruptPeriod = SYNC_PERIOD;
returnValue = mpiControlConfigSet(*control,
&mpiConfig,
&mpiConfig);
}
}
if (returnValue == MPIMessageOK) {
returnValue = mpiControlMemoryGet(*control,
&oldSampleCounter,
&firmware->SystemData.SampleCounter,
sizeof(oldSampleCounter));
if (returnValue == MPIMessageOK) {
while (!syncStop) {
returnValue = mpiControlInterruptWait(*control,
&interrupted,
MPIWaitFOREVER);
/* check to see if this is really a SyncInterrupt */
if (returnValue == MPIMessageOK) {
returnValue = mpiControlMemoryGet(*control,
&syncFlag,
&firmware->SystemData.SyncInterrupt.Flag,
sizeof(syncFlag));
if ((returnValue == MPIMessageOK) && (syncFlag)) {
#if HOST_PROCESS_FLAG
/* Set Host Process Flag */
/* WARNING: Do Not leave the Host Process Flag set for longer than 1 sample. The foreground
task in the firmware will consider this an error and will set a warning bit.
The Host Process Flag is not necessary if the SYNC_PERIOD is greater than 1 sample/interrupt.
It is there if the Host wants to know if the Host Process has compleated before the
SynqNet DMA occurs in the firmware's foreground task.
*/
long hostProcessFlag = 1;
returnValue = mpiControlMemorySet(*control,
&firmware->SystemData.SyncInterrupt.HostProcessFlag,
&hostProcessFlag,
sizeof(hostProcessFlag));
#endif
/* Host Process Start */
if (returnValue == MPIMessageOK) {
returnValue = mpiControlMemoryGet(*control,
&sampleCounter,
&firmware->SystemData.SampleCounter,
sizeof(sampleCounter));
#if 0
if (returnValue == MPIMessageOK) {
mpiPlatformConsole("SampleCounter: 0x%d\n", sampleCounter);
if ((sampleCounter - SYNC_PERIOD) != oldSampleCounter) {
mpiPlatformConsole("Error %d samples\nsampleCounter %d\noldSampleCounter %d\nperiod %d\n",
(sampleCounter - oldSampleCounter), sampleCounter, oldSampleCounter, SYNC_PERIOD);
}
oldSampleCounter = sampleCounter;
}
#endif
}
/* Host Process End */
#if HOST_PROCESS_FLAG
if (returnValue == MPIMessageOK) {
/* Clear Host Process Flag */
hostProcessFlag = 0;
returnValue = mpiControlMemorySet(*control,
&firmware->SystemData.SyncInterrupt.HostProcessFlag,
&hostProcessFlag,
sizeof(hostProcessFlag));
}
#endif
}
}
}
}
}
/* Disable sync interrupt */
if (returnValue == MPIMessageOK) {
mpiConfig.syncInterruptPeriod = 0;
returnValue = mpiControlConfigSet(*control,
&mpiConfig,
&mpiConfig);
}
syncDone = 1;
return returnValue;
}
int main(int argc,
char *argv[])
{
long returnValue;
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
Thread thread;
long threadPriority;
ThreadStatus status;
#if HOST_PROCESS_FLAG
MPINotify notify; /* event notification object */
MPIEventMgr eventMgr; /* event manager handle */
MPIEventMask eventMask;
Service service;
MPIEventStatus eventStatus;
#endif
/* Perform basic command line parsing. (-control -server -port -trace) */
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Obtain a control handle */
control = mpiControlCreate(controlType, &controlAddress);
msgCHECK(mpiControlValidate(control));
/* Initialize the controller */
returnValue = mpiControlInit(control);
msgCHECK(returnValue);
thread = threadCreate(NULL);
returnValue = threadValidate(thread);
msgCHECK(returnValue);
returnValue = threadStart(thread,
(THREAD_FUNCTION)syncInterruptFunction,
&control);
msgCHECK(returnValue);
returnValue = threadStatus(thread,
&status);
msgCHECK(returnValue);
if (status.active != FALSE) {
returnValue = threadPriorityGet(thread,
&threadPriority);
msgCHECK(returnValue);
threadPriority = THREAD_PRIORITY_TIME_CRITICAL;
returnValue = threadPrioritySet(thread,
threadPriority);
msgCHECK(returnValue);
}
else {
printf("could not activate thread\n");
syncDone = 1;
}
#if HOST_PROCESS_FLAG
/* Request notification of control events */
mpiEventMaskCLEAR(eventMask);
mpiEventMaskCONTROL(eventMask);
returnValue =
mpiControlEventNotifySet(control,
eventMask,
NULL);
msgCHECK(returnValue);
/* Create event notification object for motion */
notify =
mpiNotifyCreate(eventMask,
control);
msgCHECK(mpiNotifyValidate(notify));
/* Create event manager object */
eventMgr = mpiEventMgrCreate(control);
msgCHECK(mpiEventMgrValidate(eventMgr));
/* Add notify to event manager's list */
returnValue =
mpiEventMgrNotifyAppend(eventMgr,
notify);
msgCHECK(returnValue);
/* Create service thread */
service =
serviceCreate(eventMgr,
-1, /* default (max) priority */
-1); /* -1 => enable interrupts */
mpiAssert(service != NULL);
#endif
while(!syncDone) {
if(kbhit()) {
syncStop = 1;
}
#if HOST_PROCESS_FLAG
/* Wait for motion event */
returnValue =
mpiNotifyEventWait(notify,
&eventStatus,
MPIWaitPOLL);
if (returnValue == MPIMessageOK) {
if (eventStatus.type == MPIEventTypeCONTROL_HOST_PROCESS_TIME_EXCEEDED) {
mpiPlatformConsole("Host Process Time Exceeded\n");
mpiPlatformConsole("mpiNotifyEventWait(0x%x, 0x%x, %d) returns 0x%x\n"
"\teventStatus: type %d source 0x%x info 0x%x\n",
notify,
&eventStatus,
MPIWaitFOREVER,
returnValue,
eventStatus.type,
eventStatus.source,
eventStatus.info[0]);
returnValue = mpiControlEventReset(control,
eventMask);
msgCHECK(returnValue);
}
}
if (returnValue == MPIMessageTIMEOUT) {
returnValue = MPIMessageOK;
}
#endif
}
#if HOST_PROCESS_FLAG
/* Perform certain cleanup actions and delete MPI objects */
returnValue = serviceDelete(service);
msgCHECK(returnValue);
returnValue = mpiEventMgrDelete(eventMgr);
msgCHECK(returnValue);
returnValue = mpiNotifyDelete(notify);
msgCHECK(returnValue);
returnValue = threadDelete(thread);
msgCHECK(returnValue);
#endif
programCleanup(&control);
return MPIMessageOK;
}
|