encoder.c -- Continuous display of motor actual position while switching the
/* encoder.c */

/* Copyright(c) 1991-2002 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.
 */

#if defined(MEI_RCS)
static const char MEIAppRCS[] =
    "$Header: /MainTree/XMPLib/XMP/app/encoder.c 8     7/23/01 2:36p Kevinh $";
#endif

/*

:Continuous display of motor actual position while switching the
 encoder polarity when a key is pressed.

 Warning!  This is a sample program to assist in the integration of the
 XMP motion controller with your application.  It may not contain all
 of the logic and safety features that your application requires.

*/

#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    encoderMain

argMainRENAME(main, encoder)
#endif

/* Command line arguments and defaults */
long    axisNumber  = -1;
long    motorNumber =  0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motor",   ArgTypeLONG,    &motorNumber,   },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

typedef struct _Context *Context;

typedef struct _Context {
    MPIControl  control;
    MPIAxis     axis;
    MPIMotor    motor;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIMotorConfig  motorConfig;

    long    axisNumber;
    long    motorNumber;

    long    encoderPhase;
} _Context;

long    contextCreate(Context   contextData,
                      long      argc,
                      char      *argv[]);
long    contextDelete(Context   contextData);

void    positionDisplay(double  position);
double  positionGet(Context contextData);

Static _Context ContextObject;

int
    main(int    argc,
         char   *argv[])
{
    Context context;

    long    returnValue;

    context = &ContextObject;

    returnValue =
        contextCreate(context,
                      argc,
                      argv);

    /* Disable amplifier */
    if (returnValue == MPIMessageOK) {
        returnValue =
            mpiMotorAmpEnableSet(context->motor,
                                 FALSE);
    }

    while (returnValue == MPIMessageOK) {
        long    key;

        printf("\nMove the motor and note the direction; it should be %s.\n",
                (context->motorConfig.encoderPhase == 0)
                                ? "normal"
                                : "reversed");

        printf("Press a key to change the encoder phasing, ESC to quit.\n");

        while ((key = meiPlatformKey(MPIWaitPOLL)) <= 0) {
            positionDisplay(positionGet(context));
        }

        if (key == 0x1b) {
            break;
        }

        context->motorConfig.encoderPhase = (context->motorConfig.encoderPhase == 0);

        returnValue =
            mpiMotorConfigSet(context->motor,
                              &context->motorConfig,
                              NULL);
    }

    returnValue = contextDelete(context);
    meiASSERT(returnValue == MPIMessageOK);

    return ((int)returnValue);
}

long
    contextCreate(Context   context,
                  long      argc,
                  char      *argv[])
{
    long    returnValue;

    long    argIndex;

    memset(context, 0, sizeof(*context));

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &context->controlType,
                   &context->controlAddress);

    /* Parse command line for application-specific arguments */
    while (argIndex < argc) {
        long    argIndexNew;

        argIndexNew = argSet(argList, argIndex, argc, argv);

        if (argIndexNew <= argIndex) {
            argIndex = argIndexNew;
            break;
        }
        else {
            argIndex = argIndexNew;
        }
    }

    /* Check for unknown/invalid command line arguments */
    if ((argIndex < argc) ||
        (axisNumber  >= MEIXmpMAX_Axes) ||
        (motorNumber >= MEIXmpMAX_Motors)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    context->motorNumber = motorNumber;

    context->axisNumber =
        (axisNumber < 0)
            ? motorNumber
            : axisNumber;

    context->control =
        mpiControlCreate(context->controlType,
                         &context->controlAddress);
    msgCHECK(mpiControlValidate(context->control));

    /* Initialize motion controller */
    returnValue = mpiControlInit(context->control);
    msgCHECK(returnValue);

    /* Create axis object */
    context->axis =
        mpiAxisCreate(context->control,
                      context->axisNumber);
    msgCHECK(mpiAxisValidate(context->axis));

    /* Create motor object */
    context->motor =
        mpiMotorCreate(context->control,
                       context->motorNumber);
    msgCHECK(mpiMotorValidate(context->motor));

    returnValue =
        mpiMotorConfigGet(context->motor,
                          &context->motorConfig,
                          NULL);
    msgCHECK(returnValue);

    context->encoderPhase = context->motorConfig.encoderPhase;

    return (returnValue);
}

long
    contextDelete(Context   context)
{
    long    returnValue = MPIMessageOK;

    if (context->motor != MPIHandleVOID) {
        /* Set to original configuration */
        context->motorConfig.encoderPhase = context->encoderPhase;

        returnValue =
            mpiMotorConfigSet(context->motor,
                              &context->motorConfig,
                              NULL);

        if (returnValue == MPIMessageOK) {
            returnValue = mpiMotorDelete(context->motor);

            if (returnValue == MPIMessageOK) {
                context->motor = MPIHandleVOID;
            }
        }
    }

    if (returnValue == MPIMessageOK) {
        if (context->axis != MPIHandleVOID) {
            returnValue = mpiAxisDelete(context->axis);

            if (returnValue == MPIMessageOK) {
                context->axis = MPIHandleVOID;
            }
        }
    }

    if (returnValue == MPIMessageOK) {
        if (context->control != MPIHandleVOID) {
            returnValue = mpiControlDelete(context->control);

            if (returnValue == MPIMessageOK) {
                context->control = MPIHandleVOID;
            }
        }
    }

    return (returnValue);
}

void
    positionDisplay(double  position)
{
    printf("Actual Position: %8.0lf\r",
            position);
}

double
    positionGet(Context context)
{
    long    returnValue;

    double  actualPos;

    returnValue =
        mpiAxisActualPositionGet(context->axis,
                                 &actualPos);
    msgCHECK(returnValue);

    return (actualPos);
}