/* trustanalogrecord.c */
/* Copyright(c) 1991-2004 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.
*/
/*
: Reads and writes analog values on Trust TA805D with MPI and recorder
This program shows two major ways to deal with the analog I/O on the
Trust TA805D. The first method is via MPI function calls. The second
method is to record the I/O using the Recorder object. Special attention
should be paid to the casting of the recorded inputs. Since the analog
inputs are formatted with two 16 bits per 32 bit word, some intricate
casting is required to reconstruct the analog inputs.
The program follows this order of execution:
1. Write DAC values with the MPI.
2. Read the DAC values with the MPI
3. Read the ADC values with the MPI
4. Read the DAC and ADC values with the recorder
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 <string.h>
#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"
#if defined(ARG_MAIN_RENAME)
#define main trustanalogrecordMain
argMainRENAME(main, template)
#endif
#define SQNODE_NUMBER (0)
#define RECORD_COUNT (1) /* record one sample*/
#define OFFSET0 (7.1);
#define OFFSET1 (-3.14159);
#define OFFSET2 (-10.0);
#define OFFSET3 (-10.0);
int NumberOfNodes(MEISynqNet synqNet);
int TrustTa805DIndex(MEISqNode *sqNode, int numNodes);
int TrustTa805DMotorIndex(MEISqNode *sqNode, int numNodes);
/* 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);
}
}
/* Create and initialize MPI objects */
void programInit(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotor *ta805Motor,
MPIRecorder *recorder,
MPIRecorderRecord **record,
int recordCount,
MEISynqNet *synqNet,
MEISqNode *sqNode,
long sqNodeNumber)
{
MPIControlConfig config;
long returnValue;
int nodeIndex;
int numberNodes;
int TA805MotorNum;
/* Create motion controller object */
*control =
mpiControlCreate(controlType, controlAddress);
msgCHECK(mpiControlValidate(*control));
/* Initialize motion controller */
returnValue =
mpiControlInit(*control);
msgCHECK(returnValue);
/* Make sure Aux DACs are turned on */
returnValue = mpiControlConfigGet(*control, &config, NULL);
msgCHECK(returnValue);
config.auxDacCount = 8;
returnValue = mpiControlConfigSet(*control, &config, NULL);
msgCHECK(returnValue);
/* Create recorder object */
*recorder =
mpiRecorderCreate(*control, -1);
msgCHECK(mpiRecorderValidate(*recorder));
*record = malloc(sizeof(MPIRecorderRecord) * recordCount);
meiASSERT(*record != NULL);
/* Create synqNet object */
*synqNet =
meiSynqNetCreate(*control, 0);
msgCHECK(meiSynqNetValidate(*synqNet));
numberNodes = NumberOfNodes(*synqNet);
for(nodeIndex = 0; nodeIndex < numberNodes; nodeIndex++)
{ /* only enough node objects for valid nodes are created */
/* Create sqNode object */
sqNode[nodeIndex] =
meiSqNodeCreate(*control, nodeIndex);
msgCHECK(meiSqNodeValidate(sqNode[nodeIndex]));
}
TA805MotorNum = TrustTa805DMotorIndex(sqNode, numberNodes);
msgCHECK(TA805MotorNum < 0);
ta805Motor[0] = mpiMotorCreate(*control, TA805MotorNum);
msgCHECK(mpiMotorValidate(ta805Motor[0]));
ta805Motor[1] = mpiMotorCreate(*control, TA805MotorNum + 1);
msgCHECK(mpiMotorValidate(ta805Motor[1]));
}
/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
MPIRecorder *recorder,
MPIRecorderRecord *record,
MEISynqNet *synqNet,
MPIMotor *ta805Motor,
MEISqNode *sqNode)
{
long returnValue;
int nodeIndex;
int numberNodes;
numberNodes = NumberOfNodes(*synqNet);
for(nodeIndex = 0; nodeIndex < numberNodes; nodeIndex++)
{ /* only enough node objects for valid nodes are deleted */
/* Delete sqNode object */
returnValue =
meiSqNodeDelete(sqNode[nodeIndex]);
msgCHECK(returnValue);
sqNode[nodeIndex] = MPIHandleVOID;
}
/* Delete synqnet object */
returnValue = meiSynqNetDelete(*synqNet);
msgCHECK(returnValue);
*synqNet = MPIHandleVOID;
free(record);
/* Delete recorder object */
returnValue = mpiRecorderDelete(*recorder);
msgCHECK(returnValue);
*recorder = MPIHandleVOID;
returnValue = mpiMotorDelete(ta805Motor[0]);
msgCHECK(returnValue);
returnValue = mpiMotorDelete(ta805Motor[1]);
msgCHECK(returnValue);
/* Delete motion controller object */
returnValue = mpiControlDelete(*control);
msgCHECK(returnValue);
*control = MPIHandleVOID;
}
/*
Get the number of nodes on the SynqNet network
Returns -1 if there is an error
*/
int NumberOfNodes(MEISynqNet synqNet)
{
MEISynqNetInfo info;
long returnValue;
int numNodes = -1;
returnValue = meiSynqNetInfo(synqNet, &info);
if(returnValue == MPIMessageOK)
{
if(info.nodeCount >= 0 && info.nodeCount <= MEIXmpMaxSynqNetBlocks)
{
numNodes = info.nodeCount;
}
}
return numNodes;
}
/*
find the trustta805-d node index
returns a -1 if there is an error, or no trust ta 805-d found
numNodes is the number of valid nodes in the array
*/
int TrustTa805DIndex(MEISqNode *sqNode, int numNodes)
{
MEISqNodeInfo nodeInfo;
int ta805Index = -1;
int nodeIndex;
long returnValue;
/* find a trust ta 805 */
for(nodeIndex = 0; nodeIndex < MEIXmpMaxSynqNetBlocks; nodeIndex++)
{
returnValue = meiSqNodeInfo(sqNode[nodeIndex], &nodeInfo);
msgCHECK(returnValue);
if(strcmp(nodeInfo.id.nodeName, "Trust TA805-D") == 0)
{
ta805Index = nodeIndex;
break;
}
}
return ta805Index;
}
/*
Finds the motor index of the first motor on a Trust Ta805D
returns a -1 if there is an error or no Ta805D
numNodes is the number of valid nodes in the array
*/
int TrustTa805DMotorIndex(MEISqNode *sqNode, int numNodes)
{
MEISqNodeInfo info;
long returnValue;
int ta805NodeNum = -1;
int ta805MotorNum = -1;
ta805NodeNum = TrustTa805DIndex(sqNode, numNodes);
if(ta805NodeNum != -1)
{
returnValue = meiSqNodeInfo(sqNode[ta805NodeNum], &info);
ta805MotorNum = info.motorOffset;
}
return ta805MotorNum;
}
void writeDACOutputs(MPIMotor *ta805Motor, int ta805Index)
{
MEIMotorDacConfig dacConfig;
long returnValue;
if(ta805Index != -1)
{ /* write analog inputs with MPI code and print results */
returnValue = meiMotorDacConfigGet(ta805Motor[0], &dacConfig);
msgCHECK(returnValue);
dacConfig.Cmd.Offset = (float)OFFSET0;
dacConfig.Aux.Offset = (float)OFFSET1;
printf("Output %d = %.4f\n", 0, dacConfig.Cmd.Offset);
printf("Output %d = %.4f\n", 1, dacConfig.Aux.Offset);
returnValue = meiMotorDacConfigSet(ta805Motor[0], &dacConfig);
msgCHECK(returnValue);
returnValue = meiMotorDacConfigGet(ta805Motor[1], &dacConfig);
msgCHECK(returnValue);
dacConfig.Cmd.Offset = (float)OFFSET2;
dacConfig.Aux.Offset = (float)OFFSET3;
printf("Output %d = %.4f\n", 2, dacConfig.Cmd.Offset);
printf("Output %d = %.4f\n", 3, dacConfig.Aux.Offset);
returnValue = meiMotorDacConfigSet(ta805Motor[1], &dacConfig);
msgCHECK(returnValue);
}
}
void readADCInputs(MEISqNode *sqNode, int ta805Index)
{
long returnValue;
double analogResult[8];
int channelIndex;
if(ta805Index != -1)
{ /* read analog inputs with MPI code and print results */
for(channelIndex = 0; channelIndex < 8; channelIndex++)
{
returnValue = meiSqNodeAnalogInput(sqNode[ta805Index], channelIndex,
&analogResult[channelIndex]);
printf("Input %d = %.4f\n", channelIndex, analogResult[channelIndex]);
}
}
}
/*
Set the addresses to record. Must match print records.
*/
void RecorderPointSet(MPIControl control, void *point[MEIXmpMaxRecSize],
int *pointCount, int motorIndex, int nodeIndex)
{
MEIXmpData *firmware;
MEIXmpBufferData *buffer;
long returnValue;
long *addr[8];
int adcIndex;
*pointCount = 0;
returnValue = mpiControlMemory(control,
(void **)&firmware,
(void **)&buffer);
msgCHECK(returnValue);
/* Get all the adc indexes */
for(adcIndex = 0; adcIndex < 8; adcIndex++)
{
returnValue = mpiControlMemoryGet(control,
&addr[adcIndex],
&buffer->Block[nodeIndex].AnalogIO.InPtr,
sizeof(addr[adcIndex]));
msgCHECK(returnValue);
/* convert to host memory (controller) from firmware memory (PC) */
returnValue = meiPlatformMemoryToHost(meiControlPlatform(control),
(void*)(addr[adcIndex]),
(void**)&addr[adcIndex]);
msgCHECK(returnValue);
addr[adcIndex] = (long*)((long)(addr[adcIndex]) + adcIndex * sizeof(long) / 2);
/* increment once per two adcs */
}
point[(*pointCount)++] = &firmware->SystemData.SampleCounter;
point[(*pointCount)++] = &firmware->Motor[motorIndex].IO.Cmd.Level;
point[(*pointCount)++] = &buffer->Motor[motorIndex].IO.Aux.Level;
point[(*pointCount)++] = &firmware->Motor[motorIndex + 1].IO.Cmd.Level;
point[(*pointCount)++] = &buffer->Motor[motorIndex + 1].IO.Aux.Level;
point[(*pointCount)++] = (long*)addr[0];
point[(*pointCount)++] = (long*)addr[1];
point[(*pointCount)++] = (long*)addr[2];
point[(*pointCount)++] = (long*)addr[3];
point[(*pointCount)++] = (long*)addr[4];
point[(*pointCount)++] = (long*)addr[5];
point[(*pointCount)++] = (long*)addr[6];
point[(*pointCount)++] = (long*)addr[7];
meiASSERT(*pointCount <= MEIXmpMaxRecSize);
}
/* Start recorder, get data, and stop recorder */
void recordData(MPIRecorder recorder,
long numRecords,
MPIRecorderRecord *records)
{
long returnValue;
long recordIndex;
long recordCountRemaining;
long countGet;
/* Start recording the axis */
returnValue =
mpiRecorderStart(recorder,
numRecords);
msgCHECK(returnValue);
/* Fill the record buffer */
for (recordIndex = 0, recordCountRemaining = numRecords;
recordCountRemaining > 0; ) {
returnValue =
mpiRecorderRecordGet(recorder,
recordCountRemaining,
&records[recordIndex],
&countGet);
msgCHECK(returnValue);
recordCountRemaining -= countGet;
recordIndex += countGet;
}
/* Stop recording */
returnValue = mpiRecorderStop(recorder);
/* In case the recorder has already stopped */
if (returnValue == MPIRecorderMessageSTOPPED) {
returnValue = MPIMessageOK;
}
msgCHECK(returnValue);
}
/* Print the records */
void printRecords(long numRecords,
MPIRecorderRecord *records)
{
MPIRecorderRecord *recordPtr;
long recordIndex;
double analogOut[8];
/* Output record buffer to screen */
for (recordIndex = 0; recordIndex < numRecords; recordIndex++) {
printf("\nrecord[%d]:\n",
recordIndex);
/* Cast records to MEIRecorderRecord pointer */
recordPtr = (MPIRecorderRecord *)&records[recordIndex];
/* Cast to a float, then divide by 3276.7 to get volts */
printf("Sample %d\n\nCmd Output 0 = %.4f\nAux Output 0 = %.4f\nCmd Output
1 = %.4f\nAux Output 1 = %.4f\n\n",
recordPtr->point[0],
((float)*((float *)&recordPtr->point[1]) / 3276.7),
((float)*((float *)&recordPtr->point[2]) / 3276.7),
((float)*((float *)&recordPtr->point[3]) / 3276.7),
((float)*((float *)&recordPtr->point[4]) / 3276.7));
/*
Two 16 bit words packed into a 32 bit word. Mask each
16 bit word off and shift the top 16 bits down.
All ADC values are recorded in ADC counts (16 bit integer)
To convert to +/-1.0 floating point,
1. If the ADC index (not record index) is odd, mask to get 16 lsb,
if even, mask to get 16 msb
2. Cast to floating point
3. If even ADC index (16 msb), divide by 16 bits (1<<16)
4. Divide by full scale to get +/-1.0 fractional range
Odd ADC numbers will need to
*/
analogOut[0] = (double)((long)(short)(recordPtr->point[5] & 0xffff))/32768;
analogOut[1] = (double)((short)((unsigned long)recordPtr->point[6]/(1<<16)))/(1<<15);
analogOut[2] = (double)((long)(short)(recordPtr->point[7] & 0xffff))/32768;
analogOut[3] = (double)((short)((unsigned long)recordPtr->point[8]/(1<<16)))/(1<<15);
analogOut[4] = (double)((long)(short)(recordPtr->point[9] & 0xffff))/32768;
analogOut[5] = (double)((short)((unsigned long)recordPtr->point[10]/(1<<16)))/(1<<15);
analogOut[6] = (double)((long)(short)(recordPtr->point[11] & 0xffff))/32768;
analogOut[7] = (double)((short)((unsigned long)recordPtr->point[12]/(1<<16)))/(1<<15);
printf("Input 0 = %.4f\nInput 1 = %.4f\nInput 2 = %.4f\nInput 3 = %.4f\nInput
4 = %.4f\nInput 5 = %.4f\nInput 6 = %.4f\nInput 7 = %.4f",
analogOut[0],
analogOut[1],
analogOut[2],
analogOut[3],
analogOut[4],
analogOut[5],
analogOut[6],
analogOut[7]);
}
}
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIRecorder recorder;
MPIRecorderRecord *record = NULL;
MPIMotor ta805Motor[2];
MEISynqNet synqNet;
MEISqNode sqNode[MEIXmpMaxSynqNetBlocks];
int numberNodes;
int nodeIndex = -1;
int ta805MotorIndex = -1;
int ta805Index;
void *point[MEIXmpMaxRecSize];
long returnValue;
int pointCount = 0;
/* Perform basic command line parsing. (-control -server -port -trace) */
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects */
programInit(&control,
controlType,
&controlAddress,
ta805Motor,
&recorder,
&record,
RECORD_COUNT,
&synqNet,
sqNode,
SQNODE_NUMBER);
numberNodes = NumberOfNodes(synqNet);
printf("Number of nodes on SynqNet = %d\n", numberNodes);
ta805Index = TrustTa805DIndex(sqNode, numberNodes);
printf("Trust TA805-D node index = %d\n", ta805Index);
ta805MotorIndex = TrustTa805DMotorIndex(sqNode, numberNodes);
writeDACOutputs(ta805Motor, ta805Index);
meiPlatformSleep(10); /* do a minimum windows sleep for DAC and ADC delays
(much less that 10msec needed) */
/*Read the analog inputs with mpi calls (no recorder)*/
readADCInputs(sqNode, ta805Index);
/*read the analog inputs and outputs with the recorder*/
/*Set the points that will be recorded*/
RecorderPointSet(control, point, &pointCount, ta805MotorIndex, ta805Index);
/* Configure recorder object */
returnValue =
mpiRecorderRecordConfig(recorder,
MPIRecorderRecordTypePOINT,
pointCount,
point);
msgCHECK(returnValue);
/* Start recorder, get data, and stop recorder */
recordData(recorder,
RECORD_COUNT,
record);
/* Print the records */
printRecords(RECORD_COUNT,
record);
/* Perform certain cleanup actions and delete MPI objects */
programCleanup(&control,
&recorder,
record,
&synqNet,
ta805Motor,
sqNode);
return MPIMessageOK;
}
|